mirror of
https://github.com/ggml-org/llama.cpp.git
synced 2026-08-10 21:56:37 +02:00
Compare commits
66
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e23e9440eb | ||
|
|
157b81fe6d | ||
|
|
6ad4ab0ea0 | ||
|
|
92d1bb0c99 | ||
|
|
1e396e72a8 | ||
|
|
0377426cef | ||
|
|
aea252fb4a | ||
|
|
f401bb1390 | ||
|
|
74ce15741b | ||
|
|
936918514c | ||
|
|
08659901c4 | ||
|
|
61141f1487 | ||
|
|
7ba604f1cb | ||
|
|
687e778927 | ||
|
|
18f7ad7fc9 | ||
|
|
dd2c7c4471 | ||
|
|
69bf643791 | ||
|
|
3653e6d6d5 | ||
|
|
fc6545d322 | ||
|
|
1621a3d388 | ||
|
|
6de1b63473 | ||
|
|
f8e30266d2 | ||
|
|
a194a75b7e | ||
|
|
23634783c5 | ||
|
|
4cb22cd537 | ||
|
|
4cf5cab65d | ||
|
|
933f46f3cb | ||
|
|
9ba73fd1f5 | ||
|
|
f4f7758cae | ||
|
|
34e9ee57f5 | ||
|
|
dff15d4ac9 | ||
|
|
e1470ee6a2 | ||
|
|
217df17ac3 | ||
|
|
cb26014d96 | ||
|
|
82bb48500a | ||
|
|
42e98813e4 | ||
|
|
fc3f10b389 | ||
|
|
6b5c2efb4e | ||
|
|
31558dbb76 | ||
|
|
c1f4109898 | ||
|
|
eef5f3e343 | ||
|
|
c074cb3f76 | ||
|
|
5b87ed30f8 | ||
|
|
d8d9887228 | ||
|
|
e40bf88642 | ||
|
|
15586e2d71 | ||
|
|
6a32c29a74 | ||
|
|
eb5667a169 | ||
|
|
3db4ff877d | ||
|
|
e700bfb37f | ||
|
|
a1f96d4fc2 | ||
|
|
9de0fcf2b3 | ||
|
|
803b7fcae8 | ||
|
|
c8e03ce812 | ||
|
|
f9e832c10e | ||
|
|
360e1349f0 | ||
|
|
b06aa774c0 | ||
|
|
cd0fa6051a | ||
|
|
717dad5c8e | ||
|
|
9a688e51e6 | ||
|
|
9303cdd8d3 | ||
|
|
a035a88878 | ||
|
|
020760adfc | ||
|
|
61881b1f7f | ||
|
|
3e3a7a416d | ||
|
|
d52ec04a66 |
@@ -57,7 +57,6 @@ COPY --from=web /app/tools/ui/dist tools/ui/dist
|
||||
RUN HIPCXX="$(hipconfig -l)/clang" HIP_PATH="$(hipconfig -R)" \
|
||||
cmake -S . -B build \
|
||||
-DGGML_HIP=ON \
|
||||
-DGGML_HIP_ROCWMMA_FATTN=ON \
|
||||
-DAMDGPU_TARGETS="$ROCM_DOCKER_ARCH" \
|
||||
-DGGML_BACKEND_DL=ON -DGGML_CPU_ALL_VARIANTS=ON \
|
||||
-DCMAKE_BUILD_TYPE=Release -DLLAMA_BUILD_TESTS=OFF \
|
||||
|
||||
@@ -60,7 +60,6 @@ jobs:
|
||||
-DCMAKE_BUILD_RPATH="@loader_path" \
|
||||
-DLLAMA_FATAL_WARNINGS=ON \
|
||||
-DLLAMA_BUILD_BORINGSSL=ON \
|
||||
-DGGML_METAL_USE_BF16=ON \
|
||||
-DGGML_METAL_EMBED_LIBRARY=OFF \
|
||||
-DGGML_METAL_SHADER_DEBUG=ON \
|
||||
-DGGML_RPC=ON \
|
||||
@@ -127,7 +126,6 @@ jobs:
|
||||
run: |
|
||||
sysctl -a
|
||||
cmake -B build -G Xcode \
|
||||
-DGGML_METAL_USE_BF16=ON \
|
||||
-DGGML_METAL_EMBED_LIBRARY=ON \
|
||||
-DLLAMA_OPENSSL=OFF \
|
||||
-DLLAMA_BUILD_APP=OFF \
|
||||
@@ -178,7 +176,6 @@ jobs:
|
||||
run: |
|
||||
sysctl -a
|
||||
cmake -B build -G Xcode \
|
||||
-DGGML_METAL_USE_BF16=ON \
|
||||
-DGGML_METAL_EMBED_LIBRARY=ON \
|
||||
-DLLAMA_BUILD_COMMON=OFF \
|
||||
-DLLAMA_BUILD_APP=OFF \
|
||||
@@ -212,7 +209,6 @@ jobs:
|
||||
run: |
|
||||
sysctl -a
|
||||
cmake -B build -G Xcode \
|
||||
-DGGML_METAL_USE_BF16=ON \
|
||||
-DGGML_METAL_EMBED_LIBRARY=ON \
|
||||
-DLLAMA_BUILD_COMMON=OFF \
|
||||
-DLLAMA_BUILD_APP=OFF \
|
||||
@@ -257,7 +253,6 @@ jobs:
|
||||
run: |
|
||||
sysctl -a
|
||||
cmake -B build -G Xcode \
|
||||
-DGGML_METAL_USE_BF16=ON \
|
||||
-DGGML_METAL_EMBED_LIBRARY=ON \
|
||||
-DLLAMA_OPENSSL=OFF \
|
||||
-DLLAMA_BUILD_APP=OFF \
|
||||
|
||||
@@ -99,7 +99,6 @@ jobs:
|
||||
run: |
|
||||
cmake -B build -S . \
|
||||
-DCMAKE_HIP_COMPILER="$(hipconfig -l)/clang" \
|
||||
-DGGML_HIP_ROCWMMA_FATTN=ON \
|
||||
-DGPU_TARGETS="gfx1030" \
|
||||
-DGGML_HIP=ON
|
||||
cmake --build build --config Release -j $(nproc)
|
||||
|
||||
@@ -150,7 +150,6 @@ jobs:
|
||||
-DLLAMA_BUILD_BORINGSSL=ON `
|
||||
-DROCM_DIR="${env:HIP_PATH}" `
|
||||
-DGGML_HIP=ON `
|
||||
-DGGML_HIP_ROCWMMA_FATTN=ON `
|
||||
-DGPU_TARGETS="gfx1100" `
|
||||
-DGGML_RPC=ON
|
||||
cmake --build build -j ${env:NUMBER_OF_PROCESSORS}
|
||||
|
||||
@@ -15,6 +15,12 @@ on:
|
||||
'**/*.cpp'
|
||||
]
|
||||
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
paths: [
|
||||
'.github/workflows/build-sanitize.yml'
|
||||
]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
@@ -28,19 +34,35 @@ env:
|
||||
|
||||
jobs:
|
||||
ctest:
|
||||
runs-on: [self-hosted, X64, CPU, Linux]
|
||||
|
||||
continue-on-error: true
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
sanitizer: [ADDRESS, THREAD, UNDEFINED]
|
||||
include:
|
||||
- sanitizer: ADDRESS
|
||||
machine: [self-hosted, X64, Linux]
|
||||
# thread doesn't run properly on some self hosted machines, so run it on Github instead
|
||||
- sanitizer: THREAD
|
||||
machine: ubuntu-24.04
|
||||
- sanitizer: UNDEFINED
|
||||
machine: [self-hosted, X64, Linux]
|
||||
|
||||
runs-on: ${{ matrix.machine }}
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
id: checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: ccache
|
||||
uses: ggml-org/ccache-action@v1.2.21
|
||||
if: ${{ matrix.sanitizer == 'THREAD' }}
|
||||
with:
|
||||
key: ctest-thread-ubuntu-24.04
|
||||
variant: ccache
|
||||
evict-old-files: 1d
|
||||
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||
|
||||
# with UNDEFINED sanitizer, we have to build in Debug to avoid GCC 13 false-positive warnings
|
||||
- name: Build (undefined)
|
||||
id: cmake_build_undefined
|
||||
|
||||
@@ -71,6 +71,26 @@ jobs:
|
||||
nvidia-smi
|
||||
GG_BUILD_CUDA=1 bash ./ci/run.sh ~/results/llama.cpp ~/mnt/llama.cpp
|
||||
|
||||
gpu-rocm:
|
||||
runs-on: [self-hosted, Linux, AMD]
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
id: checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Test
|
||||
id: ggml-ci
|
||||
# HIP_LAUNCH_BLOCKING=1: workaround for an async-execution correctness
|
||||
# issue on integrated RDNA3.5 (gfx1151) where batched inference returns
|
||||
# incorrect output (perplexity ~88 vs ~9.4). Serializing kernel launches
|
||||
# restores correctness. Remove once the underlying ROCm/HIP issue is fixed.
|
||||
env:
|
||||
HIP_LAUNCH_BLOCKING: "1"
|
||||
run: |
|
||||
rocminfo
|
||||
GG_BUILD_ROCM=1 GG_BUILD_AMDGPU_TARGETS=gfx1151 bash ./ci/run.sh ~/results/llama.cpp ~/mnt/llama.cpp
|
||||
|
||||
gpu-vulkan-nvidia-cm:
|
||||
runs-on: [self-hosted, Linux, NVIDIA]
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
name: Convert PR to draft
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [labeled]
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
issues: write
|
||||
contents: write # required for "gh pr ready" command, see https://github.com/cli/cli/issues/8910
|
||||
|
||||
jobs:
|
||||
convert-to-draft:
|
||||
if: github.event.label.name == 'draft' && github.event.pull_request.draft == false
|
||||
runs-on: ubuntu-slim
|
||||
steps:
|
||||
- name: Convert PR to draft
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
PR_URL: ${{ github.event.pull_request.html_url }}
|
||||
run: |
|
||||
gh pr ready --undo "$PR_URL"
|
||||
gh pr edit "$PR_URL" --remove-label draft
|
||||
@@ -93,13 +93,13 @@ jobs:
|
||||
- build: 'arm64'
|
||||
arch: 'arm64'
|
||||
os: macos-26
|
||||
defines: "-DGGML_METAL_USE_BF16=ON -DGGML_METAL_EMBED_LIBRARY=ON -DCMAKE_OSX_DEPLOYMENT_TARGET=13.3"
|
||||
defines: "-DGGML_METAL_EMBED_LIBRARY=ON -DCMAKE_OSX_DEPLOYMENT_TARGET=13.3"
|
||||
# TODO: this build is disabled to save Github Actions resources (https://github.com/ggml-org/llama.cpp/pull/23780)
|
||||
# in order to enable it again, we have to provision dedicated runners to run it
|
||||
#- build: 'arm64-kleidiai'
|
||||
# arch: 'arm64'
|
||||
# os: macos-14
|
||||
# defines: "-DGGML_METAL_USE_BF16=ON -DGGML_METAL_EMBED_LIBRARY=ON -DCMAKE_OSX_DEPLOYMENT_TARGET=13.3 -DGGML_CPU_KLEIDIAI=ON"
|
||||
# defines: "-DGGML_METAL_EMBED_LIBRARY=ON -DCMAKE_OSX_DEPLOYMENT_TARGET=13.3 -DGGML_CPU_KLEIDIAI=ON"
|
||||
- build: 'x64'
|
||||
arch: 'x64'
|
||||
os: macos-15-intel
|
||||
@@ -1229,7 +1229,6 @@ jobs:
|
||||
-DGPU_TARGETS="${{ matrix.gpu_targets }}" \
|
||||
-DGGML_HIP=ON \
|
||||
-DHIP_PLATFORM=amd \
|
||||
-DGGML_HIP_ROCWMMA_FATTN=ON \
|
||||
-DHF_UI_VERSION=${{ needs.get-version.outputs.ui_version }} \
|
||||
${{ env.CMAKE_ARGS }}
|
||||
cmake --build build --config Release -j $(nproc)
|
||||
@@ -1353,7 +1352,6 @@ jobs:
|
||||
-DGGML_NATIVE=OFF `
|
||||
-DGGML_CPU=OFF `
|
||||
-DGPU_TARGETS="${{ matrix.gpu_targets }}" `
|
||||
-DGGML_HIP_ROCWMMA_FATTN=ON `
|
||||
-DGGML_HIP=ON `
|
||||
-DHF_UI_VERSION=${{ needs.get-version.outputs.ui_version }} `
|
||||
-DLLAMA_BUILD_BORINGSSL=ON
|
||||
@@ -1402,7 +1400,6 @@ jobs:
|
||||
run: |
|
||||
sysctl -a
|
||||
cmake -B build -G Xcode \
|
||||
-DGGML_METAL_USE_BF16=ON \
|
||||
-DGGML_METAL_EMBED_LIBRARY=ON \
|
||||
-DLLAMA_OPENSSL=OFF \
|
||||
-DLLAMA_BUILD_APP=OFF \
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
[](https://github.com/ggml-org/llama.cpp/actions/workflows/docker.yml)
|
||||
[](https://github.com/ggml-org/llama.cpp/actions/workflows/winget.yml)
|
||||
|
||||
[manifesto](https://github.com/ggml-org/llama.cpp/discussions/205) / [ggml](https://github.com/ggml-org/ggml) / [ops](https://github.com/ggml-org/llama.cpp/blob/master/docs/ops.md) / [maintainer PRs](https://github.com/ggml-org/llama.cpp/issues?q=is%3Apr%20is%3Aopen%20draft%3AFalse%20(author%3Argerganov%20OR%20author%3AKitaitiMakoto%20OR%20author%3Adanbev%20OR%20author%3Aaldehir%20OR%20author%3Amax-krasnyansky%20OR%20author%3ACISC%20OR%20author%3Aggerganov%20OR%20author%3Aam17an%20OR%20author%3Abartowski1182%20OR%20author%3Ahipudding%20OR%20author%3AServeurpersoCom%20OR%20author%3Apwilkin%20OR%20author%3Areeselevine%20OR%20author%3Angxson%20OR%20author%3Ajeffbolznv%20OR%20author%3A0cc4m%20OR%20author%3Aangt%20OR%20author%3AIMbackK%20OR%20author%3Aarthw%20OR%20author%3AJohannesGaessler%20OR%20author%3AORippler%20OR%20author%3Aruixiang63%20OR%20author%3Axctan%20OR%20author%3Aallozaur%20OR%20author%3Ayomaytk%20OR%20author%3Aaendk%20OR%20author%3Agaugarg-nv%20OR%20author%3Ataronaeo%20OR%20author%3Aforforever73%20OR%20author%3Alhez%20OR%20author%3Anetrunnereve%20OR%20author%3Afairydreaming)%20sort%3Aupdated-desc) / [dev branches](https://github.com/ggml-org/llama.cpp-dev/blob/master/README-features.md) / [compile times](https://github.com/ggml-org/llama.cpp-dev/blob/master/README-compile-times.md) / [lib llama API](https://github.com/ggml-org/llama.cpp/issues/9289) / [llama-server REST API](https://github.com/ggml-org/llama.cpp/issues/9291)
|
||||
[manifesto](https://github.com/ggml-org/llama.cpp/discussions/205) / [ggml](https://github.com/ggml-org/ggml) / [ops](https://github.com/ggml-org/llama.cpp/blob/master/docs/ops.md) / [maintainer PRs](https://github.com/ggml-org/llama.cpp/issues?q=is%3Apr%20is%3Aopen%20draft%3AFalse%20(author%3Argerganov%20OR%20author%3AKitaitiMakoto%20OR%20author%3Adanbev%20OR%20author%3Aaldehir%20OR%20author%3Amax-krasnyansky%20OR%20author%3ACISC%20OR%20author%3Aggerganov%20OR%20author%3Aam17an%20OR%20author%3Abartowski1182%20OR%20author%3Ahipudding%20OR%20author%3AServeurpersoCom%20OR%20author%3Apwilkin%20OR%20author%3Areeselevine%20OR%20author%3Angxson%20OR%20author%3Ajeffbolznv%20OR%20author%3A0cc4m%20OR%20author%3Aangt%20OR%20author%3AIMbackK%20OR%20author%3Aarthw%20OR%20author%3AJohannesGaessler%20OR%20author%3AORippler%20OR%20author%3Aruixiang63%20OR%20author%3Axctan%20OR%20author%3Aallozaur%20OR%20author%3Ayomaytk%20OR%20author%3Aaendk%20OR%20author%3Agaugarg-nv%20OR%20author%3Ataronaeo%20OR%20author%3Aforforever73%20OR%20author%3Alhez%20OR%20author%3Anetrunnereve%20OR%20author%3Afairydreaming)%20sort%3Aupdated-desc) / [compile times](https://github.com/ggml-org/llama.cpp-dev/blob/master/README-compile-times.md) / [lib llama API](https://github.com/ggml-org/llama.cpp/issues/9289) / [llama-server REST API](https://github.com/ggml-org/llama.cpp/issues/9291)
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -21,11 +21,18 @@ Please disclose it as a private [security advisory](https://github.com/ggml-org/
|
||||
|
||||
A team of volunteers on a reasonable-effort basis maintains this project. As such, please give us at least 90 days to work on a fix before public exposure.
|
||||
|
||||
### AI-powered code scan
|
||||
|
||||
llama.cpp has an AI security scanner that scans the code periodically. The full prompts and tool set can be found in [ggml-org/security-scan-prompt](https://github.com/ggml-org/security-scan-prompt).
|
||||
|
||||
We greatly appreciate reports that reflect genuine research effort, and we are happy to spend our time reviewing them. Findings that an autonomous AI agent can surface on its own add little on top of the scans we already run.
|
||||
|
||||
### Requirements
|
||||
|
||||
Before submitting your report, ensure you meet the following requirements:
|
||||
|
||||
- You have read this policy and fully understand it.
|
||||
- You have searched for existing discussions of the issue. If it has already been reported, your report will likely be rejected as a duplicate.
|
||||
- AI is only permitted in an assistive capacity as stated in [AGENTS.md](AGENTS.md). We do not accept reports that are written exclusively by AI.
|
||||
- Your report must include a working Proof-of-Concept in the form of a script and/or attached files.
|
||||
|
||||
@@ -46,6 +53,8 @@ Only vulnerabilities that fall within these parts of the project are considered
|
||||
|
||||
Note that none of the topics under [Using llama.cpp securely](#using-llamacpp-securely) are considered vulnerabilities in LLaMA C++.
|
||||
|
||||
Denial-of-Service (DoS) bugs are generally not treated as vulnerabilities. We don't reject them outright, but we look at them case-by-case and only accept those that are genuinely worth fixing.
|
||||
|
||||
For vulnerabilities that fall within the `vendor` directory, please report them directly to the third-party project.
|
||||
|
||||
## Using llama.cpp securely
|
||||
|
||||
@@ -17,7 +17,6 @@ LLAMA_BUILD_MTMD=ON
|
||||
GGML_METAL=ON
|
||||
GGML_METAL_EMBED_LIBRARY=ON
|
||||
GGML_BLAS_DEFAULT=ON
|
||||
GGML_METAL_USE_BF16=ON
|
||||
GGML_OPENMP=OFF
|
||||
|
||||
COMMON_C_FLAGS="-Wno-macro-redefined -Wno-shorten-64-to-32 -Wno-unused-command-line-argument -g"
|
||||
@@ -44,7 +43,6 @@ COMMON_CMAKE_ARGS=(
|
||||
-DGGML_METAL_EMBED_LIBRARY=${GGML_METAL_EMBED_LIBRARY}
|
||||
-DGGML_BLAS_DEFAULT=${GGML_BLAS_DEFAULT}
|
||||
-DGGML_METAL=${GGML_METAL}
|
||||
-DGGML_METAL_USE_BF16=${GGML_METAL_USE_BF16}
|
||||
-DGGML_NATIVE=OFF
|
||||
-DGGML_OPENMP=${GGML_OPENMP}
|
||||
)
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
# # with CUDA support
|
||||
# GG_BUILD_CUDA=1 bash ./ci/run.sh ./tmp/results ./tmp/mnt
|
||||
#
|
||||
# # with ROCm support
|
||||
# GG_BUILD_ROCM=1 GG_BUILD_AMDGPU_TARGETS=gfx1151 bash ./ci/run.sh ./tmp/results ./tmp/mnt
|
||||
#
|
||||
# # with SYCL support
|
||||
# GG_BUILD_SYCL=1 bash ./ci/run.sh ./tmp/results ./tmp/mnt
|
||||
#
|
||||
@@ -89,7 +92,7 @@ if [ ! -z ${GG_BUILD_CUDA} ]; then
|
||||
fi
|
||||
|
||||
if [ ! -z ${GG_BUILD_ROCM} ]; then
|
||||
CMAKE_EXTRA="${CMAKE_EXTRA} -DGGML_HIP=ON"
|
||||
CMAKE_EXTRA="${CMAKE_EXTRA} -DCMAKE_HIP_COMPILER=$(hipconfig -l)/clang -DGGML_HIP=ON"
|
||||
if [ -z ${GG_BUILD_AMDGPU_TARGETS} ]; then
|
||||
echo "Missing GG_BUILD_AMDGPU_TARGETS, please set it to your GPU architecture (e.g. gfx90a, gfx1100, etc.)"
|
||||
exit 1
|
||||
@@ -640,39 +643,52 @@ function gg_sum_rerank_tiny {
|
||||
|
||||
function gg_check_build_requirements {
|
||||
if ! command -v git &> /dev/null; then
|
||||
gg_printf 'git not found, please install'
|
||||
gg_printf 'git not found, please install\n'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v git-lfs &> /dev/null; then
|
||||
gg_printf 'git-lfs not found, please install'
|
||||
gg_printf 'git-lfs not found, please install\n'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! git config --get filter.lfs.clean &> /dev/null; then
|
||||
gg_printf 'git-lfs not initialized, please run `git lfs install`\n'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v wget &> /dev/null; then
|
||||
gg_printf 'wget not found, please install'
|
||||
gg_printf 'wget not found, please install\n'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v python3 &> /dev/null; then
|
||||
gg_printf 'python3 not found, please install'
|
||||
gg_printf 'python3 not found, please install\n'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v pip3 &> /dev/null; then
|
||||
gg_printf 'pip3 not found, please install'
|
||||
gg_printf 'pip3 not found, please install\n'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! python3 -m ensurepip --help &> /dev/null; then
|
||||
gg_printf 'ensurepip not found, please install python3-venv package'
|
||||
gg_printf 'ensurepip not found, please install python3-venv package\n'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v cmake &> /dev/null; then
|
||||
gg_printf 'cmake not found, please install'
|
||||
gg_printf 'cmake not found, please install\n'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v ccache &> /dev/null; then
|
||||
gg_printf 'ccache not found, please consider installing for faster builds'
|
||||
gg_printf 'ccache not found, please consider installing for faster builds\n'
|
||||
fi
|
||||
|
||||
if ! command -v ctest &> /dev/null; then
|
||||
gg_printf 'ctest not found, please install'
|
||||
gg_printf 'ctest not found, please install\n'
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@@ -3308,6 +3308,16 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
|
||||
params.server_tools = parse_csv_row(value);
|
||||
}
|
||||
).set_examples({LLAMA_EXAMPLE_SERVER}).set_env("LLAMA_ARG_TOOLS"));
|
||||
add_opt(common_arg(
|
||||
{"--tools-runtime"}, "OPTION",
|
||||
"experimental: run tools in a separate runtime environment (default: none, use host environment)\n"
|
||||
"available options:\n"
|
||||
" 'docker:<image>': spin up a new Docker container and reuse it for all invocations, clean up on server exit\n"
|
||||
" 'docker-container:<id>': use an existing Docker container by ID, won't stop on server exit\n",
|
||||
[](common_params & params, const std::string & value) {
|
||||
params.server_tools_runtime = value;
|
||||
}
|
||||
).set_examples({LLAMA_EXAMPLE_SERVER}).set_env("LLAMA_ARG_TOOLS_RUNTIME"));
|
||||
add_opt(common_arg(
|
||||
{"--mcp-servers-config"}, "PATH",
|
||||
"experimental: path to JSON file with MCP server definitions (Cursor-compatible format) - do not enable in untrusted environments (default: none)\n"
|
||||
|
||||
@@ -655,6 +655,7 @@ struct common_params {
|
||||
|
||||
// enable built-in tools
|
||||
std::vector<std::string> server_tools;
|
||||
std::string server_tools_runtime;
|
||||
|
||||
// MCP server configs (Cursor-compatible JSON)
|
||||
std::string mcp_servers_config; // path to JSON file with MCP server definitions
|
||||
|
||||
+4
-1
@@ -136,7 +136,10 @@ static std::vector<llama_device_memory_data> common_get_device_memory_data_impl(
|
||||
devs.push_back(llama_model_get_device(model, i));
|
||||
}
|
||||
|
||||
hp_ngl = llama_model_n_layer(model) + llama_model_n_layer_nextn(model);
|
||||
hp_ngl = llama_model_n_layer(model);
|
||||
if (mparams->load_mtp) {
|
||||
hp_ngl += llama_model_n_layer_nextn(model);
|
||||
}
|
||||
hp_n_ctx_train = llama_model_n_ctx_train(model);
|
||||
hp_n_expert = llama_model_n_expert(model);
|
||||
|
||||
|
||||
@@ -70,6 +70,7 @@ TEXT_MODEL_MAP: dict[str, str] = {
|
||||
"Exaone4ForCausalLM": "exaone",
|
||||
"ExaoneForCausalLM": "exaone",
|
||||
"ExaoneMoEForCausalLM": "exaone",
|
||||
"ExaoneMoeForCausalLM": "exaone",
|
||||
"FalconForCausalLM": "falcon",
|
||||
"FalconH1ForCausalLM": "falcon_h1",
|
||||
"FalconMambaForCausalLM": "mamba",
|
||||
@@ -102,6 +103,7 @@ TEXT_MODEL_MAP: dict[str, str] = {
|
||||
"GraniteMoeForCausalLM": "granite",
|
||||
"GraniteMoeHybridForCausalLM": "granite",
|
||||
"GraniteMoeSharedForCausalLM": "granite",
|
||||
"GraniteSwitchForCausalLM": "granite",
|
||||
"GraniteSpeechForConditionalGeneration": "granite",
|
||||
"GraniteSpeechPlusForConditionalGeneration": "granite",
|
||||
"Grok1ForCausalLM": "grok",
|
||||
|
||||
+21
-1
@@ -17,8 +17,11 @@ from .base import LazyTorchTensor, MmprojModel, ModelBase, TextModel, gguf, logg
|
||||
from .qwen import QwenModel
|
||||
|
||||
|
||||
@ModelBase.register("DeepseekOCRForCausalLM", "UnlimitedOCRForCausalLM")
|
||||
@ModelBase.register("DeepseekOCRForCausalLM")
|
||||
class DeepseekOCRVisionModel(MmprojModel):
|
||||
# HF dynamic_preprocess() max_num, which differs per model
|
||||
preproc_max_tiles = 9
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.clip_projector_type = gguf.VisionProjectorType.DEEPSEEKOCR
|
||||
@@ -43,6 +46,9 @@ class DeepseekOCRVisionModel(MmprojModel):
|
||||
# @bluebread: there's no window_size in config but just add it here anyway
|
||||
self.gguf_writer.add_vision_window_size(self.hparams.get("window_size", 14))
|
||||
|
||||
self.gguf_writer.add_vision_preproc_min_tiles(2)
|
||||
self.gguf_writer.add_vision_preproc_max_tiles(self.preproc_max_tiles)
|
||||
|
||||
# SAM configuration
|
||||
sam_hparams = hparams['sam']
|
||||
self.gguf_writer.add_vision_sam_layers_count(sam_hparams['layers'])
|
||||
@@ -93,8 +99,15 @@ class DeepseekOCRVisionModel(MmprojModel):
|
||||
return super().filter_tensors((name, gen))
|
||||
|
||||
|
||||
@ModelBase.register("UnlimitedOCRForCausalLM")
|
||||
class UnlimitedOCRVisionModel(DeepseekOCRVisionModel):
|
||||
preproc_max_tiles = 32
|
||||
|
||||
|
||||
@ModelBase.register("DeepseekOCR2ForCausalLM")
|
||||
class DeepseekOCR2VisionModel(DeepseekOCRVisionModel):
|
||||
preproc_max_tiles = 6
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.clip_projector_type = gguf.VisionProjectorType.DEEPSEEKOCR2
|
||||
@@ -520,6 +533,13 @@ class DeepseekV4Model(TextModel):
|
||||
for key, value in raw_hparams.items():
|
||||
self.hparams.setdefault(key, value)
|
||||
|
||||
# workaround for special rope_parameters (main/compress) in transformers 5.x
|
||||
if self.rope_parameters.get("full_attention", self.rope_parameters).get("rope_type") is None:
|
||||
if (rope_scaling := raw_hparams.get("rope_scaling")) is not None:
|
||||
if "rope_type" not in rope_scaling and (rope_type := rope_scaling.get("type")) is not None:
|
||||
rope_scaling["rope_type"] = rope_type
|
||||
self.rope_parameters.update(**rope_scaling)
|
||||
|
||||
self.block_count = self.hparams["num_hidden_layers"]
|
||||
if self.mtp_only:
|
||||
self.block_count += self.hparams.get("num_nextn_predict_layers", 0)
|
||||
|
||||
@@ -123,7 +123,9 @@ class Exaone4Model(TextModel):
|
||||
yield (self.format_tensor_name(gguf.MODEL_TENSOR.ROPE_FREQS), torch.tensor(rope_factors, dtype=torch.float32))
|
||||
|
||||
|
||||
@ModelBase.register("ExaoneMoEForCausalLM")
|
||||
# note: transformers >= 5.1 renamed the class to "ExaoneMoeForCausalLM" (lowercase 'e'),
|
||||
# so accept both spellings - LG AI have updated the configs of already-released models
|
||||
@ModelBase.register("ExaoneMoEForCausalLM", "ExaoneMoeForCausalLM")
|
||||
class ExaoneMoEModel(Exaone4Model):
|
||||
model_arch = gguf.MODEL_ARCH.EXAONE_MOE
|
||||
|
||||
|
||||
@@ -123,6 +123,166 @@ class GraniteMoeModel(GraniteModel):
|
||||
yield from super().modify_tensors(data_torch, name, bid)
|
||||
|
||||
|
||||
@ModelBase.register("GraniteSwitchForCausalLM")
|
||||
class GraniteSwitchModel(GraniteMoeModel):
|
||||
"""Dense, all-attention Granite with N per-token embedded LoRA adapters, stacked
|
||||
over the adapter dim with a zero adapter at slot 0 (N = num_adapters + 1)."""
|
||||
model_arch = gguf.MODEL_ARCH.GRANITE_SWITCH
|
||||
|
||||
# permute q/k per-slice below (NORM-rope layout), not via the parent's auto-permute
|
||||
undo_permute = False
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
# the weightless switch reserves one cache slot: one fewer block than num_hidden_layers
|
||||
self.block_count = self.block_count - 1
|
||||
self.tensor_map = gguf.get_tensor_name_map(self.model_arch, self.block_count)
|
||||
|
||||
self._n_adapters = int(self.hparams["num_adapters"])
|
||||
self._max_lora_rank = int(self.hparams["max_lora_rank"])
|
||||
self._n_slots = self._n_adapters + 1 # +1 for the zero slot at index 0
|
||||
|
||||
n_head = int(self.hparams["num_attention_heads"])
|
||||
n_kv_head = int(self.hparams["num_key_value_heads"])
|
||||
head_dim = (
|
||||
self.hparams.get("projection_head_dim")
|
||||
or self.hparams.get("head_dim")
|
||||
or (self.hparams["hidden_size"] // n_head)
|
||||
)
|
||||
self._n_head = n_head
|
||||
self._n_kv_head = n_kv_head
|
||||
self._head_dim = int(head_dim)
|
||||
self._q_size = n_head * self._head_dim
|
||||
self._kv_size = n_kv_head * self._head_dim
|
||||
|
||||
def set_gguf_parameters(self):
|
||||
super().set_gguf_parameters()
|
||||
|
||||
# dense: pin expert_used_count to 0 (config carries a leftover num_experts_per_tok)
|
||||
if not self.hparams.get("num_local_experts"):
|
||||
self.gguf_writer.add_expert_used_count(0)
|
||||
|
||||
self.gguf_writer.add_adapter_count(self._n_adapters)
|
||||
self.gguf_writer.add_adapter_lora_rank(self._max_lora_rank)
|
||||
self.gguf_writer.add_adapter_token_ids_activate(self.hparams["adapter_token_ids"])
|
||||
self.gguf_writer.add_adapter_token_ids_substitute(self.hparams["adapter_substitute_token_ids"])
|
||||
router_gain = float(self.hparams.get("control_token_gain", 15.0))
|
||||
self.gguf_writer.add_adapter_router_gain(router_gain)
|
||||
logger.info("gguf: (graniteswitch) num_adapters=%s max_lora_rank=%s n_slots=%s router_gain=%s", self._n_adapters, self._max_lora_rank, self._n_slots, router_gain)
|
||||
|
||||
def _lora_a(self, data: Tensor) -> Tensor:
|
||||
# on-disk A: [n_adapters, 1, max_rank, in] -> [n_adapters+1, max_rank, in]
|
||||
a = data.squeeze(1)
|
||||
zero = torch.zeros_like(a[:1])
|
||||
return torch.cat([zero, a], dim=0).contiguous()
|
||||
|
||||
def _lora_b(self, data: Tensor, permute_n_head: int | None = None) -> Tensor:
|
||||
# on-disk B: [n_adapters, 1, out, max_rank] -> [n_adapters+1, out, max_rank]
|
||||
b = data.squeeze(1)
|
||||
if permute_n_head is not None:
|
||||
# permute each adapter's B output rows to match the permuted q/k base
|
||||
b = torch.stack([self.permute(b[i], permute_n_head, permute_n_head) for i in range(b.shape[0])], dim=0)
|
||||
zero = torch.zeros_like(b[:1])
|
||||
return torch.cat([zero, b], dim=0).contiguous()
|
||||
|
||||
def modify_tensors(self, data_torch: Tensor, name: str, bid: int | None) -> Iterable[tuple[str, Tensor]]:
|
||||
T = gguf.MODEL_TENSOR
|
||||
|
||||
# skip the weightless switch + control-token buffers (rebuilt at load time)
|
||||
bare = name.split(".")[-1]
|
||||
if (
|
||||
name.startswith("model.switch.") or name.startswith("switch.")
|
||||
or bare in ("adapter_token_ids", "control_to_substitute_lut")
|
||||
):
|
||||
return
|
||||
|
||||
if "self_attn.qkv_proj" in name:
|
||||
if name.endswith("base_layer.weight"):
|
||||
# fused [q|k|v] rows: permute q/k row-blocks for ggml's NORM-rope layout
|
||||
q, k, v = data_torch.split([self._q_size, self._kv_size, self._kv_size], dim=0)
|
||||
q = self.permute(q, self._n_head, self._n_head)
|
||||
k = self.permute(k, self._n_kv_head, self._n_kv_head)
|
||||
fused = torch.cat([q, k, v], dim=0)
|
||||
yield (self.format_tensor_name(T.ATTN_QKV, bid), fused)
|
||||
return
|
||||
if "lora_A_slices." in name:
|
||||
slot = int(name.rsplit(".", 1)[1])
|
||||
key = {0: T.ATTN_Q, 1: T.ATTN_K, 2: T.ATTN_V}[slot]
|
||||
yield (self.format_tensor_name(key, bid, suffix=".lora_a"), self._lora_a(data_torch))
|
||||
return
|
||||
if "lora_B_slices." in name:
|
||||
slot = int(name.rsplit(".", 1)[1])
|
||||
key, ph = {
|
||||
0: (T.ATTN_Q, self._n_head),
|
||||
1: (T.ATTN_K, self._n_kv_head),
|
||||
2: (T.ATTN_V, None),
|
||||
}[slot]
|
||||
yield (self.format_tensor_name(key, bid, suffix=".lora_b"), self._lora_b(data_torch, ph))
|
||||
return
|
||||
raise ValueError(f"Unexpected qkv_proj tensor: {name}")
|
||||
|
||||
if "self_attn.o_proj" in name:
|
||||
if name.endswith("base_layer.weight"):
|
||||
yield (self.format_tensor_name(T.ATTN_OUT, bid), data_torch)
|
||||
return
|
||||
if name.endswith("lora_A"):
|
||||
yield (self.format_tensor_name(T.ATTN_OUT, bid, suffix=".lora_a"), self._lora_a(data_torch))
|
||||
return
|
||||
if name.endswith("lora_B"):
|
||||
yield (self.format_tensor_name(T.ATTN_OUT, bid, suffix=".lora_b"), self._lora_b(data_torch))
|
||||
return
|
||||
raise ValueError(f"Unexpected o_proj tensor: {name}")
|
||||
|
||||
if "shared_mlp.input_linear" in name:
|
||||
ffn = self.hparams["shared_intermediate_size"]
|
||||
if name.endswith("base_layer.weight"):
|
||||
gate, up = data_torch.split([ffn, ffn], dim=0)
|
||||
yield (self.format_tensor_name(T.FFN_GATE, bid), gate)
|
||||
yield (self.format_tensor_name(T.FFN_UP, bid), up)
|
||||
return
|
||||
if "lora_A_slices." in name:
|
||||
slot = int(name.rsplit(".", 1)[1])
|
||||
key = {0: T.FFN_GATE, 1: T.FFN_UP}[slot]
|
||||
yield (self.format_tensor_name(key, bid, suffix=".lora_a"), self._lora_a(data_torch))
|
||||
return
|
||||
if "lora_B_slices." in name:
|
||||
slot = int(name.rsplit(".", 1)[1])
|
||||
key = {0: T.FFN_GATE, 1: T.FFN_UP}[slot]
|
||||
yield (self.format_tensor_name(key, bid, suffix=".lora_b"), self._lora_b(data_torch))
|
||||
return
|
||||
raise ValueError(f"Unexpected shared_mlp.input_linear tensor: {name}")
|
||||
|
||||
if "shared_mlp.output_linear" in name:
|
||||
if name.endswith("base_layer.weight"):
|
||||
yield (self.format_tensor_name(T.FFN_DOWN, bid), data_torch)
|
||||
return
|
||||
if name.endswith("lora_A"):
|
||||
yield (self.format_tensor_name(T.FFN_DOWN, bid, suffix=".lora_a"), self._lora_a(data_torch))
|
||||
return
|
||||
if name.endswith("lora_B"):
|
||||
yield (self.format_tensor_name(T.FFN_DOWN, bid, suffix=".lora_b"), self._lora_b(data_torch))
|
||||
return
|
||||
raise ValueError(f"Unexpected shared_mlp.output_linear tensor: {name}")
|
||||
|
||||
if bid is not None and ".layers." in name and (
|
||||
"input_layernorm" in name or "post_attention_layernorm" in name
|
||||
):
|
||||
key = T.ATTN_NORM if "input_layernorm" in name else T.FFN_NORM
|
||||
yield (self.format_tensor_name(key, bid), data_torch)
|
||||
return
|
||||
|
||||
if name in ("model.embed_tokens.weight", "embed_tokens.weight"):
|
||||
yield (self.format_tensor_name(T.TOKEN_EMBD), data_torch)
|
||||
return
|
||||
if name in ("model.norm.weight", "norm.weight"):
|
||||
yield (self.format_tensor_name(T.OUTPUT_NORM), data_torch)
|
||||
return
|
||||
if name == "lm_head.weight":
|
||||
return # tied to token_embd
|
||||
|
||||
raise ValueError(f"graniteswitch: unhandled tensor {name!r} (bid={bid})")
|
||||
|
||||
|
||||
@ModelBase.register("GraniteMoeHybridForCausalLM", "BambaForCausalLM")
|
||||
class GraniteHybridModel(Mamba2Model, GraniteMoeModel):
|
||||
"""GraniteHybrid is a hybrid SSM + Attention model that uses Mamba2 SSM
|
||||
|
||||
@@ -449,6 +449,8 @@ Or
|
||||
use 1 SYCL GPUs: [0] with Max compute units:512
|
||||
```
|
||||
|
||||
User can use the device management in [docs/multi-gpu.md](https://github.com/ggml-org/llama.cpp/blob/master/docs/multi-gpu.md), like parameter `--device SYCL0,SYCL1` to assign one or more devices.
|
||||
|
||||
## Windows
|
||||
|
||||
### Install GPU driver
|
||||
@@ -763,6 +765,7 @@ Or
|
||||
use 1 SYCL GPUs: [0] with Max compute units:512
|
||||
```
|
||||
|
||||
User can use the device management in [docs/multi-gpu.md](https://github.com/ggml-org/llama.cpp/blob/master/docs/multi-gpu.md), like parameter `--device SYCL0,SYCL1` to assign one or more devices.
|
||||
|
||||
## Environment Variable
|
||||
|
||||
@@ -895,6 +898,45 @@ Pass these via `CXXFLAGS` or add a one-off `#define` to enable a flag on the spo
|
||||
set UR_L0_ENABLE_RELAXED_ALLOCATION_LIMITS=1
|
||||
```
|
||||
|
||||
- When I set `SYCL_CACHE_PERSISTENT=1` in running time, I meet crash.
|
||||
|
||||
`SYCL_CACHE_PERSISTENT=1` is not recommended by llama.cpp SYCL backend.
|
||||
When cache is enabled, SYCL runtime will try to cache and reuse JIT-compiled binaries.
|
||||
|
||||
We find some AI will tell user this cmd to speed up SYCL backend. It only speeds up the startup to skip the JIT process, instead of running speed.
|
||||
|
||||
It will bring negative impact when the SYCL binary file is changed frequently in your running environment. The new & old codes mix will lead to crash.
|
||||
|
||||
Compare to the benefit, it has brought more failed cases.
|
||||
If you are not familiar with the SYCL compiler principle of JIT and AOT, please don't use it.
|
||||
|
||||
To restore, you need to remove the local cache: `~/.cache/libsycl_cache/` and execute `unset SYCL_CACHE_PERSISTENT` in running time.
|
||||
|
||||
- How to use iGPU and dGPU in same time?
|
||||
|
||||
1. Detect the devices in your running time.
|
||||
```
|
||||
source /opt/intel/oneapi/setvars.sh
|
||||
./build/bin/llama-server --list-devices
|
||||
|
||||
or
|
||||
./build/bin/llama-cli --list-devices
|
||||
./build/bin/llama-bench --list-devices
|
||||
./build/bin/llama-completion --list-devices
|
||||
|
||||
Available devices:
|
||||
SYCL0: Intel(R) Arc(TM) A770 Graphics (15473 MiB, 15473 MiB free)
|
||||
SYCL1: Intel(R) UHD Graphics 770 (59675 MiB, 44986 MiB free)
|
||||
```
|
||||
|
||||
The dGPU will be in the head of this list and iGPU will be the end.
|
||||
If not all GPUs are listed, please check the env var: ONEAPI_DEVICE_SELECTOR and unset it.
|
||||
|
||||
2. Set the iGPU and dGPU
|
||||
|
||||
Set the iGPU and dGPU by `./build/bin/llama-server --device SYCL0,SYCL1,SYCLxxx`.
|
||||
|
||||
|
||||
### **GitHub contribution**:
|
||||
Please add the `[SYCL]` prefix/tag in issues/PRs titles to help the SYCL contributors to check/address them without delay.
|
||||
|
||||
|
||||
+6
-6
@@ -15,7 +15,7 @@ Legend:
|
||||
| Operation | BLAS | CANN | CPU | CUDA | ET | MTL | OpenCL | SYCL | Vulkan | WebGPU | ZenDNN | zDNN |
|
||||
|-----------|------|------|------|------|------|------|------|------|------|------|------|------|
|
||||
| ABS | ❌ | ✅ | ✅ | 🟡 | 🟡 | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| ACC | ❌ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | 🟡 | ✅ | ❌ | ❌ | ❌ |
|
||||
| ACC | ❌ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| ADD | ❌ | ✅ | ✅ | ✅ | 🟡 | 🟡 | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| ADD1 | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| ADD_ID | ❌ | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
@@ -41,9 +41,9 @@ Legend:
|
||||
| DIAG | ❌ | ❌ | ✅ | ✅ | 🟡 | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| DIAG_MASK_INF | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | 🟡 | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| DIV | ❌ | ✅ | ✅ | ✅ | ❌ | 🟡 | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| DSV4_HC_COMB | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| DSV4_HC_POST | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| DSV4_HC_PRE | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| DSV4_HC_COMB | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
|
||||
| DSV4_HC_POST | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
|
||||
| DSV4_HC_PRE | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
|
||||
| DUP | ❌ | ✅ | ✅ | 🟡 | ❌ | 🟡 | 🟡 | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| ELU | ❌ | ✅ | ✅ | 🟡 | 🟡 | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| EXP | ❌ | ✅ | ✅ | 🟡 | 🟡 | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
@@ -59,7 +59,7 @@ Legend:
|
||||
| GELU | ❌ | ✅ | ✅ | 🟡 | 🟡 | ✅ | 🟡 | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| GELU_ERF | ❌ | ✅ | ✅ | 🟡 | 🟡 | ✅ | 🟡 | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| GELU_QUICK | ❌ | ✅ | ✅ | 🟡 | 🟡 | ✅ | 🟡 | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| GET_ROWS | ❌ | 🟡 | ✅ | 🟡 | 🟡 | 🟡 | 🟡 | ✅ | ✅ | 🟡 | ❌ | ❌ |
|
||||
| GET_ROWS | ❌ | 🟡 | ✅ | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | ✅ | 🟡 | ❌ | ❌ |
|
||||
| GET_ROWS_BACK | ❌ | ❌ | 🟡 | 🟡 | ❌ | ❌ | ❌ | ❌ | 🟡 | ❌ | ❌ | ❌ |
|
||||
| GROUP_NORM | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| HARDSIGMOID | ❌ | ✅ | ✅ | 🟡 | 🟡 | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
@@ -68,7 +68,7 @@ Legend:
|
||||
| IM2COL_3D | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| L2_NORM | ❌ | ✅ | ✅ | ✅ | 🟡 | ✅ | ❌ | ✅ | ✅ | 🟡 | ❌ | ❌ |
|
||||
| LEAKY_RELU | ❌ | ✅ | ✅ | ✅ | ❌ | 🟡 | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| LIGHTNING_INDEXER | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| LIGHTNING_INDEXER | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
|
||||
| LOG | ❌ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| MEAN | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| MUL | ❌ | ✅ | ✅ | ✅ | 🟡 | 🟡 | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
|
||||
+22870
-671
File diff suppressed because it is too large
Load Diff
@@ -47,6 +47,7 @@ CMD_ARGS+=("../../convert_hf_to_gguf.py" "--verbose")
|
||||
CMD_ARGS+=("${MODEL_PATH}")
|
||||
CMD_ARGS+=("--outfile" "${CONVERTED_MODEL}")
|
||||
CMD_ARGS+=("--outtype" "${TYPE}")
|
||||
CMD_ARGS+=("--model-name" "${MODEL_NAME}")
|
||||
[[ -n "$METADATA_OVERRIDE" ]] && CMD_ARGS+=("--metadata" "${METADATA_OVERRIDE}")
|
||||
[[ -n "$MMPROJ" ]] && CMD_ARGS+=("${MMPROJ}")
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ python ../../convert_hf_to_gguf.py --verbose \
|
||||
${EMBEDDING_MODEL_PATH} \
|
||||
--outfile ${CONVERTED_MODEL} \
|
||||
--outtype ${TYPE} \
|
||||
--model-name ${MODEL_NAME} \
|
||||
${SENTENCE_TRANSFORMERS}
|
||||
|
||||
echo ""
|
||||
|
||||
@@ -12,6 +12,7 @@ This script processes files with specified options.
|
||||
|
||||
Options:
|
||||
-h, --help Display this help message and exit.
|
||||
-d, --device <value> Set SYCL devices (default: SYCL0).
|
||||
-c, --context <value> Set context length. Bigger need more memory.
|
||||
-p, --promote <value> Prompt to start generation with.
|
||||
-m, --model <value> Full model file path.
|
||||
@@ -41,10 +42,16 @@ MODEL_FILE=../models/Qwen3.5-4B-Q4_0.gguf
|
||||
NGL=99
|
||||
CONTEXT=4096
|
||||
GGML_SYCL_DEVICE=-1
|
||||
SYCL_DEVICES="SYCL0"
|
||||
SPLIT_MODE=layer
|
||||
LOG_VERBOSE=3
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-d|--device)
|
||||
SYCL_DEVICES="$2"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
-c|--context)
|
||||
CONTEXT=$2
|
||||
# Shift twice to consume both the option flag and its value
|
||||
@@ -95,8 +102,6 @@ while [[ $# -gt 0 ]]; do
|
||||
esac
|
||||
done
|
||||
|
||||
|
||||
|
||||
source /opt/intel/oneapi/setvars.sh
|
||||
|
||||
#export GGML_SYCL_DEBUG=1
|
||||
@@ -107,17 +112,19 @@ source /opt/intel/oneapi/setvars.sh
|
||||
export UR_L0_ENABLE_RELAXED_ALLOCATION_LIMITS=1
|
||||
echo "UR_L0_ENABLE_RELAXED_ALLOCATION_LIMITS=${UR_L0_ENABLE_RELAXED_ALLOCATION_LIMITS}"
|
||||
|
||||
echo "ONEAPI_DEVICE_SELECTOR=${ONEAPI_DEVICE_SELECTOR}"
|
||||
|
||||
|
||||
if [ $GGML_SYCL_DEVICE -ne -1 ]; then
|
||||
echo "Use $GGML_SYCL_DEVICE as main GPU"
|
||||
#use signle GPU only
|
||||
GPUS_SETTING="-mg $GGML_SYCL_DEVICE -sm ${SPLIT_MODE}"
|
||||
echo "ONEAPI_DEVICE_SELECTOR=${ONEAPI_DEVICE_SELECTOR}"
|
||||
else
|
||||
echo "Use all Intel GPUs, including iGPU & dGPU"
|
||||
echo "Use Intel GPUs: ${SYCL_DEVICES}"
|
||||
GPUS_SETTING="-sm ${SPLIT_MODE}"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "run cmd: ZES_ENABLE_SYSMAN=1 ${BIN_FILE} -m ${MODEL_FILE} -ngl ${NGL} -s ${SEED} -c ${CONTEXT} ${GPUS_SETTING} -lv ${LOG_VERBOSE} --mmap --host 0.0.0.0 --port 8000"
|
||||
ZES_ENABLE_SYSMAN=1 ${BIN_FILE} -m ${MODEL_FILE} -ngl ${NGL} -s ${SEED} -c ${CONTEXT} ${GPUS_SETTING} -lv ${LOG_VERBOSE} --mmap --host 0.0.0.0 --port 8000
|
||||
echo "run cmd: ZES_ENABLE_SYSMAN=1 ${BIN_FILE} -m ${MODEL_FILE} -ngl ${NGL} -s ${SEED} -c ${CONTEXT} ${GPUS_SETTING} -lv ${LOG_VERBOSE} --device ${SYCL_DEVICES} --mmap --host 0.0.0.0 --port 8000"
|
||||
ZES_ENABLE_SYSMAN=1 ${BIN_FILE} -m ${MODEL_FILE} -ngl ${NGL} -s ${SEED} -c ${CONTEXT} ${GPUS_SETTING} -lv ${LOG_VERBOSE} --device ${SYCL_DEVICES} --mmap --host 0.0.0.0 --port 8000
|
||||
|
||||
|
||||
|
||||
+12
-4
@@ -12,6 +12,7 @@ This script processes files with specified options.
|
||||
|
||||
Options:
|
||||
-h, --help Display this help message and exit.
|
||||
-d, --device <value> Set SYCL devices (default: SYCL0).
|
||||
-c, --context <value> Set context length. Bigger need more memory.
|
||||
-p, --promote <value> Prompt to start generation with.
|
||||
-m, --model <value> Full model file path.
|
||||
@@ -42,10 +43,16 @@ MODEL_FILE=../models/llama-2-7b.Q4_0.gguf
|
||||
NGL=99
|
||||
CONTEXT=4096
|
||||
GGML_SYCL_DEVICE=-1
|
||||
SYCL_DEVICES="SYCL0"
|
||||
SPLIT_MODE=layer
|
||||
LOG_VERBOSE=3
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-d|--device)
|
||||
SYCL_DEVICES="$2"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
-c|--context)
|
||||
CONTEXT=$2
|
||||
# Shift twice to consume both the option flag and its value
|
||||
@@ -115,16 +122,17 @@ source /opt/intel/oneapi/setvars.sh
|
||||
export UR_L0_ENABLE_RELAXED_ALLOCATION_LIMITS=1
|
||||
echo "UR_L0_ENABLE_RELAXED_ALLOCATION_LIMITS=${UR_L0_ENABLE_RELAXED_ALLOCATION_LIMITS}"
|
||||
|
||||
echo "ONEAPI_DEVICE_SELECTOR=${ONEAPI_DEVICE_SELECTOR}"
|
||||
|
||||
if [ $GGML_SYCL_DEVICE -ne -1 ]; then
|
||||
echo "Use $GGML_SYCL_DEVICE as main GPU"
|
||||
#use signle GPU only
|
||||
GPUS_SETTING="-mg $GGML_SYCL_DEVICE -sm ${SPLIT_MODE}"
|
||||
echo "ONEAPI_DEVICE_SELECTOR=${ONEAPI_DEVICE_SELECTOR}"
|
||||
else
|
||||
echo "Use all Intel GPUs, including iGPU & dGPU"
|
||||
echo "Use Intel GPUs: ${SYCL_DEVICES}"
|
||||
GPUS_SETTING="-sm ${SPLIT_MODE}"
|
||||
fi
|
||||
|
||||
echo "run cmd: ZES_ENABLE_SYSMAN=1 ${BIN_FILE} -m ${MODEL_FILE} -no-cnv -p "${INPUT_PROMPT}" -n 200 -e -ngl ${NGL} -s ${SEED} -c ${CONTEXT} ${GPUS_SETTING} -lv ${LOG_VERBOSE} --mmap "
|
||||
ZES_ENABLE_SYSMAN=1 ${BIN_FILE} -m ${MODEL_FILE} -no-cnv -p "${INPUT_PROMPT}" -n 200 -e -ngl ${NGL} -s ${SEED} -c ${CONTEXT} ${GPUS_SETTING} -lv ${LOG_VERBOSE} --mmap
|
||||
echo "run cmd: ZES_ENABLE_SYSMAN=1 ${BIN_FILE} -m ${MODEL_FILE} -no-cnv -p "${INPUT_PROMPT}" -n 200 -e -ngl ${NGL} -s ${SEED} -c ${CONTEXT} ${GPUS_SETTING} -lv ${LOG_VERBOSE} --device ${SYCL_DEVICES} --mmap "
|
||||
ZES_ENABLE_SYSMAN=1 ${BIN_FILE} -m ${MODEL_FILE} -no-cnv -p "${INPUT_PROMPT}" -n 200 -e -ngl ${NGL} -s ${SEED} -c ${CONTEXT} ${GPUS_SETTING} -lv ${LOG_VERBOSE} --device ${SYCL_DEVICES} --mmap
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ set "MODEL_FILE=..\models\Qwen3.5-4B-Q4_0.gguf"
|
||||
set "NGL=99"
|
||||
set "CONTEXT=4096"
|
||||
set "GGML_SYCL_DEVICE=-1"
|
||||
set "SYCL_DEVICES=SYCL0"
|
||||
set "SPLIT_MODE=layer"
|
||||
set "LOG_VERBOSE=3"
|
||||
|
||||
@@ -36,6 +37,21 @@ if /I "%~1"=="--context" (
|
||||
goto parse_args
|
||||
)
|
||||
|
||||
if /I "%~1"=="-d" (
|
||||
if "%~2"=="" goto missing_value
|
||||
set "SYCL_DEVICES=%~2"
|
||||
shift
|
||||
shift
|
||||
goto parse_args
|
||||
)
|
||||
if /I "%~1"=="--device" (
|
||||
if "%~2"=="" goto missing_value
|
||||
set "SYCL_DEVICES=%~2"
|
||||
shift
|
||||
shift
|
||||
goto parse_args
|
||||
)
|
||||
|
||||
if /I "%~1"=="-m" (
|
||||
if "%~2"=="" goto missing_value
|
||||
set "MODEL_FILE=%~2"
|
||||
@@ -130,6 +146,7 @@ echo This script processes files with specified options.
|
||||
echo.
|
||||
echo Options:
|
||||
echo -h, --help Display this help message and exit.
|
||||
echo -d, --device ^<value^> Set SYCL devices (default: SYCL0).
|
||||
echo -c, --context ^<value^> Set context length. Bigger need more memory.
|
||||
echo -m, --model ^<value^> Full model file path.
|
||||
echo -mg,--main-gpu ^<value^> Set main GPU ID (0 - n) for single GPU mode.
|
||||
@@ -160,19 +177,20 @@ REM Support malloc device memory more than 4GB.
|
||||
set "UR_L0_ENABLE_RELAXED_ALLOCATION_LIMITS=1"
|
||||
echo UR_L0_ENABLE_RELAXED_ALLOCATION_LIMITS=%UR_L0_ENABLE_RELAXED_ALLOCATION_LIMITS%
|
||||
|
||||
echo ONEAPI_DEVICE_SELECTOR=%ONEAPI_DEVICE_SELECTOR%
|
||||
|
||||
if not "%GGML_SYCL_DEVICE%"=="-1" (
|
||||
echo Use %GGML_SYCL_DEVICE% as main GPU
|
||||
REM Use single GPU only.
|
||||
set "GPUS_SETTING=-mg %GGML_SYCL_DEVICE% -sm %SPLIT_MODE%"
|
||||
echo ONEAPI_DEVICE_SELECTOR=%ONEAPI_DEVICE_SELECTOR%
|
||||
) else (
|
||||
echo Use all Intel GPUs, including iGPU ^& dGPU
|
||||
) else (
|
||||
echo Use Intel GPUs: %SYCL_DEVICES%
|
||||
set "GPUS_SETTING=-sm %SPLIT_MODE%"
|
||||
)
|
||||
|
||||
echo run cmd: ZES_ENABLE_SYSMAN=1 %BIN_FILE% -m "%MODEL_FILE%" -ngl %NGL% -s %SEED% -c %CONTEXT% %GPUS_SETTING% -lv %LOG_VERBOSE% --mmap --host 0.0.0.0 --port 8000
|
||||
echo run cmd: ZES_ENABLE_SYSMAN=1 %BIN_FILE% -m "%MODEL_FILE%" -ngl %NGL% -s %SEED% -c %CONTEXT% %GPUS_SETTING% -lv %LOG_VERBOSE% --device %SYCL_DEVICES% --mmap --host 0.0.0.0 --port 8000
|
||||
set "ZES_ENABLE_SYSMAN=1"
|
||||
%BIN_FILE% -m "%MODEL_FILE%" -ngl %NGL% -s %SEED% -c %CONTEXT% %GPUS_SETTING% -lv %LOG_VERBOSE% --mmap --host 0.0.0.0 --port 8000
|
||||
%BIN_FILE% -m "%MODEL_FILE%" -ngl %NGL% -s %SEED% -c %CONTEXT% %GPUS_SETTING% -lv %LOG_VERBOSE% --device "%SYCL_DEVICES%" --mmap --host 0.0.0.0 --port 8000
|
||||
|
||||
endlocal
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ set "MODEL_FILE=..\models\llama-2-7b.Q4_0.gguf"
|
||||
set "NGL=99"
|
||||
set "CONTEXT=4096"
|
||||
set "GGML_SYCL_DEVICE=-1"
|
||||
set "SYCL_DEVICES=SYCL0"
|
||||
set "SPLIT_MODE=layer"
|
||||
set "LOG_VERBOSE=3"
|
||||
|
||||
@@ -42,6 +43,21 @@ if /I "%~1"=="--context" (
|
||||
goto parse_args
|
||||
)
|
||||
|
||||
if /I "%~1"=="-d" (
|
||||
if "%~2"=="" goto missing_value
|
||||
set "SYCL_DEVICES=%~2"
|
||||
shift
|
||||
shift
|
||||
goto parse_args
|
||||
)
|
||||
if /I "%~1"=="--device" (
|
||||
if "%~2"=="" goto missing_value
|
||||
set "SYCL_DEVICES=%~2"
|
||||
shift
|
||||
shift
|
||||
goto parse_args
|
||||
)
|
||||
|
||||
if /I "%~1"=="-p" (
|
||||
if "%~2"=="" goto missing_value
|
||||
set "INPUT_PROMPT=%~2"
|
||||
@@ -151,6 +167,7 @@ echo This script processes files with specified options.
|
||||
echo.
|
||||
echo Options:
|
||||
echo -h, --help Display this help message and exit.
|
||||
echo -d, --device ^<value^> Set SYCL devices (default: SYCL0).
|
||||
echo -c, --context ^<value^> Set context length. Bigger need more memory.
|
||||
echo -p, --promote ^<value^> Prompt to start generation with.
|
||||
echo -m, --model ^<value^> Full model file path.
|
||||
@@ -182,19 +199,21 @@ REM Support malloc device memory more than 4GB.
|
||||
set "UR_L0_ENABLE_RELAXED_ALLOCATION_LIMITS=1"
|
||||
echo UR_L0_ENABLE_RELAXED_ALLOCATION_LIMITS=%UR_L0_ENABLE_RELAXED_ALLOCATION_LIMITS%
|
||||
|
||||
echo ONEAPI_DEVICE_SELECTOR=%ONEAPI_DEVICE_SELECTOR%
|
||||
|
||||
if not "%GGML_SYCL_DEVICE%"=="-1" (
|
||||
echo Use %GGML_SYCL_DEVICE% as main GPU
|
||||
REM Use single GPU only.
|
||||
set "GPUS_SETTING=-mg %GGML_SYCL_DEVICE% -sm %SPLIT_MODE%"
|
||||
echo ONEAPI_DEVICE_SELECTOR=%ONEAPI_DEVICE_SELECTOR%
|
||||
) else (
|
||||
echo Use all Intel GPUs, including iGPU ^& dGPU
|
||||
)
|
||||
else (
|
||||
echo Use Intel GPUs: %SYCL_DEVICES%
|
||||
set "GPUS_SETTING=-sm %SPLIT_MODE%"
|
||||
)
|
||||
|
||||
echo run cmd: ZES_ENABLE_SYSMAN=1 %BIN_FILE% -m %MODEL_FILE% -no-cnv -p "%INPUT_PROMPT%" -n 200 -e -ngl %NGL% -s %SEED% -c %CONTEXT% %GPUS_SETTING% -lv %LOG_VERBOSE% --mmap
|
||||
echo run cmd: ZES_ENABLE_SYSMAN=1 %BIN_FILE% -m %MODEL_FILE% -no-cnv -p "%INPUT_PROMPT%" -n 200 -e -ngl %NGL% -s %SEED% -c %CONTEXT% %GPUS_SETTING% -lv %LOG_VERBOSE% --device %SYCL_DEVICES% --mmap
|
||||
set "ZES_ENABLE_SYSMAN=1"
|
||||
%BIN_FILE% -m "%MODEL_FILE%" -no-cnv -p "%INPUT_PROMPT%" -n 200 -e -ngl %NGL% -s %SEED% -c %CONTEXT% %GPUS_SETTING% -lv %LOG_VERBOSE% --mmap
|
||||
%BIN_FILE% -m "%MODEL_FILE%" -no-cnv -p "%INPUT_PROMPT%" -n 200 -e -ngl %NGL% -s %SEED% -c %CONTEXT% %GPUS_SETTING% -lv %LOG_VERBOSE% --device "%SYCL_DEVICES%" --mmap
|
||||
|
||||
endlocal
|
||||
|
||||
|
||||
+2
-2
@@ -4,8 +4,8 @@ project("ggml" C CXX ASM)
|
||||
|
||||
### GGML Version
|
||||
set(GGML_VERSION_MAJOR 0)
|
||||
set(GGML_VERSION_MINOR 18)
|
||||
set(GGML_VERSION_PATCH 1)
|
||||
set(GGML_VERSION_MINOR 19)
|
||||
set(GGML_VERSION_PATCH 0)
|
||||
set(GGML_VERSION_BASE "${GGML_VERSION_MAJOR}.${GGML_VERSION_MINOR}.${GGML_VERSION_PATCH}")
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")
|
||||
|
||||
@@ -2788,6 +2788,12 @@ extern "C" {
|
||||
struct ggml_cgraph * cgraph,
|
||||
struct ggml_tensor * tensor);
|
||||
|
||||
// add the tensor and its parents to the graph without marking them for compute
|
||||
// the flag is set later, when the tensor is reached from a node that computes
|
||||
GGML_API void ggml_build_forward_order(
|
||||
struct ggml_cgraph * cgraph,
|
||||
struct ggml_tensor * tensor);
|
||||
|
||||
GGML_API void ggml_build_backward_expand(
|
||||
struct ggml_context * ctx, // context for gradient computation
|
||||
struct ggml_cgraph * cgraph,
|
||||
|
||||
@@ -8,6 +8,22 @@
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
#if !defined(HWCAP_FPHP)
|
||||
#define HWCAP_FPHP (1 << 9)
|
||||
#endif
|
||||
|
||||
#if !defined(HWCAP_ASIMDHP)
|
||||
#define HWCAP_ASIMDHP (1 << 10)
|
||||
#endif
|
||||
|
||||
#if !defined(HWCAP_ASIMDDP)
|
||||
#define HWCAP_ASIMDDP (1 << 20)
|
||||
#endif
|
||||
|
||||
#if !defined(HWCAP_SVE)
|
||||
#define HWCAP_SVE (1 << 22)
|
||||
#endif
|
||||
|
||||
#if !defined(HWCAP2_SVE2)
|
||||
#define HWCAP2_SVE2 (1 << 1)
|
||||
#endif
|
||||
@@ -23,7 +39,7 @@
|
||||
struct aarch64_features {
|
||||
// has_neon not needed, aarch64 has NEON guaranteed
|
||||
bool has_dotprod = false;
|
||||
bool has_fp16_va = false;
|
||||
bool has_fp16 = false;
|
||||
bool has_sve = false;
|
||||
bool has_sve2 = false;
|
||||
bool has_i8mm = false;
|
||||
@@ -36,7 +52,7 @@ struct aarch64_features {
|
||||
uint32_t hwcap2 = getauxval(AT_HWCAP2);
|
||||
|
||||
has_dotprod = !!(hwcap & HWCAP_ASIMDDP);
|
||||
has_fp16_va = !!(hwcap & HWCAP_FPHP);
|
||||
has_fp16 = !!(hwcap & HWCAP_FPHP) && !!(hwcap & HWCAP_ASIMDHP);
|
||||
has_sve = !!(hwcap & HWCAP_SVE);
|
||||
has_sve2 = !!(hwcap2 & HWCAP2_SVE2);
|
||||
has_i8mm = !!(hwcap2 & HWCAP2_I8MM);
|
||||
@@ -75,7 +91,7 @@ static int ggml_backend_cpu_aarch64_score() {
|
||||
score += 1<<1;
|
||||
#endif
|
||||
#ifdef GGML_USE_FP16_VECTOR_ARITHMETIC
|
||||
if (!af.has_fp16_va) { return 0; }
|
||||
if (!af.has_fp16) { return 0; }
|
||||
score += 1<<2;
|
||||
#endif
|
||||
#ifdef GGML_USE_SVE
|
||||
|
||||
@@ -195,6 +195,7 @@ template <typename BLOC_TYPE, int64_t INTER_SIZE, int64_t NB_COLS> class tensor_
|
||||
case GGML_TYPE_Q4_K:
|
||||
case GGML_TYPE_Q6_K:
|
||||
case GGML_TYPE_Q8_0:
|
||||
case GGML_TYPE_Q5_0:
|
||||
case GGML_TYPE_Q5_1:
|
||||
case GGML_TYPE_Q5_K:
|
||||
//case GGML_TYPE_MXFP4:
|
||||
@@ -214,6 +215,7 @@ template <typename BLOC_TYPE, int64_t INTER_SIZE, int64_t NB_COLS> class tensor_
|
||||
case GGML_TYPE_Q4_K:
|
||||
case GGML_TYPE_Q6_K:
|
||||
case GGML_TYPE_Q8_0:
|
||||
case GGML_TYPE_Q5_0:
|
||||
case GGML_TYPE_Q5_1:
|
||||
case GGML_TYPE_Q5_K:
|
||||
//case GGML_TYPE_MXFP4:
|
||||
|
||||
+22
-22
@@ -253,9 +253,9 @@ static void ggml_cpy_f32_q8_0_cuda(
|
||||
const int64_t nb03, const int64_t ne10, const int64_t ne11, const int64_t ne12, const int64_t nb10, const int64_t nb11, const int64_t nb12, const int64_t nb13, cudaStream_t stream) {
|
||||
|
||||
GGML_ASSERT(ne % QK8_0 == 0);
|
||||
const int64_t num_blocks = ne / QK8_0;
|
||||
const int64_t num_blocks = (ne/QK8_0 + CUDA_CPY_BLOCK_SIZE - 1) / CUDA_CPY_BLOCK_SIZE;
|
||||
GGML_ASSERT(num_blocks <= INT_MAX);
|
||||
cpy_f32_q<cpy_blck_f32_q8_0, QK8_0><<<num_blocks, 1, 0, stream>>>
|
||||
cpy_f32_q<cpy_blck_f32_q8_0, QK8_0><<<num_blocks, CUDA_CPY_BLOCK_SIZE, 0, stream>>>
|
||||
(cx, cdst, ne, ne00, ne01, ne02, nb00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb13);
|
||||
}
|
||||
|
||||
@@ -264,9 +264,9 @@ static void ggml_cpy_q8_0_f32_cuda(
|
||||
const int64_t ne00, const int64_t ne01, const int64_t ne02, const int64_t nb00, const int64_t nb01, const int64_t nb02,
|
||||
const int64_t nb03, const int64_t ne10, const int64_t ne11, const int64_t ne12, const int64_t nb10, const int64_t nb11, const int64_t nb12, const int64_t nb13, cudaStream_t stream) {
|
||||
|
||||
const int64_t num_blocks = ne;
|
||||
const int64_t num_blocks = (ne/QK8_0 + CUDA_CPY_BLOCK_SIZE - 1) / CUDA_CPY_BLOCK_SIZE;
|
||||
GGML_ASSERT(num_blocks <= INT_MAX);
|
||||
cpy_q_f32<cpy_blck_q8_0_f32, QK8_0><<<num_blocks, 1, 0, stream>>>
|
||||
cpy_q_f32<cpy_blck_q8_0_f32, QK8_0><<<num_blocks, CUDA_CPY_BLOCK_SIZE, 0, stream>>>
|
||||
(cx, cdst, ne, ne00, ne01, ne02, nb00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb13);
|
||||
}
|
||||
|
||||
@@ -276,9 +276,9 @@ static void ggml_cpy_f32_q4_0_cuda(
|
||||
const int64_t nb03, const int64_t ne10, const int64_t ne11, const int64_t ne12, const int64_t nb10, const int64_t nb11, const int64_t nb12, const int64_t nb13, cudaStream_t stream) {
|
||||
|
||||
GGML_ASSERT(ne % QK4_0 == 0);
|
||||
const int64_t num_blocks = ne / QK4_0;
|
||||
const int64_t num_blocks = (ne/QK4_0 + CUDA_CPY_BLOCK_SIZE - 1) / CUDA_CPY_BLOCK_SIZE;
|
||||
GGML_ASSERT(num_blocks <= INT_MAX);
|
||||
cpy_f32_q<cpy_blck_f32_q4_0, QK4_0><<<num_blocks, 1, 0, stream>>>
|
||||
cpy_f32_q<cpy_blck_f32_q4_0, QK4_0><<<num_blocks, CUDA_CPY_BLOCK_SIZE, 0, stream>>>
|
||||
(cx, cdst, ne, ne00, ne01, ne02, nb00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb13);
|
||||
}
|
||||
|
||||
@@ -289,9 +289,9 @@ static void ggml_cpy_q4_0_f32_cuda(
|
||||
const int64_t nb03, const int64_t ne10, const int64_t ne11, const int64_t ne12,
|
||||
const int64_t nb10, const int64_t nb11, const int64_t nb12, const int64_t nb13,
|
||||
cudaStream_t stream) {
|
||||
const int64_t num_blocks = ne;
|
||||
const int64_t num_blocks = (ne/QK4_0 + CUDA_CPY_BLOCK_SIZE - 1) / CUDA_CPY_BLOCK_SIZE;
|
||||
GGML_ASSERT(num_blocks <= INT_MAX);
|
||||
cpy_q_f32<cpy_blck_q_f32<dequantize_q4_0, QK4_0>, QK4_0><<<num_blocks, 1, 0, stream>>>(
|
||||
cpy_q_f32<cpy_blck_q_f32<dequantize_q4_0, QK4_0>, QK4_0><<<num_blocks, CUDA_CPY_BLOCK_SIZE, 0, stream>>>(
|
||||
cx, cdst, ne, ne00, ne01, ne02, nb00, nb01, nb02, nb03,
|
||||
ne10, ne11, ne12, nb10, nb11, nb12, nb13);
|
||||
}
|
||||
@@ -302,9 +302,9 @@ static void ggml_cpy_f32_q4_1_cuda(
|
||||
const int64_t nb03, const int64_t ne10, const int64_t ne11, const int64_t ne12, const int64_t nb10, const int64_t nb11, const int64_t nb12, const int64_t nb13, cudaStream_t stream) {
|
||||
|
||||
GGML_ASSERT(ne % QK4_1 == 0);
|
||||
const int64_t num_blocks = ne / QK4_1;
|
||||
const int64_t num_blocks = (ne/QK4_1 + CUDA_CPY_BLOCK_SIZE - 1) / CUDA_CPY_BLOCK_SIZE;
|
||||
GGML_ASSERT(num_blocks <= INT_MAX);
|
||||
cpy_f32_q<cpy_blck_f32_q4_1, QK4_1><<<num_blocks, 1, 0, stream>>>
|
||||
cpy_f32_q<cpy_blck_f32_q4_1, QK4_1><<<num_blocks, CUDA_CPY_BLOCK_SIZE, 0, stream>>>
|
||||
(cx, cdst, ne, ne00, ne01, ne02, nb00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb13);
|
||||
}
|
||||
|
||||
@@ -315,9 +315,9 @@ static void ggml_cpy_q4_1_f32_cuda(
|
||||
const int64_t nb03, const int64_t ne10, const int64_t ne11, const int64_t ne12,
|
||||
const int64_t nb10, const int64_t nb11, const int64_t nb12, const int64_t nb13,
|
||||
cudaStream_t stream) {
|
||||
const int64_t num_blocks = ne;
|
||||
const int64_t num_blocks = (ne/QK4_1 + CUDA_CPY_BLOCK_SIZE - 1) / CUDA_CPY_BLOCK_SIZE;
|
||||
GGML_ASSERT(num_blocks <= INT_MAX);
|
||||
cpy_q_f32<cpy_blck_q_f32<dequantize_q4_1, QK4_1>, QK4_1><<<num_blocks, 1, 0, stream>>>(
|
||||
cpy_q_f32<cpy_blck_q_f32<dequantize_q4_1, QK4_1>, QK4_1><<<num_blocks, CUDA_CPY_BLOCK_SIZE, 0, stream>>>(
|
||||
cx, cdst, ne, ne00, ne01, ne02, nb00, nb01, nb02, nb03,
|
||||
ne10, ne11, ne12, nb10, nb11, nb12, nb13);
|
||||
}
|
||||
@@ -328,9 +328,9 @@ static void ggml_cpy_f32_q5_0_cuda(
|
||||
const int64_t nb03, const int64_t ne10, const int64_t ne11, const int64_t ne12, const int64_t nb10, const int64_t nb11, const int64_t nb12, const int64_t nb13, cudaStream_t stream) {
|
||||
|
||||
GGML_ASSERT(ne % QK5_0 == 0);
|
||||
const int64_t num_blocks = ne / QK5_0;
|
||||
const int64_t num_blocks = (ne/QK5_0 + CUDA_CPY_BLOCK_SIZE - 1) / CUDA_CPY_BLOCK_SIZE;
|
||||
GGML_ASSERT(num_blocks <= INT_MAX);
|
||||
cpy_f32_q<cpy_blck_f32_q5_0, QK5_0><<<num_blocks, 1, 0, stream>>>
|
||||
cpy_f32_q<cpy_blck_f32_q5_0, QK5_0><<<num_blocks, CUDA_CPY_BLOCK_SIZE, 0, stream>>>
|
||||
(cx, cdst, ne, ne00, ne01, ne02, nb00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb13);
|
||||
}
|
||||
|
||||
@@ -341,9 +341,9 @@ static void ggml_cpy_q5_0_f32_cuda(
|
||||
const int64_t nb03, const int64_t ne10, const int64_t ne11, const int64_t ne12,
|
||||
const int64_t nb10, const int64_t nb11, const int64_t nb12, const int64_t nb13,
|
||||
cudaStream_t stream) {
|
||||
const int64_t num_blocks = ne;
|
||||
const int64_t num_blocks = (ne/QK5_0 + CUDA_CPY_BLOCK_SIZE - 1) / CUDA_CPY_BLOCK_SIZE;
|
||||
GGML_ASSERT(num_blocks <= INT_MAX);
|
||||
cpy_q_f32<cpy_blck_q_f32<dequantize_q5_0, QK5_0>, QK5_0><<<num_blocks, 1, 0, stream>>>(
|
||||
cpy_q_f32<cpy_blck_q_f32<dequantize_q5_0, QK5_0>, QK5_0><<<num_blocks, CUDA_CPY_BLOCK_SIZE, 0, stream>>>(
|
||||
cx, cdst, ne, ne00, ne01, ne02, nb00, nb01, nb02, nb03,
|
||||
ne10, ne11, ne12, nb10, nb11, nb12, nb13);
|
||||
}
|
||||
@@ -354,9 +354,9 @@ static void ggml_cpy_f32_q5_1_cuda(
|
||||
const int64_t nb03, const int64_t ne10, const int64_t ne11, const int64_t ne12, const int64_t nb10, const int64_t nb11, const int64_t nb12, const int64_t nb13, cudaStream_t stream) {
|
||||
|
||||
GGML_ASSERT(ne % QK5_1 == 0);
|
||||
const int64_t num_blocks = ne / QK5_1;
|
||||
const int64_t num_blocks = (ne/QK5_1 + CUDA_CPY_BLOCK_SIZE - 1) / CUDA_CPY_BLOCK_SIZE;
|
||||
GGML_ASSERT(num_blocks <= INT_MAX);
|
||||
cpy_f32_q<cpy_blck_f32_q5_1, QK5_1><<<num_blocks, 1, 0, stream>>>
|
||||
cpy_f32_q<cpy_blck_f32_q5_1, QK5_1><<<num_blocks, CUDA_CPY_BLOCK_SIZE, 0, stream>>>
|
||||
(cx, cdst, ne, ne00, ne01, ne02, nb00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb13);
|
||||
}
|
||||
|
||||
@@ -367,9 +367,9 @@ static void ggml_cpy_q5_1_f32_cuda(
|
||||
const int64_t nb03, const int64_t ne10, const int64_t ne11, const int64_t ne12,
|
||||
const int64_t nb10, const int64_t nb11, const int64_t nb12, const int64_t nb13,
|
||||
cudaStream_t stream) {
|
||||
const int64_t num_blocks = ne;
|
||||
const int64_t num_blocks = (ne/QK5_1 + CUDA_CPY_BLOCK_SIZE - 1) / CUDA_CPY_BLOCK_SIZE;
|
||||
GGML_ASSERT(num_blocks <= INT_MAX);
|
||||
cpy_q_f32<cpy_blck_q_f32<dequantize_q5_1, QK5_1>, QK5_1><<<num_blocks, 1, 0, stream>>>(
|
||||
cpy_q_f32<cpy_blck_q_f32<dequantize_q5_1, QK5_1>, QK5_1><<<num_blocks, CUDA_CPY_BLOCK_SIZE, 0, stream>>>(
|
||||
cx, cdst, ne, ne00, ne01, ne02, nb00, nb01, nb02, nb03,
|
||||
ne10, ne11, ne12, nb10, nb11, nb12, nb13);
|
||||
}
|
||||
@@ -380,9 +380,9 @@ static void ggml_cpy_f32_iq4_nl_cuda(
|
||||
const int64_t nb03, const int64_t ne10, const int64_t ne11, const int64_t ne12, const int64_t nb10, const int64_t nb11, const int64_t nb12, const int64_t nb13, cudaStream_t stream) {
|
||||
|
||||
GGML_ASSERT(ne % QK4_NL == 0);
|
||||
const int64_t num_blocks = ne / QK4_NL;
|
||||
const int64_t num_blocks = (ne/QK4_NL + CUDA_CPY_BLOCK_SIZE - 1) / CUDA_CPY_BLOCK_SIZE;
|
||||
GGML_ASSERT(num_blocks <= INT_MAX);
|
||||
cpy_f32_q<cpy_blck_f32_iq4_nl, QK4_NL><<<num_blocks, 1, 0, stream>>>
|
||||
cpy_f32_q<cpy_blck_f32_iq4_nl, QK4_NL><<<num_blocks, CUDA_CPY_BLOCK_SIZE, 0, stream>>>
|
||||
(cx, cdst, ne, ne00, ne01, ne02, nb00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb13);
|
||||
}
|
||||
|
||||
|
||||
@@ -2651,6 +2651,52 @@ static bool ggml_cuda_should_fuse_rope_set_rows(const ggml_tensor * rope,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ggml_cuda_should_fuse_rms_norm_mul_rope(const ggml_tensor * rms_norm,
|
||||
const ggml_tensor * mul,
|
||||
const ggml_tensor * rope) {
|
||||
if (rms_norm->op != GGML_OP_RMS_NORM || mul->op != GGML_OP_MUL || rope->op != GGML_OP_ROPE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rms_norm->src[0]->type != GGML_TYPE_F32 || rms_norm->type != GGML_TYPE_F32 ||
|
||||
mul->src[0]->type != GGML_TYPE_F32 || mul->src[1]->type != GGML_TYPE_F32 ||
|
||||
mul->type != GGML_TYPE_F32 || rope->type != GGML_TYPE_F32) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rope->src[0] != mul) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//if rms norm is the B operand, then we don't handle broadcast
|
||||
if (rms_norm == mul->src[1] && !ggml_are_same_shape(mul->src[0], rms_norm)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ggml_are_same_shape(rms_norm, mul)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//rms_norm kernel assumes contiguous rows
|
||||
if (!ggml_is_contiguous_rows(rms_norm->src[0]) ||
|
||||
!ggml_is_contiguous_rows(mul->src[0]) || !ggml_is_contiguous_rows(mul->src[1])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// the fused kernel handles the norm/neox rope modes only
|
||||
const int mode = ((const int32_t *) rope->op_params)[2];
|
||||
if (mode != GGML_ROPE_TYPE_NORMAL && mode != GGML_ROPE_TYPE_NEOX) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const int n_dims = ((const int32_t *) rope->op_params)[1];
|
||||
if (n_dims % 2 != 0 || rope->src[0]->ne[0] % 2 != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// match gated_delta_net + the strided cpy that scatters its state snapshots into the cache
|
||||
// (slot i -> rollback group i, slot 0 newest), so the kernel can write them and skip the cpy.
|
||||
static int ggml_cuda_try_gdn_cache_fusion(
|
||||
@@ -2980,6 +3026,36 @@ static bool ggml_cuda_can_fuse(const struct ggml_cgraph * cgraph,
|
||||
}
|
||||
}
|
||||
|
||||
std::initializer_list<enum ggml_op> rms_norm_mul_rope_ops = { GGML_OP_RMS_NORM, GGML_OP_MUL, GGML_OP_ROPE };
|
||||
std::initializer_list<enum ggml_op> rms_norm_mul_rope_set_rows_ops = { GGML_OP_RMS_NORM, GGML_OP_MUL, GGML_OP_ROPE, GGML_OP_VIEW, GGML_OP_SET_ROWS };
|
||||
|
||||
if (is_equal(rms_norm_mul_rope_set_rows_ops, ops) && ggml_can_fuse_subgraph(cgraph, node_idx, ops, { node_idx + 4 })) {
|
||||
const ggml_tensor * rms_norm = cgraph->nodes[node_idx];
|
||||
const ggml_tensor * mul = cgraph->nodes[node_idx + 1];
|
||||
const ggml_tensor * rope = cgraph->nodes[node_idx + 2];
|
||||
const ggml_tensor * view = cgraph->nodes[node_idx + 3];
|
||||
const ggml_tensor * set_rows = cgraph->nodes[node_idx + 4];
|
||||
|
||||
if (ggml_check_edges(cgraph, node_idx, {{1, 0, 0}, {2, 0, 1}, {3, 0, 2}, {4, 0, 3}}) &&
|
||||
ggml_cuda_should_fuse_rms_norm_mul_rope(rms_norm, mul, rope) &&
|
||||
ggml_cuda_should_fuse_rope_set_rows(rope, view, set_rows)) {
|
||||
int out_nodes[] = { node_idx + 4 };
|
||||
return ggml_cuda_check_fusion_memory_ranges(cgraph, node_idx, (int)ops.size(), out_nodes, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_equal(rms_norm_mul_rope_ops, ops) && ggml_can_fuse(cgraph, node_idx, ops)) {
|
||||
const ggml_tensor * rms_norm = cgraph->nodes[node_idx];
|
||||
const ggml_tensor * mul = cgraph->nodes[node_idx + 1];
|
||||
const ggml_tensor * rope = cgraph->nodes[node_idx + 2];
|
||||
|
||||
if (ggml_cuda_should_fuse_rms_norm_mul_rope(rms_norm, mul, rope)) {
|
||||
int out_nodes[] = { node_idx + 2 };
|
||||
return ggml_cuda_check_fusion_memory_ranges(cgraph, node_idx, (int)ops.size(), out_nodes, 1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::initializer_list<enum ggml_op> rope_set_rows_ops = { GGML_OP_ROPE, GGML_OP_VIEW, GGML_OP_SET_ROWS };
|
||||
|
||||
if (is_equal(rope_set_rows_ops, ops) && ggml_can_fuse_subgraph(cgraph, node_idx, ops, { node_idx + 2 })) {
|
||||
@@ -2988,7 +3064,8 @@ static bool ggml_cuda_can_fuse(const struct ggml_cgraph * cgraph,
|
||||
const ggml_tensor * set_rows = cgraph->nodes[node_idx + 2];
|
||||
|
||||
if (ggml_cuda_should_fuse_rope_set_rows(rope, view, set_rows)) {
|
||||
return true;
|
||||
int out_nodes[] = { node_idx + 2 };
|
||||
return ggml_cuda_check_fusion_memory_ranges(cgraph, node_idx, (int)ops.size(), out_nodes, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3840,6 +3917,16 @@ static int ggml_cuda_try_fuse(ggml_backend_cuda_context * cuda_ctx, ggml_cgraph
|
||||
return fused_node_count - 1;
|
||||
}
|
||||
|
||||
if (ggml_cuda_can_fuse(cgraph, i, { GGML_OP_RMS_NORM, GGML_OP_MUL, GGML_OP_ROPE, GGML_OP_VIEW, GGML_OP_SET_ROWS }, {})) {
|
||||
ggml_cuda_op_rms_norm_mul_rope_fused(*cuda_ctx, node, cgraph->nodes[i + 1], cgraph->nodes[i + 2], cgraph->nodes[i + 4]);
|
||||
return 4;
|
||||
}
|
||||
|
||||
if (ggml_cuda_can_fuse(cgraph, i, { GGML_OP_RMS_NORM, GGML_OP_MUL, GGML_OP_ROPE }, {})) {
|
||||
ggml_cuda_op_rms_norm_mul_rope_fused(*cuda_ctx, node, cgraph->nodes[i + 1], cgraph->nodes[i + 2], nullptr);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (ggml_cuda_can_fuse(cgraph, i, { GGML_OP_RMS_NORM, GGML_OP_MUL, GGML_OP_ADD }, {})) {
|
||||
ggml_cuda_op_rms_norm_fused_add(*cuda_ctx, node, cgraph->nodes[i + 1], cgraph->nodes[i + 2]);
|
||||
return 2;
|
||||
@@ -4033,7 +4120,11 @@ static void ggml_cuda_graph_evaluate_and_capture(ggml_backend_cuda_context * cud
|
||||
continue;
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
assert(node->buffer->buft == ggml_backend_cuda_buffer_type(cuda_ctx->device));
|
||||
// On integrated GPUs (APUs, e.g. RDNA3.5) the scheduler may place a
|
||||
// node's output on the host-visible buffer, which the compute path
|
||||
// handles. Allow that here, mirroring the src-tensor check below.
|
||||
assert(node->buffer->buft == ggml_backend_cuda_buffer_type(cuda_ctx->device) ||
|
||||
(integrated && ggml_backend_buft_is_cuda_host(node->buffer->buft)));
|
||||
for (int j = 0; j < GGML_MAX_SRC; j++) {
|
||||
if (node->src[j] != nullptr) {
|
||||
assert(node->src[j]->buffer);
|
||||
@@ -5205,6 +5296,7 @@ static bool ggml_backend_cuda_device_offload_op(ggml_backend_dev_t dev, const gg
|
||||
|
||||
static ggml_backend_event_t ggml_backend_cuda_device_event_new(ggml_backend_dev_t dev) {
|
||||
#ifdef GGML_CUDA_NO_PEER_COPY
|
||||
GGML_UNUSED(dev);
|
||||
return nullptr;
|
||||
#else
|
||||
ggml_backend_cuda_device_context * dev_ctx = (ggml_backend_cuda_device_context *)dev->context;
|
||||
|
||||
@@ -8,7 +8,6 @@ struct __builtin_align__(32) float8 {
|
||||
float x; float y; float z; float w;
|
||||
float p; float q; float r; float s;
|
||||
};
|
||||
#endif
|
||||
|
||||
#if CUDART_VERSION >= 12080
|
||||
static __device__ __forceinline__ float nvfp4_native_scale_error(
|
||||
@@ -49,6 +48,7 @@ static __device__ __forceinline__ float nvfp4_native_scale_error(
|
||||
return err;
|
||||
}
|
||||
#endif // CUDART_VERSION >= 12080
|
||||
#endif // defined(BLACKWELL_MMA_AVAILABLE)
|
||||
|
||||
__launch_bounds__(CUDA_QUANTIZE_BLOCK_SIZE, 1)
|
||||
static __global__ void quantize_q8_1(
|
||||
|
||||
@@ -670,3 +670,238 @@ void ggml_cuda_op_rope_back(ggml_backend_cuda_context & ctx, ggml_tensor * dst)
|
||||
void ggml_cuda_op_rope_fused(ggml_backend_cuda_context & ctx, ggml_tensor * rope, ggml_tensor * set_rows) {
|
||||
ggml_cuda_op_rope_impl<true>(ctx, rope, set_rows);
|
||||
}
|
||||
|
||||
// fused RMS_NORM + MUL + ROPE (+ VIEW + SET_ROWS)
|
||||
// one block per row: block_reduce gives the norm scale, then each thread applies mul and rope to the elements it owns
|
||||
template <int block_size, bool has_ff, typename D>
|
||||
static __global__ void rms_norm_mul_rope_f32(
|
||||
const float * x, D * dst, const int ncols,
|
||||
const int64_t s01, const int64_t s02, const int64_t s03,
|
||||
const int64_t s1, const int64_t s2, const int64_t s3,
|
||||
const float eps,
|
||||
const float * mul,
|
||||
const int64_t mul_s01, const int64_t mul_s02, const int64_t mul_s03,
|
||||
const uint3 mul_ncols_packed, const uint3 mul_nrows_packed,
|
||||
const uint3 mul_nchannels_packed, const uint3 mul_nsamples_packed,
|
||||
const int n_dims, const int32_t * pos,
|
||||
const float freq_scale, const float ext_factor, const float attn_factor,
|
||||
const rope_corr_dims corr_dims, const float theta_scale,
|
||||
const float * freq_factors,
|
||||
const int64_t * row_indices, const int set_rows_stride,
|
||||
const bool is_neox) {
|
||||
ggml_cuda_pdl_lc();
|
||||
const int row = blockIdx.x;
|
||||
const int channel = blockIdx.y;
|
||||
const int sample = blockIdx.z;
|
||||
const int tid = threadIdx.x;
|
||||
|
||||
x += sample*s03 + channel*s02 + row*s01;
|
||||
|
||||
const uint32_t mul_row = fastmodulo(row, mul_nrows_packed);
|
||||
const uint32_t mul_channel = fastmodulo(channel, mul_nchannels_packed);
|
||||
const uint32_t mul_sample = fastmodulo(sample, mul_nsamples_packed);
|
||||
mul += mul_sample*mul_s03 + mul_channel*mul_s02 + mul_row*mul_s01;
|
||||
|
||||
float tmp = 0.0f;
|
||||
|
||||
ggml_cuda_pdl_sync();
|
||||
for (int col = tid; col < ncols; col += block_size) {
|
||||
const float xi = x[col];
|
||||
tmp += xi * xi;
|
||||
}
|
||||
|
||||
extern __shared__ float s_sum[];
|
||||
tmp = block_reduce<block_reduce_method::SUM, block_size>(tmp, s_sum);
|
||||
|
||||
const float scale = rsqrtf(tmp/ncols + eps);
|
||||
|
||||
int64_t idst = sample*s3 + channel*s2 + row*s1;
|
||||
if (set_rows_stride != 0) {
|
||||
idst = row*s1 + row_indices[channel]*set_rows_stride;
|
||||
}
|
||||
dst += idst;
|
||||
|
||||
for (int i0 = 2*tid; i0 < ncols; i0 += 2*block_size) {
|
||||
int ix0;
|
||||
int ix1;
|
||||
if (is_neox && i0 < n_dims) {
|
||||
ix0 = i0/2;
|
||||
ix1 = i0/2 + n_dims/2;
|
||||
} else {
|
||||
ix0 = i0 + 0;
|
||||
ix1 = i0 + 1;
|
||||
}
|
||||
|
||||
const float x0 = scale * x[ix0] * mul[fastmodulo(ix0, mul_ncols_packed)];
|
||||
const float x1 = scale * x[ix1] * mul[fastmodulo(ix1, mul_ncols_packed)];
|
||||
|
||||
if (i0 >= n_dims) {
|
||||
dst[ix0] = ggml_cuda_cast<D>(x0);
|
||||
dst[ix1] = ggml_cuda_cast<D>(x1);
|
||||
continue;
|
||||
}
|
||||
|
||||
const float theta_base = pos[channel]*powf(theta_scale, i0/2.0f);
|
||||
const float freq_factor = has_ff ? freq_factors[i0/2] : 1.0f;
|
||||
|
||||
float cos_theta;
|
||||
float sin_theta;
|
||||
rope_yarn<true>(theta_base/freq_factor, freq_scale, corr_dims, i0, ext_factor, attn_factor, cos_theta, sin_theta);
|
||||
|
||||
dst[ix0] = ggml_cuda_cast<D>(x0*cos_theta - x1*sin_theta);
|
||||
dst[ix1] = ggml_cuda_cast<D>(x0*sin_theta + x1*cos_theta);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename D>
|
||||
static void rms_norm_mul_rope_cuda(
|
||||
const float * x, D * dst,
|
||||
const int ncols, const int nrows, const int nchannels, const int nsamples,
|
||||
const int64_t s01, const int64_t s02, const int64_t s03,
|
||||
const int64_t s1, const int64_t s2, const int64_t s3,
|
||||
const float eps,
|
||||
const float * mul,
|
||||
const int64_t mul_s01, const int64_t mul_s02, const int64_t mul_s03,
|
||||
const uint32_t mul_ncols, const uint32_t mul_nrows,
|
||||
const uint32_t mul_nchannels, const uint32_t mul_nsamples,
|
||||
const int n_dims, const int32_t * pos,
|
||||
const float freq_scale, const float freq_base, const float ext_factor, const float attn_factor,
|
||||
const rope_corr_dims corr_dims,
|
||||
const float * freq_factors,
|
||||
const int64_t * row_indices, const int set_rows_stride,
|
||||
const bool is_neox, cudaStream_t stream) {
|
||||
GGML_ASSERT(ncols % 2 == 0);
|
||||
|
||||
const dim3 blocks_num(nrows, nchannels, nsamples);
|
||||
|
||||
const float theta_scale = powf(freq_base, -2.0f/n_dims);
|
||||
|
||||
const uint3 mul_ncols_packed = init_fastdiv_values(mul_ncols);
|
||||
const uint3 mul_nrows_packed = init_fastdiv_values(mul_nrows);
|
||||
const uint3 mul_nchannels_packed = init_fastdiv_values(mul_nchannels);
|
||||
const uint3 mul_nsamples_packed = init_fastdiv_values(mul_nsamples);
|
||||
|
||||
if (ncols < 1024) {
|
||||
const dim3 block_dims(256, 1, 1);
|
||||
const ggml_cuda_kernel_launch_params launch_params = {blocks_num, block_dims, 32*sizeof(float), stream};
|
||||
if (freq_factors == nullptr) {
|
||||
ggml_cuda_kernel_launch(rms_norm_mul_rope_f32<256, false, D>, launch_params,
|
||||
x, dst, ncols, s01, s02, s03, s1, s2, s3, eps, mul, mul_s01, mul_s02, mul_s03,
|
||||
mul_ncols_packed, mul_nrows_packed, mul_nchannels_packed, mul_nsamples_packed,
|
||||
n_dims, pos, freq_scale, ext_factor, attn_factor, corr_dims, theta_scale,
|
||||
freq_factors, row_indices, set_rows_stride, is_neox);
|
||||
} else {
|
||||
ggml_cuda_kernel_launch(rms_norm_mul_rope_f32<256, true, D>, launch_params,
|
||||
x, dst, ncols, s01, s02, s03, s1, s2, s3, eps, mul, mul_s01, mul_s02, mul_s03,
|
||||
mul_ncols_packed, mul_nrows_packed, mul_nchannels_packed, mul_nsamples_packed,
|
||||
n_dims, pos, freq_scale, ext_factor, attn_factor, corr_dims, theta_scale,
|
||||
freq_factors, row_indices, set_rows_stride, is_neox);
|
||||
}
|
||||
} else {
|
||||
const dim3 block_dims(1024, 1, 1);
|
||||
const ggml_cuda_kernel_launch_params launch_params = {blocks_num, block_dims, 32*sizeof(float), stream};
|
||||
if (freq_factors == nullptr) {
|
||||
ggml_cuda_kernel_launch(rms_norm_mul_rope_f32<1024, false, D>, launch_params,
|
||||
x, dst, ncols, s01, s02, s03, s1, s2, s3, eps, mul, mul_s01, mul_s02, mul_s03,
|
||||
mul_ncols_packed, mul_nrows_packed, mul_nchannels_packed, mul_nsamples_packed,
|
||||
n_dims, pos, freq_scale, ext_factor, attn_factor, corr_dims, theta_scale,
|
||||
freq_factors, row_indices, set_rows_stride, is_neox);
|
||||
} else {
|
||||
ggml_cuda_kernel_launch(rms_norm_mul_rope_f32<1024, true, D>, launch_params,
|
||||
x, dst, ncols, s01, s02, s03, s1, s2, s3, eps, mul, mul_s01, mul_s02, mul_s03,
|
||||
mul_ncols_packed, mul_nrows_packed, mul_nchannels_packed, mul_nsamples_packed,
|
||||
n_dims, pos, freq_scale, ext_factor, attn_factor, corr_dims, theta_scale,
|
||||
freq_factors, row_indices, set_rows_stride, is_neox);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ggml_cuda_op_rms_norm_mul_rope_fused(ggml_backend_cuda_context & ctx,
|
||||
ggml_tensor * rms_norm, ggml_tensor * mul, ggml_tensor * rope, ggml_tensor * set_rows) {
|
||||
const ggml_tensor * x = rms_norm->src[0];
|
||||
const ggml_tensor * mul_src = mul->src[0] == rms_norm ? mul->src[1] : mul->src[0];
|
||||
|
||||
float eps = 0.0f;
|
||||
memcpy(&eps, rms_norm->op_params, sizeof(float));
|
||||
GGML_ASSERT(eps >= 0.0f);
|
||||
|
||||
GGML_ASSERT(x->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(mul_src->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(rope->type == GGML_TYPE_F32);
|
||||
|
||||
void * dst_d = rope->data;
|
||||
ggml_type dst_type = rope->type;
|
||||
const int64_t * row_indices = nullptr;
|
||||
int set_rows_stride = 0;
|
||||
|
||||
if (set_rows != nullptr) {
|
||||
dst_d = set_rows->data;
|
||||
dst_type = set_rows->type;
|
||||
row_indices = (const int64_t *) set_rows->src[1]->data;
|
||||
set_rows_stride = set_rows->nb[1] / ggml_type_size(set_rows->type);
|
||||
}
|
||||
|
||||
const int n_dims = ((const int32_t *) rope->op_params)[1];
|
||||
const int mode = ((const int32_t *) rope->op_params)[2];
|
||||
const int n_ctx_orig = ((const int32_t *) rope->op_params)[4];
|
||||
|
||||
float freq_base;
|
||||
float freq_scale;
|
||||
float ext_factor;
|
||||
float attn_factor;
|
||||
float beta_fast;
|
||||
float beta_slow;
|
||||
|
||||
memcpy(&freq_base, (const int32_t *) rope->op_params + 5, sizeof(float));
|
||||
memcpy(&freq_scale, (const int32_t *) rope->op_params + 6, sizeof(float));
|
||||
memcpy(&ext_factor, (const int32_t *) rope->op_params + 7, sizeof(float));
|
||||
memcpy(&attn_factor, (const int32_t *) rope->op_params + 8, sizeof(float));
|
||||
memcpy(&beta_fast, (const int32_t *) rope->op_params + 9, sizeof(float));
|
||||
memcpy(&beta_slow, (const int32_t *) rope->op_params + 10, sizeof(float));
|
||||
|
||||
const bool is_neox = mode & GGML_ROPE_TYPE_NEOX;
|
||||
|
||||
const int32_t * pos = (const int32_t *) rope->src[1]->data;
|
||||
|
||||
const float * freq_factors = rope->src[2] != nullptr ? (const float *) rope->src[2]->data : nullptr;
|
||||
|
||||
rope_corr_dims corr_dims;
|
||||
ggml_rope_yarn_corr_dims(n_dims, n_ctx_orig, freq_base, beta_fast, beta_slow, corr_dims.v);
|
||||
|
||||
const size_t ts0 = ggml_type_size(x->type);
|
||||
GGML_ASSERT(x->nb[0] == ts0);
|
||||
const int64_t s01 = x->nb[1] / ts0;
|
||||
const int64_t s02 = x->nb[2] / ts0;
|
||||
const int64_t s03 = x->nb[3] / ts0;
|
||||
|
||||
const size_t ts_mul = ggml_type_size(mul_src->type);
|
||||
GGML_ASSERT(mul_src->nb[0] == ts_mul);
|
||||
const int64_t mul_s01 = mul_src->nb[1] / ts_mul;
|
||||
const int64_t mul_s02 = mul_src->nb[2] / ts_mul;
|
||||
const int64_t mul_s03 = mul_src->nb[3] / ts_mul;
|
||||
|
||||
const size_t ts_dst = ggml_type_size(rope->type);
|
||||
const int64_t s1 = rope->nb[1] / ts_dst;
|
||||
const int64_t s2 = rope->nb[2] / ts_dst;
|
||||
const int64_t s3 = rope->nb[3] / ts_dst;
|
||||
|
||||
cudaStream_t stream = ctx.stream();
|
||||
|
||||
if (dst_type == GGML_TYPE_F32) {
|
||||
rms_norm_mul_rope_cuda((const float *) x->data, (float *) dst_d,
|
||||
x->ne[0], x->ne[1], x->ne[2], x->ne[3], s01, s02, s03, s1, s2, s3, eps,
|
||||
(const float *) mul_src->data, mul_s01, mul_s02, mul_s03,
|
||||
mul_src->ne[0], mul_src->ne[1], mul_src->ne[2], mul_src->ne[3],
|
||||
n_dims, pos, freq_scale, freq_base, ext_factor, attn_factor, corr_dims,
|
||||
freq_factors, row_indices, set_rows_stride, is_neox, stream);
|
||||
} else if (dst_type == GGML_TYPE_F16) {
|
||||
rms_norm_mul_rope_cuda((const float *) x->data, (half *) dst_d,
|
||||
x->ne[0], x->ne[1], x->ne[2], x->ne[3], s01, s02, s03, s1, s2, s3, eps,
|
||||
(const float *) mul_src->data, mul_s01, mul_s02, mul_s03,
|
||||
mul_src->ne[0], mul_src->ne[1], mul_src->ne[2], mul_src->ne[3],
|
||||
n_dims, pos, freq_scale, freq_base, ext_factor, attn_factor, corr_dims,
|
||||
freq_factors, row_indices, set_rows_stride, is_neox, stream);
|
||||
} else {
|
||||
GGML_ABORT("fatal error");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,3 +7,5 @@ void ggml_cuda_op_rope(ggml_backend_cuda_context & ctx, ggml_tensor * dst);
|
||||
void ggml_cuda_op_rope_back(ggml_backend_cuda_context & ctx, ggml_tensor * dst);
|
||||
|
||||
void ggml_cuda_op_rope_fused(ggml_backend_cuda_context & ctx, ggml_tensor * dst, ggml_tensor * set_rows);
|
||||
|
||||
void ggml_cuda_op_rms_norm_mul_rope_fused(ggml_backend_cuda_context & ctx, ggml_tensor * rms_norm, ggml_tensor * mul, ggml_tensor * rope, ggml_tensor * set_rows);
|
||||
|
||||
@@ -3816,7 +3816,7 @@ int ggml_metal_op_norm(ggml_metal_op_t ctx, int idx) {
|
||||
}
|
||||
|
||||
nth = std::min(nth, ggml_metal_pipeline_max_theads_per_threadgroup(pipeline));
|
||||
nth = std::min(nth, args.ne00_t);
|
||||
nth = std::min(nth, (args.ne00_t + 31)/32*32);
|
||||
|
||||
const size_t smem = pipeline.smem;
|
||||
|
||||
|
||||
@@ -11328,8 +11328,8 @@ kernel void kernel_lightning_indexer(
|
||||
const int i_kv_0 = tgpig.x*NK; // first key of this threadgroup
|
||||
const int i_kv = i_kv_0 + sgitg*NKPSG; // first key of this simdgroup
|
||||
|
||||
threadgroup half4x4 sk4x4[NK*DK16];
|
||||
threadgroup half * sk = (threadgroup half *) sk4x4;
|
||||
threadgroup half sk[NK * DK16 * 16];
|
||||
threadgroup half4x4 * sk4x4 = (threadgroup half4x4 *) sk;
|
||||
|
||||
for (short i = tiitg; i < NK*DK16; i += NTG) {
|
||||
const short ik = i/DK16;
|
||||
|
||||
@@ -1022,9 +1022,20 @@ static T block_reduce(T val, T * shared_vals, int block_size_template) {
|
||||
}
|
||||
|
||||
static __dpct_inline__ float ggml_sycl_ue4m3_to_fp32(uint8_t x) {
|
||||
const uint32_t bits = x * (x != 0x7F && x != 0xFF);
|
||||
const __nv_fp8_e4m3 xf = *reinterpret_cast<const __nv_fp8_e4m3 *>(&bits);
|
||||
return static_cast<float>(xf) / 2;
|
||||
// UE4M3 is unsigned: 4 exp bits (bias 7), 3 mantissa bits, no sign, no NaN.
|
||||
// exp == 0xF is a valid exponent (256-448 range), not NaN.
|
||||
if (x == 0 || x == 0x7F) {
|
||||
return 0.0f;
|
||||
}
|
||||
const int exp = (x >> 3) & 0xF;
|
||||
const int man = x & 0x7;
|
||||
float raw;
|
||||
if (exp == 0) {
|
||||
raw = man * (1.0f / 8.0f) * sycl::pow(2.0f, -6.0f);
|
||||
} else {
|
||||
raw = (1.0f + man / 8.0f) * sycl::pow(2.0f, (float) exp - 7.0f);
|
||||
}
|
||||
return raw * 0.5f;
|
||||
}
|
||||
|
||||
#endif // GGML_SYCL_COMMON_HPP
|
||||
|
||||
@@ -0,0 +1,280 @@
|
||||
#include "ggml-impl.h"
|
||||
#include "dsv4-hc.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
static constexpr int DSV4_HC = 4;
|
||||
|
||||
static void dsv4_hc_pre_f32_sycl(
|
||||
const float * x, const float * weights, float * dst,
|
||||
int64_t n_embd, int64_t hc, int64_t n_tokens,
|
||||
int64_t sx0, int64_t sx1, int64_t sx2,
|
||||
int64_t sw0, int64_t sw1,
|
||||
int64_t sd0, int64_t sd1,
|
||||
queue_ptr stream) {
|
||||
const int64_t nr = n_embd * n_tokens;
|
||||
const int64_t block_size = 256;
|
||||
const int64_t num_blocks = (nr + block_size - 1) / block_size;
|
||||
|
||||
stream->parallel_for(
|
||||
sycl::nd_range<1>(sycl::range<1>(num_blocks * block_size), sycl::range<1>(block_size)),
|
||||
[=](sycl::nd_item<1> item) {
|
||||
const int64_t ir = item.get_global_id(0);
|
||||
if (ir >= nr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int64_t i0 = ir % n_embd;
|
||||
const int64_t it = ir / n_embd;
|
||||
|
||||
float sum = x[i0*sx0 + it*sx2] * weights[it*sw1];
|
||||
for (int64_t ih = 1; ih < hc; ++ih) {
|
||||
const float xv = x[i0*sx0 + ih*sx1 + it*sx2];
|
||||
const float wv = weights[ih*sw0 + it*sw1];
|
||||
sum += xv * wv;
|
||||
}
|
||||
|
||||
dst[i0*sd0 + it*sd1] = sum;
|
||||
});
|
||||
}
|
||||
|
||||
static void dsv4_hc_comb_norm_cols(float * comb, float eps) {
|
||||
for (int idst = 0; idst < DSV4_HC; ++idst) {
|
||||
float sum = eps;
|
||||
for (int isrc = 0; isrc < DSV4_HC; ++isrc) {
|
||||
sum += comb[idst + DSV4_HC*isrc];
|
||||
}
|
||||
|
||||
const float inv_sum = 1.0f / sum;
|
||||
for (int isrc = 0; isrc < DSV4_HC; ++isrc) {
|
||||
comb[idst + DSV4_HC*isrc] *= inv_sum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void dsv4_hc_comb_norm_rows(float * comb, float eps) {
|
||||
for (int isrc = 0; isrc < DSV4_HC; ++isrc) {
|
||||
float sum = eps;
|
||||
for (int idst = 0; idst < DSV4_HC; ++idst) {
|
||||
sum += comb[idst + DSV4_HC*isrc];
|
||||
}
|
||||
|
||||
const float inv_sum = 1.0f / sum;
|
||||
for (int idst = 0; idst < DSV4_HC; ++idst) {
|
||||
comb[idst + DSV4_HC*isrc] *= inv_sum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void dsv4_hc_comb_f32_sycl(
|
||||
const float * mixes,
|
||||
const float * scale,
|
||||
const float * base,
|
||||
float * dst,
|
||||
int64_t n_tokens,
|
||||
int64_t sm0,
|
||||
int64_t sm1,
|
||||
int64_t ss0,
|
||||
int64_t sb0,
|
||||
int64_t sd0,
|
||||
int64_t sd1,
|
||||
int64_t sd2,
|
||||
float eps,
|
||||
int32_t n_iter,
|
||||
queue_ptr stream) {
|
||||
constexpr int comb_offset = 2*DSV4_HC;
|
||||
|
||||
const int64_t block_size = 256;
|
||||
const int64_t num_blocks = (n_tokens + block_size - 1) / block_size;
|
||||
|
||||
stream->parallel_for(
|
||||
sycl::nd_range<1>(sycl::range<1>(num_blocks * block_size), sycl::range<1>(block_size)),
|
||||
[=](sycl::nd_item<1> item_ct1) {
|
||||
const int64_t it = item_ct1.get_global_id(0);
|
||||
|
||||
if (it >= n_tokens) {
|
||||
return;
|
||||
}
|
||||
|
||||
const float scale_comb = scale[2*ss0];
|
||||
float comb[DSV4_HC*DSV4_HC];
|
||||
|
||||
for (int isrc = 0; isrc < DSV4_HC; ++isrc) {
|
||||
float max = -INFINITY;
|
||||
for (int idst = 0; idst < DSV4_HC; ++idst) {
|
||||
const int idx = idst + DSV4_HC*isrc;
|
||||
const float v = mixes[(comb_offset + idx)*sm0 + it*sm1] * scale_comb + base[(comb_offset + idx)*sb0];
|
||||
comb[idx] = v;
|
||||
max = fmaxf(max, v);
|
||||
}
|
||||
|
||||
float sum = 0.0f;
|
||||
for (int idst = 0; idst < DSV4_HC; ++idst) {
|
||||
const int idx = idst + DSV4_HC*isrc;
|
||||
const float v = expf(comb[idx] - max);
|
||||
comb[idx] = v;
|
||||
sum += v;
|
||||
}
|
||||
|
||||
const float inv_sum = 1.0f / sum;
|
||||
for (int idst = 0; idst < DSV4_HC; ++idst) {
|
||||
const int idx = idst + DSV4_HC*isrc;
|
||||
comb[idx] = comb[idx] * inv_sum + eps;
|
||||
}
|
||||
}
|
||||
|
||||
dsv4_hc_comb_norm_cols(comb, eps);
|
||||
for (int32_t i = 1; i < n_iter; ++i) {
|
||||
dsv4_hc_comb_norm_rows(comb, eps);
|
||||
dsv4_hc_comb_norm_cols(comb, eps);
|
||||
}
|
||||
|
||||
for (int isrc = 0; isrc < DSV4_HC; ++isrc) {
|
||||
for (int idst = 0; idst < DSV4_HC; ++idst) {
|
||||
const int idx = idst + DSV4_HC*isrc;
|
||||
dst[idst*sd0 + isrc*sd1 + it*sd2] = comb[idx];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void dsv4_hc_post_f32_sycl(
|
||||
const float * x, const float * residual, const float * post, const float * comb, float * dst,
|
||||
int64_t n_embd, int64_t hc, int64_t n_tokens,
|
||||
int64_t sx0, int64_t sx1,
|
||||
int64_t sr0, int64_t sr1, int64_t sr2,
|
||||
int64_t sp0, int64_t sp1,
|
||||
int64_t sc0, int64_t sc1, int64_t sc2,
|
||||
int64_t sd0, int64_t sd1, int64_t sd2,
|
||||
queue_ptr stream) {
|
||||
const int64_t nr = n_embd * hc * n_tokens;
|
||||
const int64_t block_size = 256;
|
||||
const int64_t num_blocks = (nr + block_size - 1) / block_size;
|
||||
|
||||
stream->parallel_for(
|
||||
sycl::nd_range<1>(sycl::range<1>(num_blocks * block_size), sycl::range<1>(block_size)),
|
||||
[=](sycl::nd_item<1> item) {
|
||||
const int64_t ir = item.get_global_id(0);
|
||||
if (ir >= nr) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int64_t i0 = ir % n_embd;
|
||||
const int64_t idst = (ir / n_embd) % hc;
|
||||
const int64_t it = ir / (n_embd * hc);
|
||||
|
||||
float sum = x[i0*sx0 + it*sx1] * post[idst*sp0 + it*sp1];
|
||||
for (int64_t isrc = 0; isrc < hc; ++isrc) {
|
||||
sum += residual[i0*sr0 + isrc*sr1 + it*sr2] * comb[idst*sc0 + isrc*sc1 + it*sc2];
|
||||
}
|
||||
|
||||
dst[i0*sd0 + idst*sd1 + it*sd2] = sum;
|
||||
});
|
||||
}
|
||||
|
||||
void ggml_sycl_op_dsv4_hc_pre(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
|
||||
scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/2);
|
||||
const ggml_tensor * x = dst->src[0];
|
||||
const ggml_tensor * weights = dst->src[1];
|
||||
|
||||
GGML_ASSERT(x->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(weights->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(dst->type == GGML_TYPE_F32);
|
||||
|
||||
GGML_TENSOR_LOCALS(size_t, nbx, x, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbw, weights, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbd, dst, nb);
|
||||
|
||||
const int64_t n_embd = x->ne[0];
|
||||
const int64_t hc = x->ne[1];
|
||||
const int64_t n_tokens = x->ne[2];
|
||||
|
||||
queue_ptr stream = ctx.stream();
|
||||
|
||||
dsv4_hc_pre_f32_sycl(
|
||||
(const float *) x->data, (const float *) weights->data, (float *) dst->data,
|
||||
n_embd, hc, n_tokens,
|
||||
nbx0 / sizeof(float), nbx1 / sizeof(float), nbx2 / sizeof(float),
|
||||
nbw0 / sizeof(float), nbw1 / sizeof(float),
|
||||
nbd0 / sizeof(float), nbd1 / sizeof(float),
|
||||
stream);
|
||||
}
|
||||
|
||||
void ggml_sycl_op_dsv4_hc_comb(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
|
||||
scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/3);
|
||||
|
||||
const ggml_tensor * mixes = dst->src[0];
|
||||
const ggml_tensor * scale = dst->src[1];
|
||||
const ggml_tensor * base = dst->src[2];
|
||||
|
||||
GGML_ASSERT(mixes->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(scale->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(base->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(dst->type == GGML_TYPE_F32);
|
||||
|
||||
constexpr int64_t hc_mix_dim = (2 + DSV4_HC)*DSV4_HC;
|
||||
|
||||
GGML_ASSERT(mixes->ne[0] == hc_mix_dim);
|
||||
GGML_ASSERT(dst->ne[0] == DSV4_HC);
|
||||
GGML_ASSERT(dst->ne[1] == DSV4_HC);
|
||||
GGML_ASSERT(dst->ne[2] == mixes->ne[1]);
|
||||
GGML_ASSERT(scale->ne[0] >= 3);
|
||||
GGML_ASSERT(base->ne[0] == hc_mix_dim);
|
||||
|
||||
GGML_TENSOR_LOCALS(size_t, nbm, mixes, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbs, scale, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbb, base, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbd, dst, nb);
|
||||
|
||||
const int64_t n_tokens = mixes->ne[1];
|
||||
const float eps = ggml_get_op_params_f32(dst, 0);
|
||||
const int32_t n_iter = ggml_get_op_params_i32(dst, 1);
|
||||
|
||||
queue_ptr stream = ctx.stream();
|
||||
|
||||
dsv4_hc_comb_f32_sycl(
|
||||
(const float *) mixes->data, (const float *) scale->data, (const float *) base->data, (float *) dst->data,
|
||||
n_tokens,
|
||||
nbm0 / sizeof(float), nbm1 / sizeof(float),
|
||||
nbs0 / sizeof(float),
|
||||
nbb0 / sizeof(float),
|
||||
nbd0 / sizeof(float), nbd1 / sizeof(float), nbd2 / sizeof(float),
|
||||
eps, n_iter, stream);
|
||||
}
|
||||
|
||||
void ggml_sycl_op_dsv4_hc_post(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
|
||||
scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/4);
|
||||
const ggml_tensor * x = dst->src[0];
|
||||
const ggml_tensor * residual = dst->src[1];
|
||||
const ggml_tensor * post = dst->src[2];
|
||||
const ggml_tensor * comb = dst->src[3];
|
||||
|
||||
GGML_ASSERT(x->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(residual->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(post->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(comb->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(dst->type == GGML_TYPE_F32);
|
||||
|
||||
GGML_TENSOR_LOCALS(size_t, nbx, x, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbr, residual, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbp, post, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbc, comb, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbd, dst, nb);
|
||||
|
||||
const int64_t n_embd = x->ne[0];
|
||||
const int64_t n_tokens = x->ne[1];
|
||||
const int64_t hc = residual->ne[1];
|
||||
|
||||
queue_ptr stream = ctx.stream();
|
||||
|
||||
dsv4_hc_post_f32_sycl(
|
||||
(const float *) x->data, (const float *) residual->data,
|
||||
(const float *) post->data, (const float *) comb->data, (float *) dst->data,
|
||||
n_embd, hc, n_tokens,
|
||||
nbx0 / sizeof(float), nbx1 / sizeof(float),
|
||||
nbr0 / sizeof(float), nbr1 / sizeof(float), nbr2 / sizeof(float),
|
||||
nbp0 / sizeof(float), nbp1 / sizeof(float),
|
||||
nbc0 / sizeof(float), nbc1 / sizeof(float), nbc2 / sizeof(float),
|
||||
nbd0 / sizeof(float), nbd1 / sizeof(float), nbd2 / sizeof(float),
|
||||
stream);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef GGML_SYCL_DSV4_HC_HPP
|
||||
#define GGML_SYCL_DSV4_HC_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
void ggml_sycl_op_dsv4_hc_pre(ggml_backend_sycl_context & ctx, ggml_tensor * dst);
|
||||
void ggml_sycl_op_dsv4_hc_comb(ggml_backend_sycl_context & ctx, ggml_tensor * dst);
|
||||
void ggml_sycl_op_dsv4_hc_post(ggml_backend_sycl_context & ctx, ggml_tensor * dst);
|
||||
|
||||
#endif // GGML_SYCL_DSV4_HC_HPP
|
||||
@@ -420,53 +420,31 @@ static void clamp(const T * x, T * dst, const float min, const float max, const
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void gated_op_fused_geglu(const T * x, const T * g, T * dst, const uint64_t k, const sycl::uint3 n_fd, const uint64_t o0, const uint64_t o1, const sycl::nd_item<1> &item_ct1) {
|
||||
template<typename T, typename F>
|
||||
static void unary_gated_op_flat_kernel(const T * x, const T * g, T * dst, const uint64_t k, const sycl::nd_item<1> & item_ct1, F func) {
|
||||
SYCL_GLOBAL_ID_LOOP(k, item_ct1) {
|
||||
dst[i] = func(x[i]) * g[i];
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename F>
|
||||
static void unary_gated_op_generic_kernel(
|
||||
const T * x,
|
||||
const T * g,
|
||||
T * dst,
|
||||
const uint64_t k,
|
||||
const sycl::uint3 n_fd,
|
||||
const uint64_t o0,
|
||||
const uint64_t o1,
|
||||
const sycl::nd_item<1> & item_ct1,
|
||||
F func) {
|
||||
|
||||
// rows of n columns at strides o0 and o1: two halves of one fused tensor, or two tensors
|
||||
SYCL_GLOBAL_ID_LOOP(k, item_ct1) {
|
||||
const sycl::uint2 rc = fast_div_modulo((uint32_t) i, n_fd);
|
||||
const int64_t j0 = rc.x() * o0 + rc.y();
|
||||
const int64_t j1 = o0 == o1 ? j0 : rc.x() * o1 + rc.y();
|
||||
dst[i] = op_gelu(x[j0]) * g[j1];
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void gated_op_fused_reglu(const T * x, const T * g, T * dst, const uint64_t k, const sycl::uint3 n_fd, const uint64_t o0, const uint64_t o1, const sycl::nd_item<1> &item_ct1) {
|
||||
SYCL_GLOBAL_ID_LOOP(k, item_ct1) {
|
||||
const sycl::uint2 rc = fast_div_modulo((uint32_t) i, n_fd);
|
||||
const int64_t j0 = rc.x() * o0 + rc.y();
|
||||
const int64_t j1 = o0 == o1 ? j0 : rc.x() * o1 + rc.y();
|
||||
dst[i] = op_relu(x[j0]) * g[j1];
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void gated_op_fused_swiglu(const T * x, const T * g, T * dst, const uint64_t k, const sycl::uint3 n_fd, const uint64_t o0, const uint64_t o1, const sycl::nd_item<1> &item_ct1) {
|
||||
SYCL_GLOBAL_ID_LOOP(k, item_ct1) {
|
||||
const sycl::uint2 rc = fast_div_modulo((uint32_t) i, n_fd);
|
||||
const int64_t j0 = rc.x() * o0 + rc.y();
|
||||
const int64_t j1 = o0 == o1 ? j0 : rc.x() * o1 + rc.y();
|
||||
dst[i] = op_silu(x[j0]) * g[j1];
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void gated_op_fused_geglu_erf(const T * x, const T * g, T * dst, const uint64_t k, const sycl::uint3 n_fd, const uint64_t o0, const uint64_t o1, const sycl::nd_item<1> &item_ct1) {
|
||||
SYCL_GLOBAL_ID_LOOP(k, item_ct1) {
|
||||
const sycl::uint2 rc = fast_div_modulo((uint32_t) i, n_fd);
|
||||
const int64_t j0 = rc.x() * o0 + rc.y();
|
||||
const int64_t j1 = o0 == o1 ? j0 : rc.x() * o1 + rc.y();
|
||||
dst[i] = op_gelu_erf(x[j0]) * g[j1];
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void gated_op_fused_geglu_quick(const T * x, const T * g, T * dst, const uint64_t k, const sycl::uint3 n_fd, const uint64_t o0, const uint64_t o1, const sycl::nd_item<1> &item_ct1) {
|
||||
SYCL_GLOBAL_ID_LOOP(k, item_ct1) {
|
||||
const sycl::uint2 rc = fast_div_modulo((uint32_t) i, n_fd);
|
||||
const int64_t j0 = rc.x() * o0 + rc.y();
|
||||
const int64_t j1 = o0 == o1 ? j0 : rc.x() * o1 + rc.y();
|
||||
dst[i] = op_gelu_quick(x[j0]) * g[j1];
|
||||
dst[i] = func(x[j0]) * g[j1];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -670,6 +648,35 @@ static inline void ggml_sycl_op_unary(
|
||||
});
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
static inline void ggml_sycl_op_unary_gated(
|
||||
ggml_backend_sycl_context & ctx, ggml_tensor * dst, F func) {
|
||||
|
||||
dispatch_ggml_sycl_op_fused_glu(ctx, dst,
|
||||
[func](const auto * x_ptr, const auto * g_ptr, auto * dst_ptr, uint64_t k, uint64_t n, uint64_t o0, uint64_t o1, queue_ptr main_stream) {
|
||||
|
||||
const uint32_t num_blocks = (uint32_t) ceil_div(k, SYCL_GLU_BLOCK_SIZE);
|
||||
const sycl::nd_range<1> launch_range(num_blocks * sycl::range<1>(SYCL_GLU_BLOCK_SIZE),
|
||||
sycl::range<1>(SYCL_GLU_BLOCK_SIZE));
|
||||
|
||||
// o0 == n and o1 == n make the index math the identity, so index flat
|
||||
// note: not ggml_is_contiguous - a fused [gate|up] src0 is contiguous with o0 == 2n
|
||||
if (o0 == n && o1 == n) {
|
||||
main_stream->parallel_for(launch_range,
|
||||
[=](sycl::nd_item<1> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
|
||||
unary_gated_op_flat_kernel(x_ptr, g_ptr, dst_ptr, k, item_ct1, func);
|
||||
});
|
||||
} else {
|
||||
// launch-invariant divisor, and only this path needs it
|
||||
const sycl::uint3 n_fd = init_fastdiv_values((uint32_t) n);
|
||||
main_stream->parallel_for(launch_range,
|
||||
[=](sycl::nd_item<1> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
|
||||
unary_gated_op_generic_kernel(x_ptr, g_ptr, dst_ptr, k, n_fd, o0, o1, item_ct1, func);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
static inline void ggml_sycl_op_arange(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
|
||||
GGML_ASSERT(dst->type == GGML_TYPE_F32);
|
||||
@@ -967,42 +974,21 @@ static inline void ggml_sycl_op_acc(ggml_backend_sycl_context & ctx, ggml_tensor
|
||||
}
|
||||
|
||||
static inline void ggml_sycl_op_geglu(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
|
||||
ggml_sycl_detail::dispatch_ggml_sycl_op_fused_glu(ctx, dst,
|
||||
[](const auto* x_ptr, const auto* g_ptr, auto* dst_ptr, uint64_t k, uint64_t n, uint64_t o0, uint64_t o1, queue_ptr main_stream) {
|
||||
const uint32_t num_blocks = ceil_div(k, SYCL_GELU_BLOCK_SIZE);
|
||||
const sycl::uint3 n_fd = init_fastdiv_values((uint32_t) n);
|
||||
main_stream->parallel_for(
|
||||
sycl::nd_range<1>((num_blocks * sycl::range<1>(SYCL_GELU_BLOCK_SIZE)),
|
||||
sycl::range<1>(SYCL_GELU_BLOCK_SIZE)), [=](sycl::nd_item<1> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
|
||||
gated_op_fused_geglu(x_ptr, g_ptr, dst_ptr, k, n_fd, o0, o1, item_ct1);
|
||||
});
|
||||
});
|
||||
ggml_sycl_detail::ggml_sycl_op_unary_gated(ctx, dst, [](auto x) {
|
||||
return op_gelu(x);
|
||||
});
|
||||
}
|
||||
|
||||
static inline void ggml_sycl_op_reglu(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
|
||||
ggml_sycl_detail::dispatch_ggml_sycl_op_fused_glu(ctx, dst,
|
||||
[](const auto* x_ptr, const auto* g_ptr, auto* dst_ptr, uint64_t k, uint64_t n, uint64_t o0, uint64_t o1, queue_ptr main_stream) {
|
||||
const uint32_t num_blocks = ceil_div((uint32_t)k, SYCL_RELU_BLOCK_SIZE); // Using RELU block size for reglu
|
||||
const sycl::uint3 n_fd = init_fastdiv_values((uint32_t) n);
|
||||
main_stream->parallel_for(
|
||||
sycl::nd_range<1>((num_blocks * sycl::range<1>(SYCL_RELU_BLOCK_SIZE)),
|
||||
sycl::range<1>(SYCL_RELU_BLOCK_SIZE)), [=](sycl::nd_item<1> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
|
||||
gated_op_fused_reglu(x_ptr, g_ptr, dst_ptr, k, n_fd, o0, o1, item_ct1);
|
||||
});
|
||||
});
|
||||
ggml_sycl_detail::ggml_sycl_op_unary_gated(ctx, dst, [](auto x) {
|
||||
return op_relu(x);
|
||||
});
|
||||
}
|
||||
|
||||
static inline void ggml_sycl_op_swiglu(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
|
||||
ggml_sycl_detail::dispatch_ggml_sycl_op_fused_glu(ctx, dst,
|
||||
[](const auto* x_ptr, const auto* g_ptr, auto* dst_ptr, uint64_t k, uint64_t n, uint64_t o0, uint64_t o1, queue_ptr main_stream) {
|
||||
const uint32_t num_blocks = ceil_div((uint32_t)k, SYCL_SILU_BLOCK_SIZE); // Using SILU block size for swiglu
|
||||
const sycl::uint3 n_fd = init_fastdiv_values((uint32_t) n);
|
||||
main_stream->parallel_for(
|
||||
sycl::nd_range<1>((num_blocks * sycl::range<1>(SYCL_SILU_BLOCK_SIZE)),
|
||||
sycl::range<1>(SYCL_SILU_BLOCK_SIZE)), [=](sycl::nd_item<1> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
|
||||
gated_op_fused_swiglu(x_ptr, g_ptr, dst_ptr, k, n_fd, o0, o1, item_ct1);
|
||||
});
|
||||
});
|
||||
ggml_sycl_detail::ggml_sycl_op_unary_gated(ctx, dst, [](auto x) {
|
||||
return op_silu(x);
|
||||
});
|
||||
}
|
||||
|
||||
__dpct_inline__ float ggml_sycl_op_swiglu_oai_single(float x, float g, float alpha = 1.702f, float limit = 7.0f) {
|
||||
@@ -1097,29 +1083,15 @@ void ggml_sycl_op_swiglu_oai(ggml_backend_sycl_context & ctx, ggml_tensor * dst)
|
||||
}
|
||||
|
||||
static inline void ggml_sycl_op_geglu_erf(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
|
||||
ggml_sycl_detail::dispatch_ggml_sycl_op_fused_glu(ctx, dst,
|
||||
[](const auto* x_ptr, const auto* g_ptr, auto* dst_ptr, uint64_t k, uint64_t n, uint64_t o0, uint64_t o1, queue_ptr main_stream) {
|
||||
const uint32_t num_blocks = ceil_div(k, SYCL_GELU_BLOCK_SIZE);
|
||||
const sycl::uint3 n_fd = init_fastdiv_values((uint32_t) n);
|
||||
main_stream->parallel_for(
|
||||
sycl::nd_range<1>((num_blocks * sycl::range<1>(SYCL_GELU_BLOCK_SIZE)),
|
||||
sycl::range<1>(SYCL_GELU_BLOCK_SIZE)), [=](sycl::nd_item<1> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
|
||||
gated_op_fused_geglu_erf(x_ptr, g_ptr, dst_ptr, k, n_fd, o0, o1, item_ct1);
|
||||
});
|
||||
});
|
||||
ggml_sycl_detail::ggml_sycl_op_unary_gated(ctx, dst, [](auto x) {
|
||||
return op_gelu_erf(x);
|
||||
});
|
||||
}
|
||||
|
||||
static inline void ggml_sycl_op_geglu_quick(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
|
||||
ggml_sycl_detail::dispatch_ggml_sycl_op_fused_glu(ctx, dst,
|
||||
[](const auto* x_ptr, const auto* g_ptr, auto* dst_ptr, uint64_t k, uint64_t n, uint64_t o0, uint64_t o1, queue_ptr main_stream) {
|
||||
const uint32_t num_blocks = ceil_div(k, SYCL_GELU_BLOCK_SIZE);
|
||||
const sycl::uint3 n_fd = init_fastdiv_values((uint32_t) n);
|
||||
main_stream->parallel_for(
|
||||
sycl::nd_range<1>((num_blocks * sycl::range<1>(SYCL_GELU_BLOCK_SIZE)),
|
||||
sycl::range<1>(SYCL_GELU_BLOCK_SIZE)), [=](sycl::nd_item<1> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
|
||||
gated_op_fused_geglu_quick(x_ptr, g_ptr, dst_ptr, k, n_fd, o0, o1, item_ct1);
|
||||
});
|
||||
});
|
||||
ggml_sycl_detail::ggml_sycl_op_unary_gated(ctx, dst, [](auto x) {
|
||||
return op_gelu_quick(x);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -73,6 +73,7 @@ static void flash_attn_ext_vec(const char* __restrict__ Q,
|
||||
const int32_t nb31,
|
||||
const int32_t nb32,
|
||||
const int64_t nb33) {
|
||||
|
||||
#ifdef SYCL_FLASH_ATTN
|
||||
// Skip unused kernel variants for faster compilation:
|
||||
|
||||
@@ -469,7 +470,6 @@ static void flash_attn_ext_vec(const char* __restrict__ Q,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
item_ct1.barrier(sycl::access::fence_space::local_space);
|
||||
|
||||
#pragma unroll
|
||||
@@ -591,22 +591,24 @@ void ggml_sycl_flash_attn_ext_vec_case_impl(ggml_backend_sycl_context & ctx, ggm
|
||||
|
||||
const auto arch = ggml_sycl_info().devices[ctx.device].hw_info.arch;
|
||||
const int nthreads = ggml_sycl_fattn_vec_get_nthreads_device(arch);
|
||||
// 256 threads would overflow the 64 KB work-group local memory at D == 512, so keep 128 there.
|
||||
if (D <= 256 && nthreads == 256) {
|
||||
constexpr int nthreads_hw = 256;
|
||||
constexpr int nwarps = nthreads_hw / warp_size;
|
||||
launch_fattn<D, cols_per_block, 1,
|
||||
flash_attn_ext_vec<D, cols_per_block, type_K, type_V,
|
||||
use_logit_softcap, warp_size, nthreads_hw>, warp_size>(
|
||||
ctx, dst, nwarps, nbytes_shared, D, need_f16_K, need_f16_V, false);
|
||||
} else {
|
||||
constexpr int nthreads_hw = 128;
|
||||
constexpr int nwarps = nthreads_hw / warp_size;
|
||||
launch_fattn<D, cols_per_block, 1,
|
||||
flash_attn_ext_vec<D, cols_per_block, type_K, type_V,
|
||||
use_logit_softcap, warp_size, nthreads_hw>, warp_size>(
|
||||
ctx, dst, nwarps, nbytes_shared, D, need_f16_K, need_f16_V, false);
|
||||
if constexpr (D <= 256) {
|
||||
if (nthreads == 256) {
|
||||
constexpr int nthreads_hw = 256;
|
||||
constexpr int nwarps = nthreads_hw / warp_size;
|
||||
launch_fattn<D, cols_per_block, 1,
|
||||
flash_attn_ext_vec<D, cols_per_block, type_K, type_V,
|
||||
use_logit_softcap, warp_size, nthreads_hw>, warp_size>(
|
||||
ctx, dst, nwarps, nbytes_shared, D, need_f16_K, need_f16_V, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr int nthreads_hw = 128;
|
||||
constexpr int nwarps = nthreads_hw / warp_size;
|
||||
launch_fattn<D, cols_per_block, 1,
|
||||
flash_attn_ext_vec<D, cols_per_block, type_K, type_V,
|
||||
use_logit_softcap, warp_size, nthreads_hw>, warp_size>(
|
||||
ctx, dst, nwarps, nbytes_shared, D, need_f16_K, need_f16_V, false);
|
||||
}
|
||||
|
||||
template <int D, int type_K, int type_V>
|
||||
|
||||
@@ -62,6 +62,8 @@
|
||||
#include "ggml-sycl/repeat_back.hpp"
|
||||
#include "ggml-sycl/set_rows.hpp"
|
||||
#include "ggml-sycl/set.hpp"
|
||||
#include "ggml-sycl/dsv4-hc.hpp"
|
||||
#include "ggml-sycl/lightning-indexer.hpp"
|
||||
#include "ggml-sycl/conv2d.hpp"
|
||||
#include "ggml-sycl/conv2d-dw.hpp"
|
||||
#include "ggml-sycl/conv2d-transpose.hpp"
|
||||
@@ -4942,6 +4944,18 @@ static bool ggml_sycl_compute_forward(ggml_backend_sycl_context & ctx, struct gg
|
||||
case GGML_OP_SET_ROWS:
|
||||
ggml_sycl_op_set_rows(ctx, dst);
|
||||
break;
|
||||
case GGML_OP_DSV4_HC_PRE:
|
||||
ggml_sycl_op_dsv4_hc_pre(ctx, dst);
|
||||
break;
|
||||
case GGML_OP_DSV4_HC_COMB:
|
||||
ggml_sycl_op_dsv4_hc_comb(ctx, dst);
|
||||
break;
|
||||
case GGML_OP_DSV4_HC_POST:
|
||||
ggml_sycl_op_dsv4_hc_post(ctx, dst);
|
||||
break;
|
||||
case GGML_OP_LIGHTNING_INDEXER:
|
||||
ggml_sycl_op_lightning_indexer(ctx, dst);
|
||||
break;
|
||||
case GGML_OP_DUP:
|
||||
ggml_sycl_dup(ctx, dst);
|
||||
break;
|
||||
@@ -5795,17 +5809,33 @@ static bool do_ggml_backend_sycl_device_supports_op(ggml_backend_dev_t dev, cons
|
||||
|
||||
case GGML_OP_SET_ROWS:
|
||||
{
|
||||
|
||||
auto res = ((op->type == GGML_TYPE_F32 || op->type == GGML_TYPE_F16 || op->type == GGML_TYPE_BF16 ||
|
||||
op->type == GGML_TYPE_Q8_0 || op->type == GGML_TYPE_Q5_1 || op->type == GGML_TYPE_Q5_0 ||
|
||||
op->type == GGML_TYPE_Q1_0 ||
|
||||
op->type == GGML_TYPE_Q4_1 || op->type == GGML_TYPE_Q4_0 || op->type == GGML_TYPE_IQ4_NL ||
|
||||
op->type == GGML_TYPE_MXFP4 || op->type == GGML_TYPE_NVFP4) &&
|
||||
op->src[0]->type == GGML_TYPE_F32 &&
|
||||
(op->src[1]->type == GGML_TYPE_I64 || op->src[1]->type == GGML_TYPE_I32));
|
||||
auto res = (op->src[0]->type == GGML_TYPE_F32 || op->src[0]->type == GGML_TYPE_F16 ||
|
||||
op->src[0]->type == GGML_TYPE_BF16) &&
|
||||
(op->src[1]->type == GGML_TYPE_I64 || op->src[1]->type == GGML_TYPE_I32);
|
||||
return res;
|
||||
}
|
||||
break;
|
||||
case GGML_OP_DSV4_HC_PRE:
|
||||
return op->src[0]->type == GGML_TYPE_F32 && op->src[1]->type == GGML_TYPE_F32 &&
|
||||
op->type == GGML_TYPE_F32;
|
||||
case GGML_OP_DSV4_HC_COMB:
|
||||
return op->src[0]->type == GGML_TYPE_F32 && op->src[1]->type == GGML_TYPE_F32 &&
|
||||
op->src[2]->type == GGML_TYPE_F32 && op->type == GGML_TYPE_F32;
|
||||
case GGML_OP_DSV4_HC_POST:
|
||||
return op->src[0]->type == GGML_TYPE_F32 && op->src[1]->type == GGML_TYPE_F32 &&
|
||||
op->src[2]->type == GGML_TYPE_F32 && op->src[3]->type == GGML_TYPE_F32 &&
|
||||
op->type == GGML_TYPE_F32;
|
||||
case GGML_OP_LIGHTNING_INDEXER:
|
||||
return op->src[0]->type == GGML_TYPE_F32 &&
|
||||
(op->src[1]->type == GGML_TYPE_F16 || op->src[1]->type == GGML_TYPE_F32 ||
|
||||
op->src[1]->type == GGML_TYPE_BF16 || op->src[1]->type == GGML_TYPE_Q8_0 ||
|
||||
op->src[1]->type == GGML_TYPE_Q5_1 || op->src[1]->type == GGML_TYPE_Q5_0 ||
|
||||
op->src[1]->type == GGML_TYPE_Q4_1 || op->src[1]->type == GGML_TYPE_Q4_0 ||
|
||||
op->src[1]->type == GGML_TYPE_IQ4_NL) &&
|
||||
op->src[2]->type == GGML_TYPE_F32 &&
|
||||
op->src[3]->type == GGML_TYPE_F16 &&
|
||||
op->type == GGML_TYPE_F32 &&
|
||||
op->src[0]->ne[0] == WARP_SIZE * 8;
|
||||
case GGML_OP_CPY:
|
||||
{
|
||||
ggml_type src0_type = op->src[0]->type;
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
#include "lightning-indexer.hpp"
|
||||
#include "dequantize.hpp"
|
||||
|
||||
static void lightning_indexer_f32_sycl(
|
||||
const char * q, const char * k, const char * w, const char * m, float * dst,
|
||||
int64_t n_embd, int64_t n_head, int64_t n_batch, int64_t n_stream, int64_t n_kv,
|
||||
int64_t nem3,
|
||||
int64_t nbq1, int64_t nbq2, int64_t nbq3,
|
||||
int64_t nbk2, int64_t nbk3,
|
||||
int64_t nbw1, int64_t nbw3,
|
||||
int64_t nbm1, int64_t nbm3,
|
||||
int64_t nb1, int64_t nb3,
|
||||
ggml_type k_type,
|
||||
queue_ptr stream) {
|
||||
|
||||
constexpr int64_t LANES = WARP_SIZE;
|
||||
constexpr int64_t ELEMS_PER_LANE = 8;
|
||||
constexpr int64_t ROWS_PER_BLOCK = 4;
|
||||
constexpr int64_t BLOCK_SIZE = ROWS_PER_BLOCK * LANES;
|
||||
|
||||
const int64_t n_rows = n_batch * n_stream * n_kv;
|
||||
const int64_t n_blocks = (n_rows + ROWS_PER_BLOCK - 1) / ROWS_PER_BLOCK;
|
||||
|
||||
stream->parallel_for(
|
||||
sycl::nd_range<1>(
|
||||
sycl::range<1>(n_blocks * BLOCK_SIZE),
|
||||
sycl::range<1>(BLOCK_SIZE)),
|
||||
[=](sycl::nd_item<1> item) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
|
||||
const int64_t ir = item.get_global_id(0);
|
||||
const int64_t lane = ir % LANES;
|
||||
const int64_t row = ir / LANES;
|
||||
if (row >= n_rows) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int64_t i_bs = row / n_kv;
|
||||
const int64_t i_kv = row % n_kv;
|
||||
const int64_t i_batch = i_bs / n_stream;
|
||||
const int64_t i_stream = i_bs % n_stream;
|
||||
|
||||
// load K row slice into registers (row is contiguous, nbk0 == type size)
|
||||
const char * k_base = k + i_kv*nbk2 + i_stream*nbk3;
|
||||
float k_local[ELEMS_PER_LANE];
|
||||
if (k_type == GGML_TYPE_F16) {
|
||||
const sycl::half * k_row = (const sycl::half *) k_base;
|
||||
#pragma unroll
|
||||
for (int64_t j = 0; j < ELEMS_PER_LANE; ++j) {
|
||||
k_local[j] = static_cast<float>(k_row[lane*ELEMS_PER_LANE + j]);
|
||||
}
|
||||
} else if (k_type == GGML_TYPE_F32) {
|
||||
const float * k_row = (const float *) k_base;
|
||||
#pragma unroll
|
||||
for (int64_t j = 0; j < ELEMS_PER_LANE; ++j) {
|
||||
k_local[j] = k_row[lane*ELEMS_PER_LANE + j];
|
||||
}
|
||||
} else {
|
||||
const int64_t lane_base = lane * ELEMS_PER_LANE;
|
||||
switch (k_type) {
|
||||
case GGML_TYPE_BF16: {
|
||||
const sycl::ext::oneapi::bfloat16 * k_row = (const sycl::ext::oneapi::bfloat16 *) k_base;
|
||||
#pragma unroll
|
||||
for (int64_t j = 0; j < ELEMS_PER_LANE; ++j) {
|
||||
k_local[j] = static_cast<float>(k_row[lane_base + j]);
|
||||
}
|
||||
} break;
|
||||
case GGML_TYPE_Q4_0:
|
||||
case GGML_TYPE_Q4_1:
|
||||
case GGML_TYPE_Q5_0:
|
||||
case GGML_TYPE_Q5_1: {
|
||||
#pragma unroll
|
||||
for (int64_t j = 0; j < ELEMS_PER_LANE; ++j) {
|
||||
const int64_t idx = lane_base + j;
|
||||
const int64_t ib = idx / QK4_0;
|
||||
const int iqs = idx % (QK4_0/2);
|
||||
dfloat2 kv;
|
||||
if (k_type == GGML_TYPE_Q4_0) {
|
||||
dequantize_q4_0(k_base, ib, iqs, kv);
|
||||
} else if (k_type == GGML_TYPE_Q4_1) {
|
||||
dequantize_q4_1(k_base, ib, iqs, kv);
|
||||
} else if (k_type == GGML_TYPE_Q5_0) {
|
||||
dequantize_q5_0(k_base, ib, iqs, kv);
|
||||
} else {
|
||||
dequantize_q5_1(k_base, ib, iqs, kv);
|
||||
}
|
||||
k_local[j] = (idx % QK4_0) < (QK4_0/2) ? static_cast<float>(kv.x()) : static_cast<float>(kv.y());
|
||||
}
|
||||
} break;
|
||||
case GGML_TYPE_Q8_0: {
|
||||
#pragma unroll
|
||||
for (int64_t pair = 0; pair < ELEMS_PER_LANE / 2; ++pair) {
|
||||
const int64_t elem0 = lane_base + 2 * pair;
|
||||
dfloat2 kv;
|
||||
dequantize_q8_0(k_base, elem0 / QK8_0, elem0 % QK8_0, kv);
|
||||
k_local[2 * pair + 0] = static_cast<float>(kv.x());
|
||||
k_local[2 * pair + 1] = static_cast<float>(kv.y());
|
||||
}
|
||||
} break;
|
||||
case GGML_TYPE_IQ4_NL: {
|
||||
#pragma unroll
|
||||
for (int64_t pair = 0; pair < ELEMS_PER_LANE / 2; ++pair) {
|
||||
const int64_t elem0 = lane_base + 2 * pair;
|
||||
dfloat2 kv;
|
||||
dequantize_iq4_nl(k_base, elem0 / QK4_NL, elem0 % QK4_NL, kv);
|
||||
k_local[2 * pair + 0] = static_cast<float>(kv.x());
|
||||
k_local[2 * pair + 1] = static_cast<float>(kv.y());
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
#pragma unroll
|
||||
for (int64_t j = 0; j < ELEMS_PER_LANE; ++j) {
|
||||
k_local[j] = 0.0f;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const char * q_base = q + i_batch*nbq2 + i_stream*nbq3;
|
||||
const float * w_base = (const float *) (w + i_batch*nbw1 + i_stream*nbw3);
|
||||
|
||||
float score = 0.0f;
|
||||
for (int64_t h = 0; h < n_head; ++h) {
|
||||
const float * q_row = (const float *) (q_base + h*nbq1);
|
||||
float dot = 0.0f;
|
||||
#pragma unroll
|
||||
for (int64_t j = 0; j < ELEMS_PER_LANE; ++j) {
|
||||
const int64_t i = lane*ELEMS_PER_LANE + j;
|
||||
if (i < n_embd) {
|
||||
dot += q_row[i] * k_local[j];
|
||||
}
|
||||
}
|
||||
dot = sycl::reduce_over_group(item.get_sub_group(), dot, sycl::plus<float>());
|
||||
if (lane == 0) {
|
||||
score += sycl::max(dot, 0.0f) * w_base[h];
|
||||
}
|
||||
}
|
||||
|
||||
if (lane == 0) {
|
||||
const sycl::half * m_base = (const sycl::half *) (m + i_batch*nbm1 + (i_stream % nem3)*nbm3);
|
||||
// flat-index store: storing through a strided base pointer
|
||||
// hangs/misroutes writes on this stack when n_batch*n_stream > 1
|
||||
const int64_t dst_idx = i_kv + i_batch*(nb1/sizeof(float)) + i_stream*(nb3/sizeof(float));
|
||||
dst[dst_idx] = score + static_cast<float>(m_base[i_kv]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ggml_sycl_op_lightning_indexer(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
|
||||
scope_op_debug_print scope_dbg_print(__func__, dst, /*num_src=*/4);
|
||||
const ggml_tensor * q = dst->src[0];
|
||||
const ggml_tensor * k = dst->src[1];
|
||||
const ggml_tensor * w = dst->src[2]; // weights
|
||||
const ggml_tensor * m = dst->src[3]; // mask
|
||||
|
||||
GGML_ASSERT(dst->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT( q->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT( w->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT( m->type == GGML_TYPE_F16);
|
||||
GGML_ASSERT(k->type == GGML_TYPE_F16 || k->type == GGML_TYPE_F32 || k->type == GGML_TYPE_BF16 ||
|
||||
k->type == GGML_TYPE_Q8_0 || k->type == GGML_TYPE_Q5_1 || k->type == GGML_TYPE_Q5_0 ||
|
||||
k->type == GGML_TYPE_Q4_1 || k->type == GGML_TYPE_Q4_0 || k->type == GGML_TYPE_IQ4_NL);
|
||||
|
||||
GGML_TENSOR_LOCALS(int64_t, neq, q, ne);
|
||||
GGML_TENSOR_LOCALS(size_t, nbq, q, nb);
|
||||
GGML_TENSOR_LOCALS(int64_t, nek, k, ne);
|
||||
GGML_TENSOR_LOCALS(size_t, nbk, k, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbw, w, nb);
|
||||
GGML_TENSOR_LOCALS(int64_t, nem, m, ne);
|
||||
GGML_TENSOR_LOCALS(size_t, nbm, m, nb);
|
||||
GGML_TENSOR_LOCALS(int64_t, ne, dst, ne);
|
||||
GGML_TENSOR_LOCALS(size_t, nb, dst, nb);
|
||||
|
||||
// input rows must be contiguous
|
||||
GGML_ASSERT(nbq0 == ggml_type_size(q->type));
|
||||
GGML_ASSERT(nbk0 == ggml_type_size(k->type));
|
||||
GGML_ASSERT(nbm0 == ggml_type_size(m->type));
|
||||
GGML_ASSERT(nb0 == ggml_type_size(dst->type));
|
||||
|
||||
const int64_t n_embd = neq0;
|
||||
const int64_t n_head = neq1;
|
||||
const int64_t n_batch = neq2;
|
||||
const int64_t n_stream = neq3;
|
||||
const int64_t n_kv = nek2;
|
||||
|
||||
GGML_ASSERT(n_embd == WARP_SIZE * 8);
|
||||
|
||||
lightning_indexer_f32_sycl(
|
||||
(const char *) q->data, (const char *) k->data,
|
||||
(const char *) w->data, (const char *) m->data, (float *) dst->data,
|
||||
n_embd, n_head, n_batch, n_stream, n_kv, nem3,
|
||||
nbq1, nbq2, nbq3,
|
||||
nbk2, nbk3,
|
||||
nbw1, nbw3,
|
||||
nbm1, nbm3,
|
||||
nb1, nb3,
|
||||
k->type,
|
||||
ctx.stream());
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef GGML_SYCL_LIGHTNING_INDEXER_HPP
|
||||
#define GGML_SYCL_LIGHTNING_INDEXER_HPP
|
||||
|
||||
#include "common.hpp"
|
||||
|
||||
void ggml_sycl_op_lightning_indexer(ggml_backend_sycl_context & ctx, ggml_tensor * dst);
|
||||
|
||||
#endif // GGML_SYCL_LIGHTNING_INDEXER_HPP
|
||||
@@ -20,8 +20,6 @@
|
||||
#define MATRIX_ROW_PADDING 512 // last row of quant. matrices is a multiple of this to avoid out-of-bounds memory accesses
|
||||
|
||||
#define SYCL_COL2IM_1D_BLOCK_SIZE 256
|
||||
#define SYCL_GELU_BLOCK_SIZE 256
|
||||
#define SYCL_SILU_BLOCK_SIZE 256
|
||||
#define SYCL_TANH_BLOCK_SIZE 256
|
||||
#define SYCL_RELU_BLOCK_SIZE 256
|
||||
#define SYCL_HARDSIGMOID_BLOCK_SIZE 256
|
||||
|
||||
+344
-16
@@ -1,6 +1,10 @@
|
||||
#include "set_rows.hpp"
|
||||
#include "cpy.hpp"
|
||||
|
||||
#include "ggml-quants.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace utils {
|
||||
template<typename T>
|
||||
static constexpr bool is_arithmetic_v() {
|
||||
@@ -20,7 +24,17 @@ convert (const char* src, char* dst) {
|
||||
*reinterpret_cast<TOut*>(dst) = dst_val;
|
||||
}
|
||||
|
||||
template <typename TIdx, typename blockType, int qk, cpy_kernel_t cpyblck>
|
||||
#ifdef GGML_SYCL_HAS_BF16
|
||||
// sycl::vec::convert does not provide a half -> bfloat16 path, so route through float.
|
||||
template<>
|
||||
inline void convert<sycl::half, sycl::ext::oneapi::bfloat16>(const char* src, char* dst) {
|
||||
const float tmp = sycl::vec<sycl::half, 1>(*reinterpret_cast<const sycl::half*>(src))
|
||||
.template convert<float, sycl::rounding_mode::automatic>()[0];
|
||||
*reinterpret_cast<sycl::ext::oneapi::bfloat16*>(dst) = sycl::ext::oneapi::bfloat16(tmp);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename TIn, typename TIdx, typename blockType, int qk, cpy_kernel_t cpyblck>
|
||||
static void set_rows_sycl_q(const char * __restrict__ src0_d,
|
||||
const TIdx * __restrict__ src1_d,
|
||||
blockType * __restrict__ dst_d,
|
||||
@@ -68,13 +82,22 @@ static void set_rows_sycl_q(const char * __restrict__ src0_d,
|
||||
const int64_t i11 = i02 % ne11;
|
||||
const int64_t i10 = i01;
|
||||
const size_t src_offset = calculate_offset<3>({ nb01, nb02, nb03 }, { i01, i02, i03 });
|
||||
const char * src_block = src0_d + src_offset + i00 * sizeof(float);
|
||||
const char * src_block = src0_d + src_offset + i00 * sizeof(TIn);
|
||||
const size_t src1_offset = calculate_offset<3>({ nb10, nb11, nb12 }, { i10, i11, i12 });
|
||||
const int64_t dst_row = src1_d[src1_offset / sizeof(TIdx)];
|
||||
const size_t dst_offset =
|
||||
calculate_offset<3>({ nb1, nb2, nb3 }, { dst_row, i02, i03 }) + (i00 / qk) * sizeof(blockType);
|
||||
char * dst_block = reinterpret_cast<char *>(reinterpret_cast<char *>(dst_d) + dst_offset);
|
||||
cpyblck(src_block, dst_block);
|
||||
if constexpr (std::is_same_v<TIn, float>) {
|
||||
cpyblck(src_block, dst_block);
|
||||
} else {
|
||||
float src_block_f32[qk];
|
||||
const TIn * src_block_t = reinterpret_cast<const TIn *>(src_block);
|
||||
for (int j = 0; j < qk; ++j) {
|
||||
src_block_f32[j] = (float) src_block_t[j];
|
||||
}
|
||||
cpyblck(reinterpret_cast<const char *>(src_block_f32), dst_block);
|
||||
}
|
||||
});
|
||||
GGML_UNUSED(ne10);
|
||||
GGML_UNUSED(ne13);
|
||||
@@ -82,6 +105,139 @@ static void set_rows_sycl_q(const char * __restrict__ src0_d,
|
||||
GGML_UNUSED(nb13);
|
||||
}
|
||||
|
||||
template<typename blockType>
|
||||
using quantize_row_qk_t = void (*)(const float *, blockType *, int64_t);
|
||||
|
||||
using quantize_rows_f_t = size_t (*)(const float *, void *, int64_t, int64_t, const float *);
|
||||
|
||||
template <typename TIn, typename TIdx, typename blockType, int qk, quantize_row_qk_t<blockType> quantize_row>
|
||||
static void set_rows_sycl_qk_host(
|
||||
const ggml_tensor * src0,
|
||||
const ggml_tensor * src1,
|
||||
ggml_tensor * dst,
|
||||
const int64_t ne00,
|
||||
const int64_t ne01,
|
||||
const int64_t ne02,
|
||||
const int64_t ne03,
|
||||
const int64_t ne11,
|
||||
const int64_t ne12,
|
||||
const size_t nb01,
|
||||
const size_t nb02,
|
||||
const size_t nb03,
|
||||
const size_t nb10,
|
||||
const size_t nb11,
|
||||
const size_t nb12,
|
||||
const size_t nb1,
|
||||
const size_t nb2,
|
||||
const size_t nb3,
|
||||
queue_ptr stream) {
|
||||
GGML_ASSERT(ne00 % qk == 0);
|
||||
|
||||
const size_t src0_bytes = ggml_nbytes(src0);
|
||||
const size_t src1_bytes = ggml_nbytes(src1);
|
||||
|
||||
std::vector<char> src0_host(src0_bytes);
|
||||
std::vector<char> src1_host(src1_bytes);
|
||||
|
||||
stream->memcpy(src0_host.data(), src0->data, src0_bytes);
|
||||
stream->memcpy(src1_host.data(), src1->data, src1_bytes);
|
||||
stream->wait();
|
||||
|
||||
std::vector<float> src_row_f32(ne00);
|
||||
const int64_t nblocks = ne00 / qk;
|
||||
std::vector<blockType> dst_row_q(nblocks);
|
||||
|
||||
for (int64_t i03 = 0; i03 < ne03; ++i03) {
|
||||
for (int64_t i02 = 0; i02 < ne02; ++i02) {
|
||||
for (int64_t i01 = 0; i01 < ne01; ++i01) {
|
||||
const int64_t i12 = i03 % ne12;
|
||||
const int64_t i11 = i02 % ne11;
|
||||
const int64_t i10 = i01;
|
||||
|
||||
const size_t src1_offset = calculate_offset<3>({ nb10, nb11, nb12 }, { i10, i11, i12 });
|
||||
const int64_t dst_row = *(const TIdx *) (src1_host.data() + src1_offset);
|
||||
|
||||
const size_t src0_row_offset = calculate_offset<3>({ nb01, nb02, nb03 }, { i01, i02, i03 });
|
||||
const TIn * src_row = reinterpret_cast<const TIn *>(src0_host.data() + src0_row_offset);
|
||||
|
||||
for (int64_t i00 = 0; i00 < ne00; ++i00) {
|
||||
src_row_f32[i00] = (float) src_row[i00];
|
||||
}
|
||||
|
||||
quantize_row(src_row_f32.data(), dst_row_q.data(), ne00);
|
||||
|
||||
const size_t dst_offset = calculate_offset<3>({ nb1, nb2, nb3 }, { dst_row, i02, i03 });
|
||||
stream->memcpy((char *) dst->data + dst_offset, dst_row_q.data(), nblocks * sizeof(blockType));
|
||||
stream->wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TIn, typename TIdx, typename blockType, int qk, quantize_rows_f_t quantize_rows>
|
||||
static void set_rows_sycl_iq_host(
|
||||
const ggml_tensor * src0,
|
||||
const ggml_tensor * src1,
|
||||
ggml_tensor * dst,
|
||||
const int64_t ne00,
|
||||
const int64_t ne01,
|
||||
const int64_t ne02,
|
||||
const int64_t ne03,
|
||||
const int64_t ne11,
|
||||
const int64_t ne12,
|
||||
const size_t nb01,
|
||||
const size_t nb02,
|
||||
const size_t nb03,
|
||||
const size_t nb10,
|
||||
const size_t nb11,
|
||||
const size_t nb12,
|
||||
const size_t nb1,
|
||||
const size_t nb2,
|
||||
const size_t nb3,
|
||||
queue_ptr stream) {
|
||||
GGML_ASSERT(ne00 % qk == 0);
|
||||
|
||||
const size_t src0_bytes = ggml_nbytes(src0);
|
||||
const size_t src1_bytes = ggml_nbytes(src1);
|
||||
|
||||
std::vector<char> src0_host(src0_bytes);
|
||||
std::vector<char> src1_host(src1_bytes);
|
||||
|
||||
stream->memcpy(src0_host.data(), src0->data, src0_bytes);
|
||||
stream->memcpy(src1_host.data(), src1->data, src1_bytes);
|
||||
stream->wait();
|
||||
|
||||
std::vector<float> src_row_f32(ne00);
|
||||
const int64_t nblocks = ne00 / qk;
|
||||
std::vector<blockType> dst_row_q(nblocks);
|
||||
|
||||
for (int64_t i03 = 0; i03 < ne03; ++i03) {
|
||||
for (int64_t i02 = 0; i02 < ne02; ++i02) {
|
||||
for (int64_t i01 = 0; i01 < ne01; ++i01) {
|
||||
const int64_t i12 = i03 % ne12;
|
||||
const int64_t i11 = i02 % ne11;
|
||||
const int64_t i10 = i01;
|
||||
|
||||
const size_t src1_offset = calculate_offset<3>({ nb10, nb11, nb12 }, { i10, i11, i12 });
|
||||
const int64_t dst_row = *(const TIdx *) (src1_host.data() + src1_offset);
|
||||
|
||||
const size_t src0_row_offset = calculate_offset<3>({ nb01, nb02, nb03 }, { i01, i02, i03 });
|
||||
const TIn * src_row = reinterpret_cast<const TIn *>(src0_host.data() + src0_row_offset);
|
||||
|
||||
for (int64_t i00 = 0; i00 < ne00; ++i00) {
|
||||
src_row_f32[i00] = (float) src_row[i00];
|
||||
}
|
||||
|
||||
quantize_rows(src_row_f32.data(), dst_row_q.data(), 1, ne00, nullptr);
|
||||
|
||||
const size_t dst_offset = calculate_offset<3>({ nb1, nb2, nb3 }, { dst_row, i02, i03 });
|
||||
stream->memcpy((char *) dst->data + dst_offset, dst_row_q.data(), nblocks * sizeof(blockType));
|
||||
stream->wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename TIn, typename TIdx, typename TOut>
|
||||
static void k_set_rows(
|
||||
const char * __restrict__ src0, const TIdx * __restrict__ src1, char * __restrict__ dst,
|
||||
@@ -200,31 +356,194 @@ static void set_rows_sycl(ggml_backend_sycl_context & ctx, const ggml_tensor * s
|
||||
break;
|
||||
#endif
|
||||
case GGML_TYPE_Q8_0:
|
||||
set_rows_sycl_q<TIdx, block_q8_0, QK8_0, cpy_blck_f32_q8_0>(src0_d, src1_d, (block_q8_0 *)dst->data, ne00, ne01, ne02, ne03, ne10, ne11, ne12, ne13, nb00, nb01, nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
set_rows_sycl_q<TIn, TIdx, block_q8_0, QK8_0, cpy_blck_f32_q8_0>(
|
||||
src0_d, src1_d, (block_q8_0 *) dst->data, ne00, ne01, ne02, ne03,
|
||||
ne10, ne11, ne12, ne13, nb00, nb01,
|
||||
nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
case GGML_TYPE_Q1_0:
|
||||
set_rows_sycl_q<TIdx, block_q1_0, QK1_0, cpy_blck_f32_q1_0>(src0_d, src1_d, (block_q1_0 *)dst->data, ne00, ne01, ne02, ne03, ne10, ne11, ne12, ne13, nb00, nb01, nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
set_rows_sycl_q<TIn, TIdx, block_q1_0, QK1_0, cpy_blck_f32_q1_0>(
|
||||
src0_d, src1_d, (block_q1_0 *) dst->data, ne00, ne01, ne02, ne03,
|
||||
ne10, ne11, ne12, ne13, nb00, nb01,
|
||||
nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
case GGML_TYPE_Q2_0:
|
||||
set_rows_sycl_q<TIn, TIdx, block_q2_0, QK2_0, cpy_blck_f32_q2_0>(
|
||||
src0_d, src1_d, (block_q2_0 *) dst->data, ne00, ne01, ne02, ne03,
|
||||
ne10, ne11, ne12, ne13, nb00, nb01,
|
||||
nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
case GGML_TYPE_Q5_1:
|
||||
set_rows_sycl_q<TIdx, block_q5_1, QK5_1, cpy_blck_f32_q5_1>(src0_d, src1_d, (block_q5_1 *)dst->data, ne00, ne01, ne02, ne03, ne10, ne11, ne12, ne13, nb00, nb01, nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
set_rows_sycl_q<TIn, TIdx, block_q5_1, QK5_1, cpy_blck_f32_q5_1>(
|
||||
src0_d, src1_d, (block_q5_1 *) dst->data, ne00, ne01, ne02, ne03,
|
||||
ne10, ne11, ne12, ne13, nb00, nb01,
|
||||
nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
case GGML_TYPE_Q5_0:
|
||||
set_rows_sycl_q<TIdx, block_q5_0, QK5_0, cpy_blck_f32_q5_0>(src0_d, src1_d, (block_q5_0 *)dst->data, ne00, ne01, ne02, ne03, ne10, ne11, ne12, ne13, nb00, nb01, nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
set_rows_sycl_q<TIn, TIdx, block_q5_0, QK5_0, cpy_blck_f32_q5_0>(
|
||||
src0_d, src1_d, (block_q5_0 *) dst->data, ne00, ne01, ne02, ne03,
|
||||
ne10, ne11, ne12, ne13, nb00, nb01,
|
||||
nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
case GGML_TYPE_Q4_1:
|
||||
set_rows_sycl_q<TIdx, block_q4_1, QK4_1, cpy_blck_f32_q4_1>(src0_d, src1_d, (block_q4_1 *)dst->data, ne00, ne01, ne02, ne03, ne10, ne11, ne12, ne13, nb00, nb01, nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
set_rows_sycl_q<TIn, TIdx, block_q4_1, QK4_1, cpy_blck_f32_q4_1>(
|
||||
src0_d, src1_d, (block_q4_1 *) dst->data, ne00, ne01, ne02, ne03,
|
||||
ne10, ne11, ne12, ne13, nb00, nb01,
|
||||
nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
case GGML_TYPE_Q4_0:
|
||||
set_rows_sycl_q<TIdx, block_q4_0, QK4_0, cpy_blck_f32_q4_0>(src0_d, src1_d, (block_q4_0 *)dst->data, ne00, ne01, ne02, ne03, ne10, ne11, ne12, ne13, nb00, nb01, nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
set_rows_sycl_q<TIn, TIdx, block_q4_0, QK4_0, cpy_blck_f32_q4_0>(
|
||||
src0_d, src1_d, (block_q4_0 *) dst->data, ne00, ne01, ne02, ne03,
|
||||
ne10, ne11, ne12, ne13, nb00, nb01,
|
||||
nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
case GGML_TYPE_IQ4_NL:
|
||||
set_rows_sycl_q<TIdx, block_iq4_nl, QK4_NL, cpy_blck_f32_iq4_nl>(src0_d, src1_d, (block_iq4_nl *)dst->data, ne00, ne01, ne02, ne03, ne10, ne11, ne12, ne13, nb00, nb01, nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
set_rows_sycl_q<TIn, TIdx, block_iq4_nl, QK4_NL, cpy_blck_f32_iq4_nl>(
|
||||
src0_d, src1_d, (block_iq4_nl *) dst->data, ne00, ne01, ne02, ne03,
|
||||
ne10, ne11, ne12, ne13, nb00, nb01,
|
||||
nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
case GGML_TYPE_MXFP4:
|
||||
set_rows_sycl_q<TIdx, block_mxfp4, QK_MXFP4, cpy_blck_f32_mxfp4>(src0_d, src1_d, (block_mxfp4 *)dst->data, ne00, ne01, ne02, ne03, ne10, ne11, ne12, ne13, nb00, nb01, nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
set_rows_sycl_q<TIn, TIdx, block_mxfp4, QK_MXFP4, cpy_blck_f32_mxfp4>(
|
||||
src0_d, src1_d, (block_mxfp4 *) dst->data, ne00, ne01, ne02, ne03,
|
||||
ne10, ne11, ne12, ne13, nb00, nb01,
|
||||
nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
case GGML_TYPE_NVFP4:
|
||||
set_rows_sycl_q<TIdx, block_nvfp4, QK_NVFP4, cpy_blck_f32_nvfp4>(src0_d, src1_d, (block_nvfp4 *)dst->data, ne00, ne01, ne02, ne03, ne10, ne11, ne12, ne13, nb00, nb01, nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
set_rows_sycl_q<TIn, TIdx, block_nvfp4, QK_NVFP4, cpy_blck_f32_nvfp4>(
|
||||
src0_d, src1_d, (block_nvfp4 *) dst->data, ne00, ne01, ne02, ne03,
|
||||
ne10, ne11, ne12, ne13, nb00, nb01,
|
||||
nb02, nb03, nb10, nb11, nb12, nb13, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
case GGML_TYPE_Q2_K:
|
||||
set_rows_sycl_qk_host<TIn, TIdx, block_q2_K, QK_K, quantize_row_q2_K_ref>(
|
||||
src0, src1, dst,
|
||||
ne00, ne01, ne02, ne03,
|
||||
ne11, ne12,
|
||||
nb01, nb02, nb03,
|
||||
nb10, nb11, nb12,
|
||||
nb1, nb2, nb3,
|
||||
stream);
|
||||
break;
|
||||
case GGML_TYPE_Q3_K:
|
||||
set_rows_sycl_qk_host<TIn, TIdx, block_q3_K, QK_K, quantize_row_q3_K_ref>(
|
||||
src0, src1, dst,
|
||||
ne00, ne01, ne02, ne03,
|
||||
ne11, ne12,
|
||||
nb01, nb02, nb03,
|
||||
nb10, nb11, nb12,
|
||||
nb1, nb2, nb3,
|
||||
stream);
|
||||
break;
|
||||
case GGML_TYPE_Q4_K:
|
||||
set_rows_sycl_qk_host<TIn, TIdx, block_q4_K, QK_K, quantize_row_q4_K_ref>(
|
||||
src0, src1, dst,
|
||||
ne00, ne01, ne02, ne03,
|
||||
ne11, ne12,
|
||||
nb01, nb02, nb03,
|
||||
nb10, nb11, nb12,
|
||||
nb1, nb2, nb3,
|
||||
stream);
|
||||
break;
|
||||
case GGML_TYPE_Q5_K:
|
||||
set_rows_sycl_qk_host<TIn, TIdx, block_q5_K, QK_K, quantize_row_q5_K_ref>(
|
||||
src0, src1, dst,
|
||||
ne00, ne01, ne02, ne03,
|
||||
ne11, ne12,
|
||||
nb01, nb02, nb03,
|
||||
nb10, nb11, nb12,
|
||||
nb1, nb2, nb3,
|
||||
stream);
|
||||
break;
|
||||
case GGML_TYPE_Q6_K:
|
||||
set_rows_sycl_qk_host<TIn, TIdx, block_q6_K, QK_K, quantize_row_q6_K_ref>(
|
||||
src0, src1, dst,
|
||||
ne00, ne01, ne02, ne03,
|
||||
ne11, ne12,
|
||||
nb01, nb02, nb03,
|
||||
nb10, nb11, nb12,
|
||||
nb1, nb2, nb3,
|
||||
stream);
|
||||
break;
|
||||
case GGML_TYPE_IQ2_XXS:
|
||||
set_rows_sycl_iq_host<TIn, TIdx, block_iq2_xxs, QK_K, quantize_iq2_xxs>(
|
||||
src0, src1, dst,
|
||||
ne00, ne01, ne02, ne03,
|
||||
ne11, ne12,
|
||||
nb01, nb02, nb03,
|
||||
nb10, nb11, nb12,
|
||||
nb1, nb2, nb3,
|
||||
stream);
|
||||
break;
|
||||
case GGML_TYPE_IQ2_XS:
|
||||
set_rows_sycl_iq_host<TIn, TIdx, block_iq2_xs, QK_K, quantize_iq2_xs>(
|
||||
src0, src1, dst,
|
||||
ne00, ne01, ne02, ne03,
|
||||
ne11, ne12,
|
||||
nb01, nb02, nb03,
|
||||
nb10, nb11, nb12,
|
||||
nb1, nb2, nb3,
|
||||
stream);
|
||||
break;
|
||||
case GGML_TYPE_IQ2_S:
|
||||
set_rows_sycl_iq_host<TIn, TIdx, block_iq2_s, QK_K, quantize_iq2_s>(
|
||||
src0, src1, dst,
|
||||
ne00, ne01, ne02, ne03,
|
||||
ne11, ne12,
|
||||
nb01, nb02, nb03,
|
||||
nb10, nb11, nb12,
|
||||
nb1, nb2, nb3,
|
||||
stream);
|
||||
break;
|
||||
case GGML_TYPE_IQ3_XXS:
|
||||
set_rows_sycl_qk_host<TIn, TIdx, block_iq3_xxs, QK_K, quantize_row_iq3_xxs_ref>(
|
||||
src0, src1, dst,
|
||||
ne00, ne01, ne02, ne03,
|
||||
ne11, ne12,
|
||||
nb01, nb02, nb03,
|
||||
nb10, nb11, nb12,
|
||||
nb1, nb2, nb3,
|
||||
stream);
|
||||
break;
|
||||
case GGML_TYPE_IQ3_S:
|
||||
set_rows_sycl_qk_host<TIn, TIdx, block_iq3_s, QK_K, quantize_row_iq3_s_ref>(
|
||||
src0, src1, dst,
|
||||
ne00, ne01, ne02, ne03,
|
||||
ne11, ne12,
|
||||
nb01, nb02, nb03,
|
||||
nb10, nb11, nb12,
|
||||
nb1, nb2, nb3,
|
||||
stream);
|
||||
break;
|
||||
case GGML_TYPE_IQ1_S:
|
||||
set_rows_sycl_iq_host<TIn, TIdx, block_iq1_s, QK_K, quantize_iq1_s>(
|
||||
src0, src1, dst,
|
||||
ne00, ne01, ne02, ne03,
|
||||
ne11, ne12,
|
||||
nb01, nb02, nb03,
|
||||
nb10, nb11, nb12,
|
||||
nb1, nb2, nb3,
|
||||
stream);
|
||||
break;
|
||||
case GGML_TYPE_IQ1_M:
|
||||
set_rows_sycl_iq_host<TIn, TIdx, block_iq1_m, QK_K, quantize_iq1_m>(
|
||||
src0, src1, dst,
|
||||
ne00, ne01, ne02, ne03,
|
||||
ne11, ne12,
|
||||
nb01, nb02, nb03,
|
||||
nb10, nb11, nb12,
|
||||
nb1, nb2, nb3,
|
||||
stream);
|
||||
break;
|
||||
case GGML_TYPE_IQ4_XS:
|
||||
set_rows_sycl_qk_host<TIn, TIdx, block_iq4_xs, QK_K, quantize_row_iq4_xs_ref>(
|
||||
src0, src1, dst,
|
||||
ne00, ne01, ne02, ne03,
|
||||
ne11, ne12,
|
||||
nb01, nb02, nb03,
|
||||
nb10, nb11, nb12,
|
||||
nb1, nb2, nb3,
|
||||
stream);
|
||||
break;
|
||||
default:
|
||||
GGML_ABORT("Unsupported tensor type!");
|
||||
@@ -237,12 +556,21 @@ void ggml_sycl_op_set_rows(ggml_backend_sycl_context & ctx, ggml_tensor * dst) {
|
||||
const ggml_tensor * src0 = dst->src[0];
|
||||
const ggml_tensor * src1 = dst->src[1];
|
||||
|
||||
GGML_ASSERT(dst->src[0]->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(dst->src[0]->type == GGML_TYPE_F32 || dst->src[0]->type == GGML_TYPE_F16);
|
||||
GGML_ASSERT(dst->src[1]->type == GGML_TYPE_I64 || dst->src[1]->type == GGML_TYPE_I32);
|
||||
|
||||
if (src1->type == GGML_TYPE_I64) {
|
||||
set_rows_sycl<float, int64_t>(ctx, src0, src1, dst);
|
||||
// dispatch on the index type (src1) and the source value type (src0)
|
||||
if (src0->type == GGML_TYPE_F16) {
|
||||
if (src1->type == GGML_TYPE_I64) {
|
||||
set_rows_sycl<sycl::half, int64_t>(ctx, src0, src1, dst);
|
||||
} else {
|
||||
set_rows_sycl<sycl::half, int32_t>(ctx, src0, src1, dst);
|
||||
}
|
||||
} else {
|
||||
set_rows_sycl<float, int32_t>(ctx, src0, src1, dst);
|
||||
if (src1->type == GGML_TYPE_I64) {
|
||||
set_rows_sycl<float, int64_t>(ctx, src0, src1, dst);
|
||||
} else {
|
||||
set_rows_sycl<float, int32_t>(ctx, src0, src1, dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,9 +36,13 @@ static void kernel_ssm_conv(
|
||||
return;
|
||||
}
|
||||
|
||||
const int channel = static_cast<int>(idx % d_inner);
|
||||
const int token = static_cast<int>((idx / d_inner) % n_t);
|
||||
const int seq = static_cast<int>(idx / (static_cast<size_t>(d_inner) * static_cast<size_t>(n_t)));
|
||||
// src has the tokens of one channel contiguous, dst has the channels of one
|
||||
// token contiguous, so either the loads or the store must be strided. Indexing
|
||||
// token-fastest coalesces the d_conv loads, which measured faster except for
|
||||
// short, cache-resident rows.
|
||||
const int token = static_cast<int>(idx % n_t);
|
||||
const int channel = static_cast<int>((idx / n_t) % d_inner);
|
||||
const int seq = static_cast<int>(idx / (static_cast<size_t>(n_t) * static_cast<size_t>(d_inner)));
|
||||
|
||||
const float *s = src_data
|
||||
+ static_cast<size_t>(seq) * static_cast<size_t>(src_stride_seq)
|
||||
|
||||
@@ -186,13 +186,22 @@ static bool is_pow2(uint32_t x) { return x > 1 && (x & (x-1)) == 0; }
|
||||
|
||||
#define VK_DEVICE_DESCRIPTOR_POOL_SIZE 256
|
||||
|
||||
#define VK_CHECK(err, msg) \
|
||||
#define VK_CHECK(err, msg, dev) \
|
||||
do { \
|
||||
vk::Result err_ = (err); \
|
||||
vk::Result err_; \
|
||||
try { \
|
||||
err_ = (err); \
|
||||
} catch (vk::DeviceLostError &) { \
|
||||
ggml_vk_print_device_lost_info(dev); \
|
||||
GGML_LOG_ERROR("ggml_vulkan: %s at %s:%d\n", \
|
||||
#err, __FILE__, __LINE__); \
|
||||
throw; \
|
||||
} \
|
||||
if (err_ != vk::Result::eSuccess) { \
|
||||
fprintf(stderr, "ggml_vulkan: %s error %s at %s:%d\n", \
|
||||
GGML_LOG_ERROR("ggml_vulkan: %s error %s at %s:%d\n", \
|
||||
#err, to_string(err_).c_str(), __FILE__, __LINE__); \
|
||||
exit(1); \
|
||||
throw vk::SystemError(vk::make_error_code(err_), \
|
||||
"ggml_vulkan: " msg); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
@@ -302,9 +311,13 @@ struct vk_command_pool {
|
||||
}
|
||||
};
|
||||
|
||||
static void ggml_vk_print_device_fault_info(const vk_device& device);
|
||||
static void ggml_vk_print_device_lost_info(const vk_device& device);
|
||||
|
||||
// Prevent simultaneous submissions to the same queue.
|
||||
struct vk_queue_handle {
|
||||
vk::Queue queue;
|
||||
vk_device_ref device;
|
||||
virtual void submit(vk::ArrayProxy<const vk::SubmitInfo> submits, vk::Fence fence) = 0;
|
||||
virtual void lock() {} // no-op by default (internally synchronized case)
|
||||
virtual void unlock() {}
|
||||
@@ -315,7 +328,14 @@ struct vk_queue_handle_synchronized : vk_queue_handle {
|
||||
std::mutex mutex;
|
||||
void submit(vk::ArrayProxy<const vk::SubmitInfo> submits, vk::Fence fence) override {
|
||||
std::lock_guard<std::mutex> guard(mutex);
|
||||
queue.submit(submits, fence);
|
||||
try {
|
||||
queue.submit(submits, fence);
|
||||
} catch (vk::DeviceLostError &) {
|
||||
if (auto dev = device.lock()) {
|
||||
ggml_vk_print_device_lost_info(dev);
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
void lock() override { mutex.lock(); }
|
||||
void unlock() override { mutex.unlock(); }
|
||||
@@ -324,7 +344,14 @@ struct vk_queue_handle_synchronized : vk_queue_handle {
|
||||
struct vk_queue_handle_unsynchronized : vk_queue_handle {
|
||||
void submit(vk::ArrayProxy<const vk::SubmitInfo> submits, vk::Fence fence) override {
|
||||
// Driver guarantees internal synchronization via VK_KHR_internally_synchronized_queues
|
||||
queue.submit(submits, fence);
|
||||
try {
|
||||
queue.submit(submits, fence);
|
||||
} catch (vk::DeviceLostError &) {
|
||||
if (auto dev = device.lock()) {
|
||||
ggml_vk_print_device_lost_info(dev);
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
// lock()/unlock() inherited no-ops
|
||||
};
|
||||
@@ -835,6 +862,15 @@ struct vk_device_struct {
|
||||
|
||||
bool pipeline_executable_properties_support {};
|
||||
|
||||
bool device_fault {};
|
||||
PFN_vkGetDeviceFaultInfoEXT pfn_vkGetDeviceFaultInfoEXT {};
|
||||
|
||||
bool serialize_submissions {};
|
||||
|
||||
const ggml_cgraph * diag_cgraph {};
|
||||
int diag_prev_start = -1;
|
||||
int diag_prev_end = -1;
|
||||
|
||||
size_t idx;
|
||||
|
||||
bool mul_mat_l[GGML_TYPE_COUNT];
|
||||
@@ -1118,6 +1154,57 @@ void vk_command_pool::destroy(vk::Device& device) {
|
||||
cmd_buffers.clear();
|
||||
}
|
||||
|
||||
static void ggml_vk_print_device_fault_info(const vk_device& device) {
|
||||
if (!device->device_fault || !device->pfn_vkGetDeviceFaultInfoEXT) {
|
||||
return;
|
||||
}
|
||||
|
||||
VkDeviceFaultCountsEXT fault_counts {};
|
||||
fault_counts.sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_COUNTS_EXT;
|
||||
VkResult res = device->pfn_vkGetDeviceFaultInfoEXT(device->device, &fault_counts, nullptr);
|
||||
if (res != VK_SUCCESS) {
|
||||
GGML_LOG_ERROR("ggml_vulkan: vkGetDeviceFaultInfoEXT (counts) failed: %d\n", res);
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<VkDeviceFaultAddressInfoEXT> address_infos(fault_counts.addressInfoCount);
|
||||
std::vector<VkDeviceFaultVendorInfoEXT> vendor_infos(fault_counts.vendorInfoCount);
|
||||
|
||||
VkDeviceFaultInfoEXT fault_info {};
|
||||
fault_info.sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_INFO_EXT;
|
||||
fault_info.pAddressInfos = address_infos.data();
|
||||
fault_info.pVendorInfos = vendor_infos.data();
|
||||
|
||||
res = device->pfn_vkGetDeviceFaultInfoEXT(device->device, &fault_counts, &fault_info);
|
||||
if (res != VK_SUCCESS) {
|
||||
GGML_LOG_ERROR("ggml_vulkan: vkGetDeviceFaultInfoEXT (info) failed: %d\n", res);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fault_counts.addressInfoCount == 0 && fault_counts.vendorInfoCount == 0 && fault_info.description[0] == '\0') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (fault_info.description[0] != '\0') {
|
||||
GGML_LOG_ERROR("ggml_vulkan: device fault on %s: %s\n", device->name.c_str(), fault_info.description);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < fault_counts.addressInfoCount; i++) {
|
||||
const auto& info = address_infos[i];
|
||||
GGML_LOG_CONT(" address fault %u: type=%d address=0x%llx precision=0x%llx\n",
|
||||
i, (int)info.addressType,
|
||||
(unsigned long long)info.reportedAddress,
|
||||
(unsigned long long)info.addressPrecision);
|
||||
}
|
||||
for (uint32_t i = 0; i < fault_counts.vendorInfoCount; i++) {
|
||||
const auto& info = vendor_infos[i];
|
||||
GGML_LOG_CONT(" vendor fault %u: %s (code=0x%llx data=0x%llx)\n",
|
||||
i, info.description,
|
||||
(unsigned long long)info.vendorFaultCode,
|
||||
(unsigned long long)info.vendorFaultData);
|
||||
}
|
||||
}
|
||||
|
||||
struct vk_buffer_struct {
|
||||
vk::Buffer buffer = VK_NULL_HANDLE;
|
||||
vk::DeviceMemory device_memory = VK_NULL_HANDLE;
|
||||
@@ -2059,6 +2146,36 @@ static uint64_t ggml_vk_get_node_flops(const ggml_tensor * node) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ggml_vk_print_node_list(const ggml_cgraph * cgraph, int start, int end) {
|
||||
uint64_t total_flops = 0;
|
||||
int n_ops = 0;
|
||||
for (int j = start; j <= end && j < cgraph->n_nodes; j++) {
|
||||
uint64_t flops = ggml_vk_get_node_flops(cgraph->nodes[j]);
|
||||
total_flops += flops;
|
||||
n_ops++;
|
||||
if (flops > 0) {
|
||||
GGML_LOG_CONT(" node %d: %s (%s) [%.2f GFLOP]\n",
|
||||
j, cgraph->nodes[j]->name, ggml_op_name(cgraph->nodes[j]->op),
|
||||
flops / 1e9);
|
||||
} else {
|
||||
GGML_LOG_CONT(" node %d: %s (%s)\n",
|
||||
j, cgraph->nodes[j]->name, ggml_op_name(cgraph->nodes[j]->op));
|
||||
}
|
||||
}
|
||||
GGML_LOG_CONT(" total: %d ops, %.2f GFLOP\n", n_ops, total_flops / 1e9);
|
||||
}
|
||||
|
||||
static void ggml_vk_print_device_lost_info(const vk_device& device) {
|
||||
ggml_vk_print_device_fault_info(device);
|
||||
if (device->serialize_submissions && device->diag_cgraph != nullptr && device->diag_prev_start >= 0) {
|
||||
GGML_LOG_ERROR("ggml_vulkan: device lost on %s, likely caused by previous submission (nodes %d to %d):\n",
|
||||
device->name.c_str(), device->diag_prev_start, device->diag_prev_end);
|
||||
ggml_vk_print_node_list(device->diag_cgraph, device->diag_prev_start, device->diag_prev_end);
|
||||
} else {
|
||||
GGML_LOG_ERROR("ggml_vulkan: device lost on %s\n", device->name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
class vk_perf_logger {
|
||||
public:
|
||||
void print_timings(bool force = false) {
|
||||
@@ -2471,17 +2588,27 @@ static void ggml_vk_wait_for_fence(ggml_backend_vk_context * ctx) {
|
||||
// Use waitForFences while most of the graph executes. Hopefully the CPU can sleep
|
||||
// during this wait.
|
||||
if (ctx->almost_ready_fence_pending) {
|
||||
VK_CHECK(ctx->device->device.waitForFences({ ctx->almost_ready_fence }, true, UINT64_MAX), "almost_ready_fence");
|
||||
VK_CHECK(ctx->device->device.waitForFences({ ctx->almost_ready_fence }, true, UINT64_MAX), "almost_ready_fence", ctx->device);
|
||||
ctx->device->device.resetFences({ ctx->almost_ready_fence });
|
||||
ctx->almost_ready_fence_pending = false;
|
||||
}
|
||||
|
||||
// Spin (w/pause) waiting for the graph to finish executing.
|
||||
vk::Result result;
|
||||
while ((result = ctx->device->device.getFenceStatus(ctx->fence)) != vk::Result::eSuccess) {
|
||||
for (;;) {
|
||||
try {
|
||||
result = ctx->device->device.getFenceStatus(ctx->fence);
|
||||
} catch (vk::DeviceLostError &) {
|
||||
ggml_vk_print_device_lost_info(ctx->device);
|
||||
GGML_LOG_ERROR("ggml_vulkan: getFenceStatus at %s:%d\n", __FILE__, __LINE__);
|
||||
throw;
|
||||
}
|
||||
if (result == vk::Result::eSuccess) {
|
||||
break;
|
||||
}
|
||||
if (result != vk::Result::eNotReady) {
|
||||
fprintf(stderr, "ggml_vulkan: error %s at %s:%d\n", to_string(result).c_str(), __FILE__, __LINE__);
|
||||
exit(1);
|
||||
GGML_LOG_ERROR("ggml_vulkan: error %s at %s:%d\n", to_string(result).c_str(), __FILE__, __LINE__);
|
||||
throw vk::SystemError(vk::make_error_code(result), "ggml_vulkan: getFenceStatus");
|
||||
}
|
||||
for (uint32_t i = 0; i < 100; ++i) {
|
||||
YIELD();
|
||||
@@ -3172,6 +3299,7 @@ static std::unique_ptr<vk_queue> ggml_vk_create_queue(vk_device& device, uint32_
|
||||
}
|
||||
|
||||
h->queue = device->device.getQueue2(queue_info2);
|
||||
h->device = device;
|
||||
q->handle = h;
|
||||
|
||||
q->cmd_pool.init(device, q.get());
|
||||
@@ -6117,6 +6245,8 @@ static vk_device ggml_vk_get_device(size_t idx) {
|
||||
#endif
|
||||
} else if (strcmp(VK_KHR_INTERNALLY_SYNCHRONIZED_QUEUES_EXTENSION_NAME, properties.extensionName) == 0) {
|
||||
internally_sync_support = true;
|
||||
} else if (strcmp("VK_EXT_device_fault", properties.extensionName) == 0) {
|
||||
device->device_fault = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6471,8 +6601,18 @@ static vk_device ggml_vk_get_device(size_t idx) {
|
||||
}
|
||||
#endif
|
||||
|
||||
VkPhysicalDeviceFaultFeaturesEXT fault_features {};
|
||||
fault_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT;
|
||||
if (device->device_fault) {
|
||||
last_struct->pNext = (VkBaseOutStructure *)&fault_features;
|
||||
last_struct = (VkBaseOutStructure *)&fault_features;
|
||||
device_extensions.push_back("VK_EXT_device_fault");
|
||||
}
|
||||
|
||||
vkGetPhysicalDeviceFeatures2(device->physical_device, &device_features2);
|
||||
|
||||
device->device_fault = device->device_fault && fault_features.deviceFault;
|
||||
|
||||
device->has_internally_synchronized_queues = internally_synchronized_queues_features.internallySynchronizedQueues;
|
||||
|
||||
// Build queue create infos only after querying whether internally synchronized queues are enabled.
|
||||
@@ -6771,6 +6911,11 @@ static vk_device ggml_vk_get_device(size_t idx) {
|
||||
device_create_info.setPNext(&device_features2);
|
||||
device->device = device->physical_device.createDevice(device_create_info);
|
||||
|
||||
if (device->device_fault) {
|
||||
device->pfn_vkGetDeviceFaultInfoEXT = (PFN_vkGetDeviceFaultInfoEXT)
|
||||
vkGetDeviceProcAddr(device->device, "vkGetDeviceFaultInfoEXT");
|
||||
}
|
||||
|
||||
// Queues
|
||||
device->compute_queue = ggml_vk_create_queue(device, compute_queue_family_index, 0, { vk::PipelineStageFlagBits::eComputeShader | vk::PipelineStageFlagBits::eTransfer }, false);
|
||||
|
||||
@@ -6893,6 +7038,8 @@ static vk_device ggml_vk_get_device(size_t idx) {
|
||||
|
||||
device->idx = idx;
|
||||
|
||||
device->serialize_submissions = getenv("GGML_VK_SERIALIZE_SUBMISSIONS") != nullptr;
|
||||
|
||||
device->disable_fusion = getenv("GGML_VK_DISABLE_FUSION") != nullptr;
|
||||
|
||||
device->add_rms_fusion = !device->disable_fusion &&
|
||||
@@ -8319,7 +8466,7 @@ static void ggml_vk_buffer_write_2d(vk_buffer& dst, size_t offset, const void *
|
||||
}
|
||||
|
||||
ggml_vk_submit(subctx, dst->device->fence);
|
||||
VK_CHECK(dst->device->device.waitForFences({ dst->device->fence }, true, UINT64_MAX), "vk_buffer_write_2d waitForFences");
|
||||
VK_CHECK(dst->device->device.waitForFences({ dst->device->fence }, true, UINT64_MAX), "vk_buffer_write_2d waitForFences", dst->device);
|
||||
dst->device->device.resetFences({ dst->device->fence });
|
||||
ggml_vk_queue_command_pools_cleanup(dst->device);
|
||||
}
|
||||
@@ -8431,7 +8578,7 @@ static void ggml_vk_buffer_read_2d(vk_buffer& src, size_t offset, void * dst, si
|
||||
ggml_vk_ctx_end(subctx);
|
||||
ggml_vk_submit(subctx, src->device->fence);
|
||||
VK_CHECK(src->device->device.waitForFences({ src->device->fence }, true, UINT64_MAX),
|
||||
"vk_buffer_read_2d uma waitForFences");
|
||||
"vk_buffer_read_2d uma waitForFences", src->device);
|
||||
src->device->device.resetFences({ src->device->fence });
|
||||
ggml_vk_queue_command_pools_cleanup(src->device);
|
||||
|
||||
@@ -8452,7 +8599,7 @@ static void ggml_vk_buffer_read_2d(vk_buffer& src, size_t offset, void * dst, si
|
||||
ggml_vk_ctx_end(subctx);
|
||||
|
||||
ggml_vk_submit(subctx, src->device->fence);
|
||||
VK_CHECK(src->device->device.waitForFences({ src->device->fence }, true, UINT64_MAX), "vk_buffer_read_2d waitForFences");
|
||||
VK_CHECK(src->device->device.waitForFences({ src->device->fence }, true, UINT64_MAX), "vk_buffer_read_2d waitForFences", src->device);
|
||||
src->device->device.resetFences({ src->device->fence });
|
||||
ggml_vk_queue_command_pools_cleanup(src->device);
|
||||
|
||||
@@ -8487,7 +8634,7 @@ static void ggml_vk_buffer_copy(vk_buffer& dst, size_t dst_offset, vk_buffer& sr
|
||||
ggml_vk_buffer_copy_async(subctx, dst, dst_offset, src, src_offset, size);
|
||||
ggml_vk_ctx_end(subctx);
|
||||
ggml_vk_submit(subctx, src->device->fence);
|
||||
VK_CHECK(src->device->device.waitForFences({ src->device->fence }, true, UINT64_MAX), "vk_buffer_copy waitForFences");
|
||||
VK_CHECK(src->device->device.waitForFences({ src->device->fence }, true, UINT64_MAX), "vk_buffer_copy waitForFences", src->device);
|
||||
src->device->device.resetFences({ src->device->fence });
|
||||
ggml_vk_queue_command_pools_cleanup(src->device);
|
||||
} else {
|
||||
@@ -8531,7 +8678,7 @@ static void ggml_vk_buffer_memset(vk_buffer& dst, size_t offset, uint32_t c, siz
|
||||
ggml_vk_ctx_end(subctx);
|
||||
|
||||
ggml_vk_submit(subctx, dst->device->fence);
|
||||
VK_CHECK(dst->device->device.waitForFences({ dst->device->fence }, true, UINT64_MAX), "vk_memset waitForFences");
|
||||
VK_CHECK(dst->device->device.waitForFences({ dst->device->fence }, true, UINT64_MAX), "vk_memset waitForFences", dst->device);
|
||||
dst->device->device.resetFences({ dst->device->fence });
|
||||
ggml_vk_queue_command_pools_cleanup(dst->device);
|
||||
}
|
||||
@@ -14266,7 +14413,7 @@ static void ggml_vk_test_matmul(ggml_backend_vk_context * ctx, size_t m, size_t
|
||||
|
||||
auto begin = std::chrono::high_resolution_clock::now();
|
||||
ggml_vk_submit(subctx, ctx->fence);
|
||||
VK_CHECK(ctx->device->device.waitForFences({ ctx->fence }, true, UINT64_MAX), "ggml_vk_test_matmul waitForFences");
|
||||
VK_CHECK(ctx->device->device.waitForFences({ ctx->fence }, true, UINT64_MAX), "ggml_vk_test_matmul waitForFences", ctx->device);
|
||||
ctx->device->device.resetFences({ ctx->fence });
|
||||
ggml_vk_queue_command_pools_cleanup(ctx->device);
|
||||
|
||||
@@ -14468,7 +14615,7 @@ static void ggml_vk_test_dequant(ggml_backend_vk_context * ctx, size_t ne, ggml_
|
||||
auto begin = std::chrono::high_resolution_clock::now();
|
||||
|
||||
ggml_vk_submit(subctx, ctx->fence);
|
||||
VK_CHECK(ctx->device->device.waitForFences({ ctx->fence }, true, UINT64_MAX), "ggml_vk_test_dequant waitForFences");
|
||||
VK_CHECK(ctx->device->device.waitForFences({ ctx->fence }, true, UINT64_MAX), "ggml_vk_test_dequant waitForFences", ctx->device);
|
||||
ctx->device->device.resetFences({ ctx->fence });
|
||||
ggml_vk_queue_command_pools_cleanup(ctx->device);
|
||||
|
||||
@@ -14754,7 +14901,7 @@ static void ggml_vk_test_dequant_matmul(ggml_backend_vk_context * ctx, size_t m,
|
||||
auto begin = std::chrono::high_resolution_clock::now();
|
||||
|
||||
ggml_vk_submit(subctx, ctx->fence);
|
||||
VK_CHECK(ctx->device->device.waitForFences({ ctx->fence }, true, UINT64_MAX), "ggml_vk_test_dequant waitForFences");
|
||||
VK_CHECK(ctx->device->device.waitForFences({ ctx->fence }, true, UINT64_MAX), "ggml_vk_test_dequant waitForFences", ctx->device);
|
||||
ctx->device->device.resetFences({ ctx->fence });
|
||||
ggml_vk_queue_command_pools_cleanup(ctx->device);
|
||||
|
||||
@@ -15553,7 +15700,9 @@ static void ggml_vk_compute_forward(ggml_backend_vk_context * ctx, ggml_cgraph *
|
||||
memset(mset.dst, mset.val, mset.n);
|
||||
}
|
||||
|
||||
if (almost_ready && !ctx->almost_ready_fence_pending) {
|
||||
if (ctx->device->serialize_submissions) {
|
||||
ggml_vk_submit(subctx, ctx->fence);
|
||||
} else if (almost_ready && !ctx->almost_ready_fence_pending) {
|
||||
ggml_vk_submit(subctx, ctx->almost_ready_fence);
|
||||
ctx->almost_ready_fence_pending = true;
|
||||
} else {
|
||||
@@ -16164,12 +16313,20 @@ static void ggml_vk_synchronize(ggml_backend_vk_context * ctx) {
|
||||
memcpy(cpy.dst, cpy.src, cpy.n);
|
||||
}
|
||||
|
||||
ggml_vk_submit(compute_ctx, {});
|
||||
if (ctx->device->serialize_submissions) {
|
||||
ggml_vk_submit(compute_ctx, ctx->fence);
|
||||
VK_CHECK(ctx->device->device.waitForFences({ ctx->fence }, true, UINT64_MAX), "synchronize waitForFences", ctx->device);
|
||||
ctx->device->device.resetFences({ ctx->fence });
|
||||
} else {
|
||||
ggml_vk_submit(compute_ctx, {});
|
||||
}
|
||||
ctx->submit_pending = true;
|
||||
}
|
||||
|
||||
if (ctx->submit_pending) {
|
||||
if (ctx->device->async_use_transfer_queue && ctx->transfer_semaphore_last_submitted < ctx->transfer_semaphore.value) {
|
||||
if (ctx->device->serialize_submissions) {
|
||||
ctx->submit_pending = false;
|
||||
} else if (ctx->device->async_use_transfer_queue && ctx->transfer_semaphore_last_submitted < ctx->transfer_semaphore.value) {
|
||||
vk::TimelineSemaphoreSubmitInfo tl_info{
|
||||
1, &ctx->transfer_semaphore.value,
|
||||
0, nullptr,
|
||||
@@ -16186,7 +16343,9 @@ static void ggml_vk_synchronize(ggml_backend_vk_context * ctx) {
|
||||
} else {
|
||||
ctx->device->compute_queue->handle->submit({}, ctx->fence);
|
||||
}
|
||||
ggml_vk_wait_for_fence(ctx);
|
||||
if (!ctx->device->serialize_submissions) {
|
||||
ggml_vk_wait_for_fence(ctx);
|
||||
}
|
||||
ctx->submit_pending = false;
|
||||
if (cmd_buf) {
|
||||
cmd_buf->in_use = false;
|
||||
@@ -16758,6 +16917,10 @@ static ggml_status ggml_backend_vk_graph_compute(ggml_backend_t backend, ggml_cg
|
||||
VK_LOG_DEBUG("ggml_backend_vk_graph_compute(" << cgraph->n_nodes << " nodes)");
|
||||
ggml_backend_vk_context * ctx = (ggml_backend_vk_context *)backend->context;
|
||||
|
||||
ctx->device->diag_cgraph = nullptr;
|
||||
ctx->device->diag_prev_start = -1;
|
||||
ctx->device->diag_prev_end = -1;
|
||||
|
||||
if (vk_instance.debug_utils_support) {
|
||||
vk::DebugUtilsLabelEXT dul = {};
|
||||
dul.pLabelName = "ggml_backend_vk_graph_compute";
|
||||
@@ -16849,6 +17012,36 @@ static ggml_status ggml_backend_vk_graph_compute(ggml_backend_t backend, ggml_cg
|
||||
}
|
||||
uint64_t flops_per_submit = std::min(flops_cap, ctx->last_total_flops / 40u);
|
||||
|
||||
auto const submit_after = [&](int start, int end) {
|
||||
if (ctx->device->serialize_submissions) {
|
||||
try {
|
||||
auto res = ctx->device->device.waitForFences({ ctx->fence }, true, UINT64_MAX);
|
||||
if (res != vk::Result::eSuccess) {
|
||||
GGML_LOG_ERROR("ggml_vulkan: waitForFences error during serialized submission\n");
|
||||
throw vk::SystemError(vk::make_error_code(res), "ggml_vulkan: waitForFences during serialized submission");
|
||||
}
|
||||
} catch (vk::DeviceLostError &) {
|
||||
ggml_vk_print_device_fault_info(ctx->device);
|
||||
GGML_LOG_ERROR("ggml_vulkan: device lost on %s waiting for submission (nodes %d to %d):\n",
|
||||
ctx->device->name.c_str(), start, end);
|
||||
ggml_vk_print_node_list(cgraph, start, end);
|
||||
throw;
|
||||
}
|
||||
ctx->device->device.resetFences({ ctx->fence });
|
||||
ctx->submit_pending = false;
|
||||
ctx->device->diag_cgraph = cgraph;
|
||||
ctx->device->diag_prev_start = start;
|
||||
ctx->device->diag_prev_end = end;
|
||||
}
|
||||
first_node_in_batch = true;
|
||||
submitted_nodes = 0;
|
||||
batch_flops = 0;
|
||||
if (submit_count < 3) {
|
||||
flops_per_submit *= 2;
|
||||
}
|
||||
submit_count++;
|
||||
};
|
||||
|
||||
for (int i = 0; i < cgraph->n_nodes; i++) {
|
||||
if (first_node_in_batch) {
|
||||
submit_node_idx = i;
|
||||
@@ -16856,8 +17049,20 @@ static ggml_status ggml_backend_vk_graph_compute(ggml_backend_t backend, ggml_cg
|
||||
|
||||
{
|
||||
auto node_flops = ggml_vk_get_node_flops(cgraph->nodes[i]);
|
||||
batch_flops += node_flops;
|
||||
total_flops += node_flops;
|
||||
|
||||
// Flush the current batch before recording a node that would push it over the flop threshold
|
||||
if (flops_per_submit != 0 && submitted_nodes > 0 && batch_flops + node_flops >= flops_per_submit) {
|
||||
vk_context flush_ctx = ggml_vk_get_compute_ctx(ctx);
|
||||
ggml_vk_ctx_end(flush_ctx);
|
||||
flush_ctx->exit_tensor_idx = -1;
|
||||
ctx->compute_ctx.reset();
|
||||
ggml_vk_compute_forward(ctx, cgraph, cgraph->nodes[submit_node_idx], submit_node_idx, false);
|
||||
submit_after(submit_node_idx, i - 1);
|
||||
submit_node_idx = i;
|
||||
}
|
||||
|
||||
batch_flops += node_flops;
|
||||
}
|
||||
|
||||
// op_srcs_fused_elementwise indicates whether an op's srcs all contribute to
|
||||
@@ -17111,13 +17316,7 @@ static ggml_status ggml_backend_vk_graph_compute(ggml_backend_t backend, ggml_cg
|
||||
}
|
||||
|
||||
if (submit && enqueued) {
|
||||
first_node_in_batch = true;
|
||||
submitted_nodes = 0;
|
||||
batch_flops = 0;
|
||||
if (submit_count < 3) {
|
||||
flops_per_submit *= 2;
|
||||
}
|
||||
submit_count++;
|
||||
submit_after(submit_node_idx, i + (int)ctx->num_additional_fused_ops);
|
||||
}
|
||||
i += ctx->num_additional_fused_ops;
|
||||
ctx->num_additional_fused_ops = 0;
|
||||
@@ -17133,13 +17332,13 @@ static ggml_status ggml_backend_vk_graph_compute(ggml_backend_t backend, ggml_cg
|
||||
ggml_vk_ctx_end(compute_ctx);
|
||||
|
||||
ggml_vk_submit(compute_ctx, ctx->device->fence);
|
||||
VK_CHECK(ctx->device->device.waitForFences({ ctx->device->fence }, true, UINT64_MAX), "GGML_VULKAN_PERF waitForFences");
|
||||
VK_CHECK(ctx->device->device.waitForFences({ ctx->device->fence }, true, UINT64_MAX), "GGML_VULKAN_PERF waitForFences", ctx->device);
|
||||
ctx->device->device.resetFences({ ctx->device->fence });
|
||||
ctx->compute_ctx.reset();
|
||||
|
||||
// Get the results and pass them to the logger
|
||||
std::vector<uint64_t> timestamps(cgraph->n_nodes + 1);
|
||||
VK_CHECK(ctx->device->device.getQueryPoolResults(ctx->query_pool, 0, ctx->query_idx, (cgraph->n_nodes + 1)*sizeof(uint64_t), timestamps.data(), sizeof(uint64_t), vk::QueryResultFlagBits::e64 | vk::QueryResultFlagBits::eWait), "get timestamp results");
|
||||
VK_CHECK(ctx->device->device.getQueryPoolResults(ctx->query_pool, 0, ctx->query_idx, (cgraph->n_nodes + 1)*sizeof(uint64_t), timestamps.data(), sizeof(uint64_t), vk::QueryResultFlagBits::e64 | vk::QueryResultFlagBits::eWait), "get timestamp results", ctx->device);
|
||||
if (!vk_perf_logger_concurrent) {
|
||||
// Log each op separately
|
||||
for (int i = 1; i < ctx->query_idx; i++) {
|
||||
@@ -18366,7 +18565,7 @@ static void ggml_backend_vk_device_event_synchronize(ggml_backend_dev_t dev, ggm
|
||||
vk::Semaphore sem = vkev->tl_semaphore.s;
|
||||
uint64_t val = vkev->tl_semaphore.value;
|
||||
vk::SemaphoreWaitInfo swi{vk::SemaphoreWaitFlags{}, sem, val};
|
||||
VK_CHECK(device->device.waitSemaphores(swi, UINT64_MAX), "event_synchronize");
|
||||
VK_CHECK(device->device.waitSemaphores(swi, UINT64_MAX), "event_synchronize", device);
|
||||
|
||||
// Reset and move submitted events
|
||||
for (auto& event : vkev->events_submitted) {
|
||||
|
||||
@@ -3221,17 +3221,17 @@ class ggml_webgpu_shader_lib {
|
||||
auto push_type_defines = [&](const char * prefix, ggml_type type) {
|
||||
std::string s_prefix = prefix;
|
||||
if (type == GGML_TYPE_F32) {
|
||||
defines.push_back(s_prefix + "_F32");
|
||||
defines.push_back(s_prefix + "=f32");
|
||||
} else if (type == GGML_TYPE_F16) {
|
||||
defines.push_back(s_prefix + "_F16");
|
||||
defines.push_back(s_prefix + "=f16");
|
||||
} else {
|
||||
GGML_ABORT("Unsupported type for CONV_2D shader");
|
||||
}
|
||||
};
|
||||
|
||||
push_type_defines("WEIGHT", key.weight_type);
|
||||
push_type_defines("INPUT", key.input_type);
|
||||
push_type_defines("OUTPUT", key.output_type);
|
||||
push_type_defines("WEIGHT_TYPE", key.weight_type);
|
||||
push_type_defines("INPUT_TYPE", key.input_type);
|
||||
push_type_defines("OUTPUT_TYPE", key.output_type);
|
||||
|
||||
defines.push_back(std::string("WG_SIZE=") + std::to_string(context.max_wg_size));
|
||||
|
||||
@@ -3263,17 +3263,18 @@ class ggml_webgpu_shader_lib {
|
||||
auto push_type_defines = [&](const char * prefix, ggml_type type) {
|
||||
std::string s_prefix = prefix;
|
||||
if (type == GGML_TYPE_F32) {
|
||||
defines.push_back(s_prefix + "_F32");
|
||||
defines.push_back(s_prefix + "=f32");
|
||||
} else if (type == GGML_TYPE_F16) {
|
||||
defines.push_back(s_prefix + "_F16");
|
||||
defines.push_back(s_prefix + "=f16");
|
||||
} else {
|
||||
GGML_ABORT("Unsupported type for CONV_2D_DW shader");
|
||||
GGML_ABORT("Unsupported type for CONV_2D shader");
|
||||
}
|
||||
};
|
||||
|
||||
push_type_defines("WEIGHT", key.weight_type);
|
||||
push_type_defines("INPUT", key.input_type);
|
||||
push_type_defines("OUTPUT", key.output_type);
|
||||
push_type_defines("WEIGHT_TYPE", key.weight_type);
|
||||
push_type_defines("INPUT_TYPE", key.input_type);
|
||||
push_type_defines("OUTPUT_TYPE", key.output_type);
|
||||
|
||||
if (whcn) {
|
||||
defines.push_back("WHCN");
|
||||
}
|
||||
@@ -3304,16 +3305,16 @@ class ggml_webgpu_shader_lib {
|
||||
auto push_type_defines = [&](const char * prefix, ggml_type type) {
|
||||
std::string s_prefix = prefix;
|
||||
if (type == GGML_TYPE_F32) {
|
||||
defines.push_back(s_prefix + "_F32");
|
||||
defines.push_back(s_prefix + "=f32");
|
||||
} else if (type == GGML_TYPE_F16) {
|
||||
defines.push_back(s_prefix + "_F16");
|
||||
defines.push_back(s_prefix + "=f16");
|
||||
} else {
|
||||
GGML_ABORT("Unsupported type for IM2COL shader");
|
||||
}
|
||||
};
|
||||
|
||||
push_type_defines("INPUT", key.input_type);
|
||||
push_type_defines("OUTPUT", key.output_type);
|
||||
push_type_defines("INPUT_TYPE", key.input_type);
|
||||
push_type_defines("OUTPUT_TYPE", key.output_type);
|
||||
|
||||
defines.push_back(std::string("WG_SIZE=") + std::to_string(context.max_wg_size));
|
||||
|
||||
|
||||
@@ -930,7 +930,6 @@ static webgpu_encoded_op ggml_webgpu_solve_tri(webgpu_context & ctx,
|
||||
|
||||
(uint32_t) src1->ne[0],
|
||||
(uint32_t) dst->ne[2],
|
||||
(uint32_t) dst->ne[3],
|
||||
};
|
||||
|
||||
std::vector<wgpu::BindGroupEntry> entries = {
|
||||
@@ -1039,7 +1038,6 @@ static webgpu_encoded_op ggml_webgpu_conv_2d_dw(webgpu_context & ctx,
|
||||
|
||||
(uint32_t) ggml_nelements(dst),
|
||||
(uint32_t) dst->ne[2],
|
||||
(uint32_t) dst->ne[3],
|
||||
(uint32_t) dst->ne[0],
|
||||
(uint32_t) dst->ne[1],
|
||||
(uint32_t) src1->ne[0],
|
||||
@@ -1328,7 +1326,6 @@ static webgpu_encoded_op ggml_webgpu_ssm_scan(webgpu_context & ctx,
|
||||
(uint32_t) src0->ne[2],
|
||||
(uint32_t) src4->ne[1],
|
||||
(uint32_t) src1->ne[2],
|
||||
(uint32_t) src1->ne[3],
|
||||
(uint32_t) ggml_nelements(src1),
|
||||
};
|
||||
|
||||
@@ -1921,25 +1918,20 @@ static bool ggml_webgpu_flash_attn_use_vec_path(const webgpu_global_context & gl
|
||||
const ggml_tensor * K,
|
||||
const ggml_tensor * V) {
|
||||
const size_t storage_offset_alignment = global_ctx->capabilities.limits.minStorageBufferOffsetAlignment;
|
||||
const bool k_float_vec4_aligned = (K->type != GGML_TYPE_F16 && K->type != GGML_TYPE_F32) ||
|
||||
ggml_webgpu_flash_attn_float_vec4_aligned(K, storage_offset_alignment);
|
||||
const bool v_float_vec4_aligned = (V->type != GGML_TYPE_F16 && V->type != GGML_TYPE_F32) ||
|
||||
ggml_webgpu_flash_attn_float_vec4_aligned(V, storage_offset_alignment);
|
||||
const bool k_vec_type_supported =
|
||||
K->type == GGML_TYPE_F32 || K->type == GGML_TYPE_F16 || K->type == GGML_TYPE_Q4_0 || K->type == GGML_TYPE_Q8_0;
|
||||
const bool v_vec_type_supported =
|
||||
V->type == GGML_TYPE_F32 || V->type == GGML_TYPE_F16 || V->type == GGML_TYPE_Q4_0 || V->type == GGML_TYPE_Q8_0;
|
||||
const uint32_t k_vec_head_align = (K->type == GGML_TYPE_F32 || K->type == GGML_TYPE_F16) ?
|
||||
GGML_WEBGPU_FLASH_ATTN_TILE_KV_VEC_WIDTH :
|
||||
(uint32_t) ggml_blck_size(K->type);
|
||||
const uint32_t v_vec_head_align = (V->type == GGML_TYPE_F32 || V->type == GGML_TYPE_F16) ?
|
||||
GGML_WEBGPU_FLASH_ATTN_TILE_KV_VEC_WIDTH :
|
||||
(uint32_t) ggml_blck_size(V->type);
|
||||
const bool kv_vec_head_dims_aligned = Q->ne[0] % k_vec_head_align == 0 && V->ne[0] % v_vec_head_align == 0;
|
||||
|
||||
const bool k_float_vec4_aligned = (K->type != GGML_TYPE_F16 && K->type != GGML_TYPE_F32) ||
|
||||
ggml_webgpu_flash_attn_float_vec4_aligned(K, storage_offset_alignment);
|
||||
const bool v_float_vec4_aligned = (V->type != GGML_TYPE_F16 && V->type != GGML_TYPE_F32) ||
|
||||
ggml_webgpu_flash_attn_float_vec4_aligned(V, storage_offset_alignment);
|
||||
|
||||
const uint32_t k_vec_head_align =
|
||||
ggml_is_quantized(K->type) ? ggml_blck_size(K->type) : GGML_WEBGPU_FLASH_ATTN_TILE_KV_VEC_WIDTH;
|
||||
const uint32_t v_vec_head_align =
|
||||
ggml_is_quantized(V->type) ? ggml_blck_size(V->type) : GGML_WEBGPU_FLASH_ATTN_TILE_KV_VEC_WIDTH;
|
||||
const bool kv_vec_head_dims_aligned = Q->ne[0] % k_vec_head_align == 0 && V->ne[0] % v_vec_head_align == 0;
|
||||
|
||||
return global_ctx->capabilities.supports_subgroups && (Q->ne[1] < GGML_WEBGPU_FLASH_ATTN_VEC_MAX_SEQ_LEN) &&
|
||||
kv_vec_head_dims_aligned && k_vec_type_supported && v_vec_type_supported && k_float_vec4_aligned &&
|
||||
v_float_vec4_aligned;
|
||||
kv_vec_head_dims_aligned && k_float_vec4_aligned && v_float_vec4_aligned;
|
||||
}
|
||||
|
||||
static ggml_webgpu_flash_attn_op ggml_webgpu_flash_attn_prepare(webgpu_context & ctx,
|
||||
@@ -2514,7 +2506,6 @@ static webgpu_encoded_op ggml_webgpu_concat(webgpu_context & ctx,
|
||||
(uint32_t) dst->ne[0],
|
||||
(uint32_t) dst->ne[1],
|
||||
(uint32_t) dst->ne[2],
|
||||
(uint32_t) dst->ne[3],
|
||||
dim,
|
||||
(uint32_t) src0->ne[dim] };
|
||||
|
||||
@@ -2610,7 +2601,6 @@ static std::optional<webgpu_encoded_op> ggml_webgpu_rms_norm_mul(webgpu_context
|
||||
(uint32_t) dst->ne[0],
|
||||
(uint32_t) dst->ne[1],
|
||||
(uint32_t) dst->ne[2],
|
||||
(uint32_t) dst->ne[3],
|
||||
ggml_webgpu_u32_from_f32(ggml_get_op_params_f32(rn_dst, 0)) // epsilon, treated as f32 in the shader
|
||||
};
|
||||
|
||||
@@ -2666,7 +2656,6 @@ static webgpu_encoded_op ggml_webgpu_row_norm(webgpu_context & ctx, ggml_tensor
|
||||
(uint32_t) src->ne[0],
|
||||
(uint32_t) src->ne[1],
|
||||
(uint32_t) src->ne[2],
|
||||
(uint32_t) src->ne[3],
|
||||
ggml_webgpu_u32_from_f32(ggml_get_op_params_f32(dst, 0)) // epsilon, treated as f32 in the shader
|
||||
};
|
||||
|
||||
@@ -2925,7 +2914,6 @@ static webgpu_encoded_op ggml_webgpu_soft_max(webgpu_context & ctx,
|
||||
(uint32_t) (dst->nb[1] / ggml_type_size(dst->type)),
|
||||
(uint32_t) (dst->nb[2] / ggml_type_size(dst->type)),
|
||||
(uint32_t) (dst->nb[3] / ggml_type_size(dst->type)),
|
||||
(uint32_t) ggml_nelements(dst),
|
||||
(uint32_t) src0->ne[0],
|
||||
(uint32_t) src0->ne[1],
|
||||
(uint32_t) src0->ne[2],
|
||||
|
||||
@@ -18,7 +18,6 @@ struct Params {
|
||||
ne0: u32,
|
||||
ne1: u32,
|
||||
ne2: u32,
|
||||
ne3: u32,
|
||||
|
||||
dim: u32,
|
||||
src0_nedim: u32
|
||||
|
||||
@@ -2,25 +2,11 @@
|
||||
enable f16;
|
||||
|
||||
@group(0) @binding(0)
|
||||
#if defined(WEIGHT_F32)
|
||||
var<storage, read_write> weights: array<f32>;
|
||||
#elif defined(WEIGHT_F16)
|
||||
var<storage, read_write> weights: array<f16>;
|
||||
#endif
|
||||
|
||||
var<storage, read_write> weights: array<WEIGHT_TYPE>;
|
||||
@group(0) @binding(1)
|
||||
#if defined(INPUT_F32)
|
||||
var<storage, read_write> input: array<f32>;
|
||||
#elif defined(INPUT_F16)
|
||||
var<storage, read_write> input: array<f16>;
|
||||
#endif
|
||||
|
||||
var<storage, read_write> input: array<INPUT_TYPE>;
|
||||
@group(0) @binding(2)
|
||||
#if defined(OUTPUT_F32)
|
||||
var<storage, read_write> output: array<f32>;
|
||||
#elif defined(OUTPUT_F16)
|
||||
var<storage, read_write> output: array<f16>;
|
||||
#endif
|
||||
var<storage, read_write> output: array<OUTPUT_TYPE>;
|
||||
|
||||
struct Params {
|
||||
offset_w: u32,
|
||||
@@ -50,30 +36,6 @@ struct Params {
|
||||
@group(0) @binding(3)
|
||||
var<uniform> params: Params;
|
||||
|
||||
fn load_weight(idx: u32) -> f32 {
|
||||
#if defined(WEIGHT_F32)
|
||||
return weights[idx];
|
||||
#elif defined(WEIGHT_F16)
|
||||
return f32(weights[idx]);
|
||||
#endif
|
||||
}
|
||||
|
||||
fn load_input(idx: u32) -> f32 {
|
||||
#if defined(INPUT_F32)
|
||||
return input[idx];
|
||||
#elif defined(INPUT_F16)
|
||||
return f32(input[idx]);
|
||||
#endif
|
||||
}
|
||||
|
||||
fn store_output(idx: u32, val: f32) {
|
||||
#if defined(OUTPUT_F32)
|
||||
output[idx] = val;
|
||||
#elif defined(OUTPUT_F16)
|
||||
output[idx] = f16(val);
|
||||
#endif
|
||||
}
|
||||
|
||||
fn ceil_div_u32(x: u32, y: u32) -> u32 {
|
||||
return (x + y - 1) / y;
|
||||
}
|
||||
@@ -136,7 +98,7 @@ fn main(
|
||||
// entire receptive field is out of bounds
|
||||
if (kw_begin >= kw_end || kh_begin >= kh_end) {
|
||||
let out_idx = params.offset_o + ow * params.so0 + oh * params.so1 + oc * params.so2 + n * params.so3;
|
||||
store_output(out_idx, 0.0);
|
||||
output[out_idx] = OUTPUT_TYPE(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -155,11 +117,11 @@ fn main(
|
||||
let iw = u32(ow_base + i32(kw * params.d0));
|
||||
let w_idx = w_row_base + kw * params.sw0;
|
||||
let in_idx = in_row_base + iw * params.si0;
|
||||
sum += load_weight(w_idx) * load_input(in_idx);
|
||||
sum += f32(weights[w_idx]) * f32(input[in_idx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let out_idx = params.offset_o + ow * params.so0 + oh * params.so1 + oc * params.so2 + n * params.so3;
|
||||
store_output(out_idx, sum);
|
||||
output[out_idx] = OUTPUT_TYPE(sum);
|
||||
}
|
||||
|
||||
@@ -6,25 +6,11 @@ enable f16;
|
||||
// weight (src0) is [KW,KH,1,C]; output matches the input layout.
|
||||
|
||||
@group(0) @binding(0)
|
||||
#if defined(WEIGHT_F32)
|
||||
var<storage, read_write> weights: array<f32>;
|
||||
#elif defined(WEIGHT_F16)
|
||||
var<storage, read_write> weights: array<f16>;
|
||||
#endif
|
||||
|
||||
var<storage, read_write> weights: array<WEIGHT_TYPE>;
|
||||
@group(0) @binding(1)
|
||||
#if defined(INPUT_F32)
|
||||
var<storage, read_write> input: array<f32>;
|
||||
#elif defined(INPUT_F16)
|
||||
var<storage, read_write> input: array<f16>;
|
||||
#endif
|
||||
|
||||
var<storage, read_write> input: array<INPUT_TYPE>;
|
||||
@group(0) @binding(2)
|
||||
#if defined(OUTPUT_F32)
|
||||
var<storage, read_write> output: array<f32>;
|
||||
#elif defined(OUTPUT_F16)
|
||||
var<storage, read_write> output: array<f16>;
|
||||
#endif
|
||||
var<storage, read_write> output: array<OUTPUT_TYPE>;
|
||||
|
||||
struct Params {
|
||||
offset_w: u32,
|
||||
@@ -33,7 +19,6 @@ struct Params {
|
||||
|
||||
ne: u32,
|
||||
channels: u32,
|
||||
batches: u32,
|
||||
dst_w: u32, dst_h: u32,
|
||||
src_w: u32, src_h: u32,
|
||||
knl_w: u32, knl_h: u32,
|
||||
@@ -46,28 +31,6 @@ struct Params {
|
||||
@group(0) @binding(3)
|
||||
var<uniform> params: Params;
|
||||
|
||||
fn load_weight(idx: u32) -> f32 {
|
||||
#if defined(WEIGHT_F32)
|
||||
return weights[idx];
|
||||
#elif defined(WEIGHT_F16)
|
||||
return f32(weights[idx]);
|
||||
#endif
|
||||
}
|
||||
fn load_input(idx: u32) -> f32 {
|
||||
#if defined(INPUT_F32)
|
||||
return input[idx];
|
||||
#elif defined(INPUT_F16)
|
||||
return f32(input[idx]);
|
||||
#endif
|
||||
}
|
||||
fn store_output(idx: u32, val: f32) {
|
||||
#if defined(OUTPUT_F32)
|
||||
output[idx] = val;
|
||||
#elif defined(OUTPUT_F16)
|
||||
output[idx] = f16(val);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(WHCN)
|
||||
// Input/output/kernel contiguous in [W, H, C, N] order (kernel [KW,KH,C]).
|
||||
fn conv_2d_dw(idx: u32) -> f32 {
|
||||
@@ -89,8 +52,8 @@ fn conv_2d_dw(idx: u32) -> f32 {
|
||||
for (var kx: u32 = 0u; kx < params.knl_w; kx += 1u) {
|
||||
let src_x = i32(dst_x) * params.stride_x + i32(kx) * params.dilation_x - params.pad_x;
|
||||
if (src_x < 0 || src_x >= i32(params.src_w)) { continue; }
|
||||
let v = load_input(src_i + u32(src_y) * params.src_w + u32(src_x));
|
||||
let k = load_weight(knl_i + ky * params.knl_w + kx);
|
||||
let v = f32(input[src_i + u32(src_y) * params.src_w + u32(src_x)]);
|
||||
let k = f32(weights[knl_i + ky * params.knl_w + kx]);
|
||||
sum += v * k;
|
||||
}
|
||||
}
|
||||
@@ -117,8 +80,8 @@ fn conv_2d_dw(idx: u32) -> f32 {
|
||||
for (var kx: u32 = 0u; kx < params.knl_w; kx += 1u) {
|
||||
let src_x = i32(dst_x) * params.stride_x + i32(kx) * params.dilation_x - params.pad_x;
|
||||
if (src_x < 0 || src_x >= i32(params.src_w)) { continue; }
|
||||
let v = load_input(src_i + u32(src_y) * src_row + u32(src_x) * params.channels + c);
|
||||
let k = load_weight(params.offset_w + ky * knl_row + kx * params.channels + c);
|
||||
let v = f32(input[src_i + u32(src_y) * src_row + u32(src_x) * params.channels + c]);
|
||||
let k = f32(weights[params.offset_w + ky * knl_row + kx * params.channels + c]);
|
||||
sum += v * k;
|
||||
}
|
||||
}
|
||||
@@ -133,5 +96,5 @@ fn main(
|
||||
) {
|
||||
let idx = gid.x + (num_wg.x * u32(WG_SIZE)) * gid.y;
|
||||
if (idx >= params.ne) { return; }
|
||||
store_output(params.offset_o + idx, conv_2d_dw(idx));
|
||||
output[params.offset_o + idx] = OUTPUT_TYPE(conv_2d_dw(idx));
|
||||
}
|
||||
|
||||
@@ -7,32 +7,18 @@ enable chromium_experimental_subgroup_matrix;
|
||||
#define BYTE_HELPERS
|
||||
#include "common_decls.tmpl"
|
||||
|
||||
#ifdef K_F32
|
||||
#define K_TYPE f32
|
||||
#elif defined(K_Q4_0) || defined(K_Q8_0)
|
||||
#define K_TYPE u32
|
||||
#else
|
||||
#define K_TYPE f16
|
||||
#endif
|
||||
|
||||
#ifdef V_F32
|
||||
#define V_TYPE f32
|
||||
#elif defined(V_Q4_0) || defined(V_Q8_0)
|
||||
#define V_TYPE u32
|
||||
#else
|
||||
#define V_TYPE f16
|
||||
#endif
|
||||
#define FLASH_ATTN_SCALAR_KV
|
||||
#include "flash_attn_decls.tmpl"
|
||||
|
||||
// Default values
|
||||
// The actual values are defined in shader-lib.
|
||||
#define HEAD_DIM_QK 64
|
||||
#define HEAD_DIM_V 64
|
||||
|
||||
// The number of rows/columns/k in a subgroup matrix. MxK * KxN = MxN
|
||||
// Note that the "K" here does not correspond to the K in attention's Q/K/V, it's just the common dimension.
|
||||
#define SG_MAT_M 8
|
||||
#define SG_MAT_N 8
|
||||
#define SG_MAT_K 8
|
||||
|
||||
// Each workgroup processes one subgroup matrix of Q rows
|
||||
#define Q_TILE SG_MAT_M
|
||||
#define KV_TILE 16
|
||||
@@ -41,104 +27,13 @@ enable chromium_experimental_subgroup_matrix;
|
||||
// Number of subgroup-matrix-width blocks that span the KV tile. SG_MAT_N must divide KV_TILE.
|
||||
#define KV_BLOCKS (KV_TILE / SG_MAT_N)
|
||||
|
||||
struct Params {
|
||||
offset_q: u32,
|
||||
offset_k: u32,
|
||||
offset_v: u32,
|
||||
offset_mask: u32,
|
||||
offset_sinks: u32,
|
||||
offset_dst: u32,
|
||||
|
||||
// shapes of Q/K/V
|
||||
n_heads: u32,
|
||||
seq_len_q: u32,
|
||||
seq_len_kv: u32,
|
||||
|
||||
// strides (in elements)
|
||||
stride_q1: u32,
|
||||
stride_q2: u32,
|
||||
stride_q3: u32,
|
||||
stride_k1: u32,
|
||||
stride_k2: u32,
|
||||
stride_k3: u32,
|
||||
stride_v1: u32,
|
||||
stride_v2: u32,
|
||||
stride_v3: u32,
|
||||
stride_mask3: u32,
|
||||
|
||||
// repeat factors for K/V, e.g., MHA vs. MQA vs. GQA
|
||||
q_per_kv: u32,
|
||||
|
||||
// softmax params
|
||||
scale: f32,
|
||||
max_bias: f32,
|
||||
logit_softcap: f32,
|
||||
n_head_log2: f32,
|
||||
m0: f32,
|
||||
m1: f32,
|
||||
};
|
||||
|
||||
@group(0) @binding(0) var<storage, read_write> Q: array<f32>;
|
||||
#ifdef KV_OVERLAP
|
||||
@group(0) @binding(1) var<storage, read_write> K: array<K_TYPE>;
|
||||
#define V K
|
||||
#else
|
||||
@group(0) @binding(1) var<storage, read_write> K: array<K_TYPE>;
|
||||
@group(0) @binding(2) var<storage, read_write> V: array<V_TYPE>;
|
||||
#endif
|
||||
|
||||
#if defined(MASK) && defined(SINKS)
|
||||
#ifdef KV_OVERLAP
|
||||
@group(0) @binding(2) var<storage, read_write> mask: array<f16>;
|
||||
@group(0) @binding(3) var<storage, read_write> sinks: array<f32>;
|
||||
#define DST_BINDING 4
|
||||
#define PARAMS_BINDING 5
|
||||
#else
|
||||
@group(0) @binding(3) var<storage, read_write> mask: array<f16>;
|
||||
@group(0) @binding(4) var<storage, read_write> sinks: array<f32>;
|
||||
#define DST_BINDING 5
|
||||
#define PARAMS_BINDING 6
|
||||
#endif
|
||||
#elif defined(MASK)
|
||||
#ifdef KV_OVERLAP
|
||||
@group(0) @binding(2) var<storage, read_write> mask: array<f16>;
|
||||
#define DST_BINDING 3
|
||||
#define PARAMS_BINDING 4
|
||||
#else
|
||||
@group(0) @binding(3) var<storage, read_write> mask: array<f16>;
|
||||
#define DST_BINDING 4
|
||||
#define PARAMS_BINDING 5
|
||||
#endif
|
||||
#elif defined(SINKS)
|
||||
#ifdef KV_OVERLAP
|
||||
@group(0) @binding(2) var<storage, read_write> sinks: array<f32>;
|
||||
#define DST_BINDING 3
|
||||
#define PARAMS_BINDING 4
|
||||
#else
|
||||
@group(0) @binding(3) var<storage, read_write> sinks: array<f32>;
|
||||
#define DST_BINDING 4
|
||||
#define PARAMS_BINDING 5
|
||||
#endif
|
||||
#else
|
||||
#ifdef KV_OVERLAP
|
||||
#define DST_BINDING 2
|
||||
#define PARAMS_BINDING 3
|
||||
#else
|
||||
#define DST_BINDING 3
|
||||
#define PARAMS_BINDING 4
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@group(0) @binding(DST_BINDING) var<storage, read_write> dst: array<vec4<f32>>;
|
||||
@group(0) @binding(PARAMS_BINDING) var<uniform> params: Params;
|
||||
|
||||
// Just a very small float value.
|
||||
const FLOAT_MIN: f32 = -1.0e9;
|
||||
|
||||
// The number of Q rows processed per workgroup
|
||||
var<workgroup> q_shmem: array<f16, Q_TILE * HEAD_DIM_QK>;
|
||||
|
||||
#if !defined(K_DIRECT) || !defined(V_DIRECT)
|
||||
#define STAGING_SHMEM kv_shmem
|
||||
#define STAGING_OUT_TYPE f16
|
||||
#include "flash_attn_staging.tmpl"
|
||||
const kv_shmem_size = KV_TILE * max(HEAD_DIM_QK, HEAD_DIM_V);
|
||||
// we can reuse the same shmem for K and V since we only need one at a time
|
||||
var<workgroup> kv_shmem: array<f16, kv_shmem_size>;
|
||||
@@ -175,50 +70,6 @@ fn calc_softmax_term(kv_idx: u32, q_tile_row: u32, slope: f32) -> f32 {
|
||||
return v;
|
||||
}
|
||||
|
||||
fn load_f32x4(buf: ptr<storage, array<vec4<f32>>, read_write>, scalar_index: u32) -> vec4<f32> {
|
||||
return (*buf)[scalar_index >> 2u];
|
||||
}
|
||||
|
||||
fn load_kx4(buf: ptr<storage, array<vec4<K_TYPE>>, read_write>, scalar_index: u32) -> vec4<K_TYPE> {
|
||||
return (*buf)[scalar_index >> 2u];
|
||||
}
|
||||
|
||||
#if !defined(K_DIRECT) || !defined(V_DIRECT)
|
||||
#define QUANT_SHMEM kv_shmem
|
||||
#define QUANT_OUT_TYPE f16
|
||||
#include "flash_attn_quant_staging.tmpl"
|
||||
|
||||
#if !defined(K_DIRECT) && !defined(K_Q4_0) && !defined(K_Q8_0)
|
||||
fn load_k_tile_block(local_x: u32, kv_count: u32, kv_tile: u32, k_head_offset: u32) {
|
||||
for (var elem_idx = local_x; elem_idx < KV_TILE * HEAD_DIM_QK; elem_idx += WG_SIZE) {
|
||||
let k_row = elem_idx / HEAD_DIM_QK;
|
||||
let k_col = elem_idx % HEAD_DIM_QK;
|
||||
let global_k_row = kv_tile + k_row;
|
||||
let global_k_row_offset = k_head_offset + global_k_row * params.stride_k1;
|
||||
kv_shmem[elem_idx] = f16(select(
|
||||
0.0,
|
||||
K[global_k_row_offset + k_col],
|
||||
global_k_row < params.seq_len_kv && k_col < HEAD_DIM_QK));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(V_DIRECT) && !defined(V_Q4_0) && !defined(V_Q8_0)
|
||||
fn load_v_tile_block(local_x: u32, kv_count: u32, kv_tile: u32, v_head_offset: u32) {
|
||||
for (var elem_idx = local_x; elem_idx < KV_TILE * HEAD_DIM_V; elem_idx += WG_SIZE) {
|
||||
let v_row = elem_idx / HEAD_DIM_V;
|
||||
let v_col = elem_idx % HEAD_DIM_V;
|
||||
let global_v_row = kv_tile + v_row;
|
||||
let global_v_row_offset = v_head_offset + global_v_row * params.stride_v1;
|
||||
kv_shmem[elem_idx] = f16(select(
|
||||
0.0,
|
||||
V[global_v_row_offset + v_col],
|
||||
global_v_row < params.seq_len_kv && v_col < HEAD_DIM_V));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@compute @workgroup_size(WG_SIZE)
|
||||
fn main(@builtin(workgroup_id) wg_id: vec3<u32>,
|
||||
@builtin(local_invocation_id) local_id: vec3<u32>,
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
#ifdef Q_F32
|
||||
#define Q_TYPE f32
|
||||
#else
|
||||
#define Q_TYPE f16
|
||||
#endif
|
||||
|
||||
#ifdef K_F32
|
||||
#define K_TYPE f32
|
||||
#elif defined(K_Q4_0) || defined(K_Q8_0)
|
||||
#define K_TYPE u32
|
||||
#else
|
||||
#define K_TYPE f16
|
||||
#endif
|
||||
|
||||
#ifdef V_F32
|
||||
#define V_TYPE f32
|
||||
#elif defined(V_Q4_0) || defined(V_Q8_0)
|
||||
#define V_TYPE u32
|
||||
#else
|
||||
#define V_TYPE f16
|
||||
#endif
|
||||
|
||||
#ifdef DST_F32
|
||||
#define DST_TYPE f32
|
||||
#else
|
||||
#define DST_TYPE f16
|
||||
#endif
|
||||
|
||||
#if defined(FLASH_ATTN_SCALAR_KV) || defined(K_Q4_0) || defined(K_Q8_0)
|
||||
#define K_STORAGE_TYPE K_TYPE
|
||||
#else
|
||||
#define K_STORAGE_TYPE vec4<K_TYPE>
|
||||
#endif
|
||||
|
||||
#if defined(FLASH_ATTN_SCALAR_KV) || defined(V_Q4_0) || defined(V_Q8_0)
|
||||
#define V_STORAGE_TYPE V_TYPE
|
||||
#else
|
||||
#define V_STORAGE_TYPE vec4<V_TYPE>
|
||||
#endif
|
||||
|
||||
// Just a very small float value.
|
||||
const FLOAT_MIN: f32 = -1.0e9;
|
||||
|
||||
struct Params {
|
||||
offset_q: u32,
|
||||
offset_k: u32,
|
||||
offset_v: u32,
|
||||
offset_mask: u32,
|
||||
offset_sinks: u32,
|
||||
offset_dst: u32,
|
||||
|
||||
// shapes of Q/K/V
|
||||
n_heads: u32,
|
||||
seq_len_q: u32,
|
||||
seq_len_kv: u32,
|
||||
|
||||
// strides (in elements)
|
||||
stride_q1: u32,
|
||||
stride_q2: u32,
|
||||
stride_q3: u32,
|
||||
stride_k1: u32,
|
||||
stride_k2: u32,
|
||||
stride_k3: u32,
|
||||
stride_v1: u32,
|
||||
stride_v2: u32,
|
||||
stride_v3: u32,
|
||||
stride_mask3: u32,
|
||||
|
||||
// repeat factors for K/V, e.g., MHA vs. MQA vs. GQA
|
||||
q_per_kv: u32,
|
||||
|
||||
// softmax params
|
||||
scale: f32,
|
||||
max_bias: f32,
|
||||
logit_softcap: f32,
|
||||
n_head_log2: f32,
|
||||
m0: f32,
|
||||
m1: f32,
|
||||
|
||||
#ifdef FLASH_ATTN_VEC_SPLIT
|
||||
#ifdef BLK
|
||||
blk_base: u32,
|
||||
blk_nblk0: u32,
|
||||
blk_nblk1: u32,
|
||||
#endif
|
||||
|
||||
tmp_data_base: u32,
|
||||
tmp_stats_base: u32,
|
||||
nwg: u32,
|
||||
#endif
|
||||
};
|
||||
|
||||
@group(0) @binding(0) var<storage, read_write> Q: array<Q_TYPE>;
|
||||
@group(0) @binding(1) var<storage, read_write> K: array<K_STORAGE_TYPE>;
|
||||
#ifdef KV_OVERLAP
|
||||
#define V K
|
||||
#define MASK_BINDING 2
|
||||
#else
|
||||
@group(0) @binding(2) var<storage, read_write> V: array<V_STORAGE_TYPE>;
|
||||
#define MASK_BINDING 3
|
||||
#endif // KV_OVERLAP
|
||||
|
||||
#ifdef MASK
|
||||
@group(0) @binding(MASK_BINDING) var<storage, read_write> mask: array<f16>;
|
||||
#define SINKS_BINDING (MASK_BINDING + 1)
|
||||
#else
|
||||
#define SINKS_BINDING MASK_BINDING
|
||||
#endif
|
||||
|
||||
#ifdef SINKS
|
||||
@group(0) @binding(SINKS_BINDING) var<storage, read_write> sinks: array<f32>;
|
||||
#define BLK_BINDING (SINKS_BINDING + 1)
|
||||
#else
|
||||
#define BLK_BINDING SINKS_BINDING
|
||||
#endif
|
||||
|
||||
#ifdef FLASH_ATTN_VEC_SPLIT
|
||||
#ifdef BLK
|
||||
@group(0) @binding(BLK_BINDING) var<storage, read_write> blk: array<u32>;
|
||||
#define TMP_BINDING (BLK_BINDING + 1)
|
||||
#else
|
||||
#define TMP_BINDING BLK_BINDING
|
||||
#endif
|
||||
|
||||
@group(0) @binding(TMP_BINDING) var<storage, read_write> tmp: array<f32>;
|
||||
#define DST_BINDING (TMP_BINDING + 1)
|
||||
#else
|
||||
#define DST_BINDING BLK_BINDING
|
||||
#endif // FLASH_ATTN_VEC_SPLIT
|
||||
|
||||
@group(0) @binding(DST_BINDING) var<storage, read_write> dst: array<vec4<DST_TYPE>>;
|
||||
|
||||
#define PARAMS_BINDING (DST_BINDING + 1)
|
||||
@group(0) @binding(PARAMS_BINDING) var<uniform> params: Params;
|
||||
@@ -1,83 +0,0 @@
|
||||
#include "quant_inner_loops.tmpl"
|
||||
|
||||
#define BLOCK_SIZE 32
|
||||
#define BLOCKS_K ((HEAD_DIM_QK + BLOCK_SIZE - 1) / BLOCK_SIZE)
|
||||
#define BLOCKS_V ((HEAD_DIM_V + BLOCK_SIZE - 1) / BLOCK_SIZE)
|
||||
|
||||
#if defined(K_Q4_0)
|
||||
#define K_NQ 16
|
||||
#define K_BLOCK_SIZE_BYTES 18u
|
||||
#define K_BYTES_PER_THREAD 8u
|
||||
#define K_BYTES_PER_INNER_LOOP 4u
|
||||
#elif defined(K_Q8_0)
|
||||
#define K_NQ 16
|
||||
#define K_BLOCK_SIZE_BYTES 34u
|
||||
#define K_BYTES_PER_THREAD 16u
|
||||
#define K_BYTES_PER_INNER_LOOP 4u
|
||||
#endif
|
||||
|
||||
#if defined(V_Q4_0)
|
||||
#define V_NQ 16
|
||||
#define V_BLOCK_SIZE_BYTES 18u
|
||||
#define V_BYTES_PER_THREAD 8u
|
||||
#define V_BYTES_PER_INNER_LOOP 4u
|
||||
#elif defined(V_Q8_0)
|
||||
#define V_NQ 16
|
||||
#define V_BLOCK_SIZE_BYTES 34u
|
||||
#define V_BYTES_PER_THREAD 16u
|
||||
#define V_BYTES_PER_INNER_LOOP 4u
|
||||
#endif
|
||||
|
||||
#if defined(K_Q4_0) || defined(K_Q8_0)
|
||||
fn load_k_tile_block(local_x: u32, kv_count: u32, kv_tile: u32, k_head_offset: u32) {
|
||||
for (var elem_idx = local_x * K_NQ; elem_idx < kv_count * HEAD_DIM_QK; elem_idx += WG_SIZE * K_NQ) {
|
||||
let blck_idx = elem_idx / BLOCK_SIZE;
|
||||
let block_offset = (elem_idx % BLOCK_SIZE) / K_NQ;
|
||||
let k_row = blck_idx / BLOCKS_K;
|
||||
let global_k_row = kv_tile + k_row;
|
||||
let block_k = blck_idx % BLOCKS_K;
|
||||
let row_offset = k_row * HEAD_DIM_QK;
|
||||
let global_block_idx = k_head_offset + global_k_row * params.stride_k1 + block_k;
|
||||
let block_byte_base = global_block_idx * K_BLOCK_SIZE_BYTES;
|
||||
let d = f16_from_u16(load_k_u16_at(block_byte_base));
|
||||
let thread_byte_offset = block_offset * K_BYTES_PER_THREAD;
|
||||
let shmem_idx = row_offset + block_k * BLOCK_SIZE + thread_byte_offset;
|
||||
for (var j = 0u; j < K_BYTES_PER_THREAD / K_BYTES_PER_INNER_LOOP; j += 1u) {
|
||||
let q_byte_offset = block_byte_base + 2u + thread_byte_offset + j * K_BYTES_PER_INNER_LOOP;
|
||||
let q_packed = load_k_u32_at(q_byte_offset);
|
||||
#if defined(K_Q4_0)
|
||||
dequant_q4_0_packed_to_shmem(q_packed, d, shmem_idx + j * K_BYTES_PER_INNER_LOOP);
|
||||
#elif defined(K_Q8_0)
|
||||
dequant_q8_0_packed_to_shmem(q_packed, d, shmem_idx + j * K_BYTES_PER_INNER_LOOP);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(V_Q4_0) || defined(V_Q8_0)
|
||||
fn load_v_tile_block(local_x: u32, kv_count: u32, kv_tile: u32, v_head_offset: u32) {
|
||||
for (var elem_idx = local_x * V_NQ; elem_idx < kv_count * HEAD_DIM_V; elem_idx += WG_SIZE * V_NQ) {
|
||||
let blck_idx = elem_idx / BLOCK_SIZE;
|
||||
let block_offset = (elem_idx % BLOCK_SIZE) / V_NQ;
|
||||
let v_row = blck_idx / BLOCKS_V;
|
||||
let global_v_row = kv_tile + v_row;
|
||||
let block_k = blck_idx % BLOCKS_V;
|
||||
let row_offset = v_row * HEAD_DIM_V;
|
||||
let global_block_idx = v_head_offset + global_v_row * params.stride_v1 + block_k;
|
||||
let block_byte_base = global_block_idx * V_BLOCK_SIZE_BYTES;
|
||||
let d = f16_from_u16(load_v_u16_at(block_byte_base));
|
||||
let thread_byte_offset = block_offset * V_BYTES_PER_THREAD;
|
||||
let shmem_idx = row_offset + block_k * BLOCK_SIZE + thread_byte_offset;
|
||||
for (var j = 0u; j < V_BYTES_PER_THREAD / V_BYTES_PER_INNER_LOOP; j += 1u) {
|
||||
let q_byte_offset = block_byte_base + 2u + thread_byte_offset + j * V_BYTES_PER_INNER_LOOP;
|
||||
let q_packed = load_v_u32_at(q_byte_offset);
|
||||
#if defined(V_Q4_0)
|
||||
dequant_q4_0_packed_to_shmem(q_packed, d, shmem_idx + j * V_BYTES_PER_INNER_LOOP);
|
||||
#elif defined(V_Q8_0)
|
||||
dequant_q8_0_packed_to_shmem(q_packed, d, shmem_idx + j * V_BYTES_PER_INNER_LOOP);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,136 @@
|
||||
#if defined(K_Q4_0) || defined(K_Q8_0) || defined(V_Q4_0) || defined(V_Q8_0)
|
||||
#define QUANT_SHMEM STAGING_SHMEM
|
||||
#define QUANT_OUT_TYPE STAGING_OUT_TYPE
|
||||
#include "quant_inner_loops.tmpl"
|
||||
#undef QUANT_SHMEM
|
||||
#undef QUANT_OUT_TYPE
|
||||
#define BLOCK_SIZE 32
|
||||
#define BLOCKS_K ((HEAD_DIM_QK + BLOCK_SIZE - 1) / BLOCK_SIZE)
|
||||
#define BLOCKS_V ((HEAD_DIM_V + BLOCK_SIZE - 1) / BLOCK_SIZE)
|
||||
#endif
|
||||
|
||||
#if defined(K_Q4_0)
|
||||
#define K_NQ 16
|
||||
#define K_BLOCK_SIZE_BYTES 18u
|
||||
#define K_BYTES_PER_THREAD 8u
|
||||
#define K_BYTES_PER_INNER_LOOP 4u
|
||||
#define DEQUANT_K_PACKED_TO_SHMEM dequant_q4_0_packed_to_shmem
|
||||
#elif defined(K_Q8_0)
|
||||
#define K_NQ 16
|
||||
#define K_BLOCK_SIZE_BYTES 34u
|
||||
#define K_BYTES_PER_THREAD 16u
|
||||
#define K_BYTES_PER_INNER_LOOP 4u
|
||||
#define DEQUANT_K_PACKED_TO_SHMEM dequant_q8_0_packed_to_shmem
|
||||
#endif
|
||||
|
||||
#if defined(V_Q4_0)
|
||||
#define V_NQ 16
|
||||
#define V_BLOCK_SIZE_BYTES 18u
|
||||
#define V_BYTES_PER_THREAD 8u
|
||||
#define V_BYTES_PER_INNER_LOOP 4u
|
||||
#define DEQUANT_V_PACKED_TO_SHMEM dequant_q4_0_packed_to_shmem
|
||||
#elif defined(V_Q8_0)
|
||||
#define V_NQ 16
|
||||
#define V_BLOCK_SIZE_BYTES 34u
|
||||
#define V_BYTES_PER_THREAD 16u
|
||||
#define V_BYTES_PER_INNER_LOOP 4u
|
||||
#define DEQUANT_V_PACKED_TO_SHMEM dequant_q8_0_packed_to_shmem
|
||||
#endif
|
||||
|
||||
#ifndef K_DIRECT
|
||||
fn load_k_tile_block(local_x: u32, kv_count: u32, kv_tile: u32, k_head_offset: u32) {
|
||||
#if defined(K_Q4_0) || defined(K_Q8_0)
|
||||
for (var elem_idx = local_x * K_NQ; elem_idx < kv_count * HEAD_DIM_QK; elem_idx += WG_SIZE * K_NQ) {
|
||||
let blck_idx = elem_idx / BLOCK_SIZE;
|
||||
let block_offset = (elem_idx % BLOCK_SIZE) / K_NQ;
|
||||
let k_row = blck_idx / BLOCKS_K;
|
||||
let global_k_row = kv_tile + k_row;
|
||||
let block_k = blck_idx % BLOCKS_K;
|
||||
let row_offset = k_row * HEAD_DIM_QK;
|
||||
let global_block_idx = k_head_offset + global_k_row * params.stride_k1 + block_k;
|
||||
let block_byte_base = global_block_idx * K_BLOCK_SIZE_BYTES;
|
||||
let d = f16_from_u16(load_k_u16_at(block_byte_base));
|
||||
let thread_byte_offset = block_offset * K_BYTES_PER_THREAD;
|
||||
let shmem_idx = row_offset + block_k * BLOCK_SIZE + thread_byte_offset;
|
||||
for (var j = 0u; j < K_BYTES_PER_THREAD / K_BYTES_PER_INNER_LOOP; j += 1u) {
|
||||
let q_byte_offset = block_byte_base + 2u + thread_byte_offset + j * K_BYTES_PER_INNER_LOOP;
|
||||
let q_packed = load_k_u32_at(q_byte_offset);
|
||||
DEQUANT_K_PACKED_TO_SHMEM(q_packed, d, shmem_idx + j * K_BYTES_PER_INNER_LOOP);
|
||||
}
|
||||
}
|
||||
#elif defined(FLASH_ATTN_SCALAR_KV)
|
||||
for (var elem_idx = local_x; elem_idx < KV_TILE * HEAD_DIM_QK; elem_idx += WG_SIZE) {
|
||||
let k_row = elem_idx / HEAD_DIM_QK;
|
||||
let k_col = elem_idx % HEAD_DIM_QK;
|
||||
let global_k_row = kv_tile + k_row;
|
||||
let global_k_row_offset = k_head_offset + global_k_row * params.stride_k1;
|
||||
STAGING_SHMEM[elem_idx] = STAGING_OUT_TYPE(select(
|
||||
0.0,
|
||||
K[global_k_row_offset + k_col],
|
||||
global_k_row < params.seq_len_kv && k_col < HEAD_DIM_QK));
|
||||
}
|
||||
#else
|
||||
for (var vec_idx_local = local_x; vec_idx_local < kv_count * Q_CHUNKS; vec_idx_local += WG_SIZE) {
|
||||
let kv_local = vec_idx_local / Q_CHUNKS;
|
||||
let chunk = vec_idx_local % Q_CHUNKS;
|
||||
let global_k_row = kv_tile + kv_local;
|
||||
let k_vec_index = (k_head_offset + global_k_row * params.stride_k1 + chunk * 4u) >> 2u;
|
||||
let k4 = K[k_vec_index];
|
||||
let kv_off = kv_local * HEAD_DIM_QK + chunk * 4u;
|
||||
STAGING_SHMEM[kv_off + 0u] = STAGING_OUT_TYPE(k4.x);
|
||||
STAGING_SHMEM[kv_off + 1u] = STAGING_OUT_TYPE(k4.y);
|
||||
STAGING_SHMEM[kv_off + 2u] = STAGING_OUT_TYPE(k4.z);
|
||||
STAGING_SHMEM[kv_off + 3u] = STAGING_OUT_TYPE(k4.w);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif // !defined(K_DIRECT)
|
||||
|
||||
#ifndef V_DIRECT
|
||||
fn load_v_tile_block(local_x: u32, kv_count: u32, kv_tile: u32, v_head_offset: u32) {
|
||||
#if defined(V_Q4_0) || defined(V_Q8_0)
|
||||
for (var elem_idx = local_x * V_NQ; elem_idx < kv_count * HEAD_DIM_V; elem_idx += WG_SIZE * V_NQ) {
|
||||
let blck_idx = elem_idx / BLOCK_SIZE;
|
||||
let block_offset = (elem_idx % BLOCK_SIZE) / V_NQ;
|
||||
let v_row = blck_idx / BLOCKS_V;
|
||||
let global_v_row = kv_tile + v_row;
|
||||
let block_k = blck_idx % BLOCKS_V;
|
||||
let row_offset = v_row * HEAD_DIM_V;
|
||||
let global_block_idx = v_head_offset + global_v_row * params.stride_v1 + block_k;
|
||||
let block_byte_base = global_block_idx * V_BLOCK_SIZE_BYTES;
|
||||
let d = f16_from_u16(load_v_u16_at(block_byte_base));
|
||||
let thread_byte_offset = block_offset * V_BYTES_PER_THREAD;
|
||||
let shmem_idx = row_offset + block_k * BLOCK_SIZE + thread_byte_offset;
|
||||
for (var j = 0u; j < V_BYTES_PER_THREAD / V_BYTES_PER_INNER_LOOP; j += 1u) {
|
||||
let q_byte_offset = block_byte_base + 2u + thread_byte_offset + j * V_BYTES_PER_INNER_LOOP;
|
||||
let q_packed = load_v_u32_at(q_byte_offset);
|
||||
DEQUANT_V_PACKED_TO_SHMEM(q_packed, d, shmem_idx + j * V_BYTES_PER_INNER_LOOP);
|
||||
}
|
||||
}
|
||||
#elif defined(FLASH_ATTN_SCALAR_KV)
|
||||
for (var elem_idx = local_x; elem_idx < KV_TILE * HEAD_DIM_V; elem_idx += WG_SIZE) {
|
||||
let v_row = elem_idx / HEAD_DIM_V;
|
||||
let v_col = elem_idx % HEAD_DIM_V;
|
||||
let global_v_row = kv_tile + v_row;
|
||||
let global_v_row_offset = v_head_offset + global_v_row * params.stride_v1;
|
||||
STAGING_SHMEM[elem_idx] = STAGING_OUT_TYPE(select(
|
||||
0.0,
|
||||
V[global_v_row_offset + v_col],
|
||||
global_v_row < params.seq_len_kv && v_col < HEAD_DIM_V));
|
||||
}
|
||||
#else
|
||||
for (var vec_idx_local = local_x; vec_idx_local < kv_count * V_CHUNKS; vec_idx_local += WG_SIZE) {
|
||||
let kv_local = vec_idx_local / V_CHUNKS;
|
||||
let chunk = vec_idx_local % V_CHUNKS;
|
||||
let global_v_row = kv_tile + kv_local;
|
||||
let v_vec_index = (v_head_offset + global_v_row * params.stride_v1 + chunk * 4u) >> 2u;
|
||||
let v4 = V[v_vec_index];
|
||||
let kv_off = kv_local * HEAD_DIM_V + chunk * 4u;
|
||||
STAGING_SHMEM[kv_off + 0u] = STAGING_OUT_TYPE(v4.x);
|
||||
STAGING_SHMEM[kv_off + 1u] = STAGING_OUT_TYPE(v4.y);
|
||||
STAGING_SHMEM[kv_off + 2u] = STAGING_OUT_TYPE(v4.z);
|
||||
STAGING_SHMEM[kv_off + 3u] = STAGING_OUT_TYPE(v4.w);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif // !defined(V_DIRECT)
|
||||
@@ -3,192 +3,32 @@ enable subgroups;
|
||||
|
||||
#define BYTE_HELPERS
|
||||
#include "common_decls.tmpl"
|
||||
#include "flash_attn_decls.tmpl"
|
||||
|
||||
#ifdef Q_F16
|
||||
#define Q_TYPE f16
|
||||
#else
|
||||
#define Q_TYPE f32
|
||||
#endif
|
||||
|
||||
#ifdef K_F32
|
||||
#define K_TYPE f32
|
||||
#elif defined(K_Q4_0) || defined(K_Q8_0)
|
||||
#define K_TYPE u32
|
||||
#else
|
||||
#define K_TYPE f16
|
||||
#endif
|
||||
|
||||
#ifdef V_F32
|
||||
#define V_TYPE f32
|
||||
#elif defined(V_Q4_0) || defined(V_Q8_0)
|
||||
#define V_TYPE u32
|
||||
#else
|
||||
#define V_TYPE f16
|
||||
#endif
|
||||
|
||||
#ifdef DST_F16
|
||||
#define DST_TYPE f16
|
||||
#else
|
||||
#define DST_TYPE f32
|
||||
#endif
|
||||
|
||||
// Default values
|
||||
// The actual values are defined in shader-lib.
|
||||
#define HEAD_DIM_QK 64
|
||||
#define HEAD_DIM_V 64
|
||||
#define Q_TILE 4
|
||||
#define KV_TILE 64
|
||||
#define WG_SIZE 128
|
||||
#ifndef MIN_SUBGROUP_SIZE
|
||||
#define MIN_SUBGROUP_SIZE MAX_SUBGROUP_SIZE
|
||||
#endif
|
||||
|
||||
struct Params {
|
||||
offset_q: u32,
|
||||
offset_k: u32,
|
||||
offset_v: u32,
|
||||
offset_mask: u32,
|
||||
offset_sinks: u32,
|
||||
offset_dst: u32,
|
||||
|
||||
n_heads: u32,
|
||||
seq_len_q: u32,
|
||||
seq_len_kv: u32,
|
||||
|
||||
stride_q1: u32,
|
||||
stride_q2: u32,
|
||||
stride_q3: u32,
|
||||
stride_k1: u32,
|
||||
stride_k2: u32,
|
||||
stride_k3: u32,
|
||||
stride_v1: u32,
|
||||
stride_v2: u32,
|
||||
stride_v3: u32,
|
||||
stride_mask3: u32,
|
||||
|
||||
q_per_kv: u32,
|
||||
|
||||
scale: f32,
|
||||
max_bias: f32,
|
||||
logit_softcap: f32,
|
||||
n_head_log2: f32,
|
||||
m0: f32,
|
||||
m1: f32,
|
||||
};
|
||||
|
||||
@group(0) @binding(0) var<storage, read_write> Q: array<Q_TYPE>;
|
||||
#ifdef KV_OVERLAP
|
||||
#if defined(K_Q4_0) || defined(K_Q8_0)
|
||||
@group(0) @binding(1) var<storage, read_write> K: array<K_TYPE>;
|
||||
#else
|
||||
@group(0) @binding(1) var<storage, read_write> K: array<vec4<K_TYPE>>;
|
||||
#endif
|
||||
#define V K
|
||||
#else
|
||||
#if defined(K_Q4_0) || defined(K_Q8_0)
|
||||
@group(0) @binding(1) var<storage, read_write> K: array<K_TYPE>;
|
||||
#else
|
||||
@group(0) @binding(1) var<storage, read_write> K: array<vec4<K_TYPE>>;
|
||||
#endif
|
||||
#if defined(V_Q4_0) || defined(V_Q8_0)
|
||||
@group(0) @binding(2) var<storage, read_write> V: array<V_TYPE>;
|
||||
#else
|
||||
@group(0) @binding(2) var<storage, read_write> V: array<vec4<V_TYPE>>;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(MASK) && defined(SINKS)
|
||||
#ifdef KV_OVERLAP
|
||||
@group(0) @binding(2) var<storage, read_write> mask: array<f16>;
|
||||
@group(0) @binding(3) var<storage, read_write> sinks: array<f32>;
|
||||
#define DST_BINDING 4
|
||||
#define PARAMS_BINDING 5
|
||||
#else
|
||||
@group(0) @binding(3) var<storage, read_write> mask: array<f16>;
|
||||
@group(0) @binding(4) var<storage, read_write> sinks: array<f32>;
|
||||
#define DST_BINDING 5
|
||||
#define PARAMS_BINDING 6
|
||||
#endif
|
||||
#elif defined(MASK)
|
||||
#ifdef KV_OVERLAP
|
||||
@group(0) @binding(2) var<storage, read_write> mask: array<f16>;
|
||||
#define DST_BINDING 3
|
||||
#define PARAMS_BINDING 4
|
||||
#else
|
||||
@group(0) @binding(3) var<storage, read_write> mask: array<f16>;
|
||||
#define DST_BINDING 4
|
||||
#define PARAMS_BINDING 5
|
||||
#endif
|
||||
#elif defined(SINKS)
|
||||
#ifdef KV_OVERLAP
|
||||
@group(0) @binding(2) var<storage, read_write> sinks: array<f32>;
|
||||
#define DST_BINDING 3
|
||||
#define PARAMS_BINDING 4
|
||||
#else
|
||||
@group(0) @binding(3) var<storage, read_write> sinks: array<f32>;
|
||||
#define DST_BINDING 4
|
||||
#define PARAMS_BINDING 5
|
||||
#endif
|
||||
#else
|
||||
#ifdef KV_OVERLAP
|
||||
#define DST_BINDING 2
|
||||
#define PARAMS_BINDING 3
|
||||
#else
|
||||
#define DST_BINDING 3
|
||||
#define PARAMS_BINDING 4
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@group(0) @binding(DST_BINDING) var<storage, read_write> dst: array<vec4<DST_TYPE>>;
|
||||
@group(0) @binding(PARAMS_BINDING) var<uniform> params: Params;
|
||||
|
||||
const FLOAT_MIN: f32 = -1.0e9;
|
||||
const Q_CHUNKS: u32 = HEAD_DIM_QK / 4u;
|
||||
const V_CHUNKS: u32 = HEAD_DIM_V / 4u;
|
||||
const SCORE_REGS_PER_LANE: u32 = (KV_TILE + MIN_SUBGROUP_SIZE - 1u) / MIN_SUBGROUP_SIZE;
|
||||
const OUT_REGS_PER_LANE: u32 = (V_CHUNKS + MIN_SUBGROUP_SIZE - 1u) / MIN_SUBGROUP_SIZE;
|
||||
|
||||
#if !defined(K_DIRECT) || !defined(V_DIRECT)
|
||||
#define STAGING_SHMEM kv_shmem
|
||||
#define STAGING_OUT_TYPE f16
|
||||
#include "flash_attn_staging.tmpl"
|
||||
const kv_shmem_size = KV_TILE * max(HEAD_DIM_QK, HEAD_DIM_V);
|
||||
var<workgroup> kv_shmem: array<f16, kv_shmem_size>;
|
||||
#endif
|
||||
|
||||
var<workgroup> q_shmem: array<Q_TYPE, Q_TILE * HEAD_DIM_QK>;
|
||||
var<workgroup> kv_shmem: array<f16, kv_shmem_size>;
|
||||
var<workgroup> p_shmem: array<f16, Q_TILE * KV_TILE>;
|
||||
|
||||
#define QUANT_SHMEM kv_shmem
|
||||
#define QUANT_OUT_TYPE f16
|
||||
#include "flash_attn_quant_staging.tmpl"
|
||||
|
||||
#if !defined(K_Q4_0) && !defined(K_Q8_0)
|
||||
fn load_k_tile_block(local_x: u32, kv_count: u32, kv_tile: u32, k_head_offset: u32) {
|
||||
for (var vec_idx_local = local_x; vec_idx_local < kv_count * Q_CHUNKS; vec_idx_local += WG_SIZE) {
|
||||
let kv_local = vec_idx_local / Q_CHUNKS;
|
||||
let chunk = vec_idx_local % Q_CHUNKS;
|
||||
let global_k_row = kv_tile + kv_local;
|
||||
let k_vec_index = (k_head_offset + global_k_row * params.stride_k1 + chunk * 4u) >> 2u;
|
||||
let k4 = K[k_vec_index];
|
||||
let kv_off = kv_local * HEAD_DIM_QK + chunk * 4u;
|
||||
kv_shmem[kv_off + 0u] = f16(k4.x);
|
||||
kv_shmem[kv_off + 1u] = f16(k4.y);
|
||||
kv_shmem[kv_off + 2u] = f16(k4.z);
|
||||
kv_shmem[kv_off + 3u] = f16(k4.w);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(V_Q4_0) && !defined(V_Q8_0)
|
||||
fn load_v_tile_block(local_x: u32, kv_count: u32, kv_tile: u32, v_head_offset: u32) {
|
||||
for (var vec_idx_local = local_x; vec_idx_local < kv_count * V_CHUNKS; vec_idx_local += WG_SIZE) {
|
||||
let kv_local = vec_idx_local / V_CHUNKS;
|
||||
let chunk = vec_idx_local % V_CHUNKS;
|
||||
let global_v_row = kv_tile + kv_local;
|
||||
let v_vec_index = (v_head_offset + global_v_row * params.stride_v1 + chunk * 4u) >> 2u;
|
||||
let v4 = V[v_vec_index];
|
||||
let kv_off = kv_local * HEAD_DIM_V + chunk * 4u;
|
||||
kv_shmem[kv_off + 0u] = f16(v4.x);
|
||||
kv_shmem[kv_off + 1u] = f16(v4.y);
|
||||
kv_shmem[kv_off + 2u] = f16(v4.z);
|
||||
kv_shmem[kv_off + 3u] = f16(v4.w);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@compute @workgroup_size(WG_SIZE)
|
||||
fn main(@builtin(workgroup_id) wg_id: vec3<u32>,
|
||||
@builtin(local_invocation_id) local_id: vec3<u32>,
|
||||
|
||||
@@ -4,200 +4,35 @@ enable subgroups;
|
||||
|
||||
#define BYTE_HELPERS
|
||||
#include "common_decls.tmpl"
|
||||
#define FLASH_ATTN_VEC_SPLIT
|
||||
#include "flash_attn_decls.tmpl"
|
||||
|
||||
#ifdef K_F32
|
||||
#define K_TYPE f32
|
||||
#elif defined(K_Q4_0) || defined(K_Q8_0)
|
||||
#define K_TYPE u32
|
||||
#else
|
||||
#define K_TYPE f16
|
||||
#endif
|
||||
|
||||
#ifdef V_F32
|
||||
#define V_TYPE f32
|
||||
#elif defined(V_Q4_0) || defined(V_Q8_0)
|
||||
#define V_TYPE u32
|
||||
#else
|
||||
#define V_TYPE f16
|
||||
#endif
|
||||
|
||||
#ifdef Q_F16
|
||||
#define Q_TYPE f16
|
||||
#else
|
||||
#define Q_TYPE f32
|
||||
#endif
|
||||
|
||||
#ifdef DST_F16
|
||||
#define DST_TYPE f16
|
||||
#else
|
||||
#define DST_TYPE f32
|
||||
#endif
|
||||
|
||||
// Default values
|
||||
// The actual values are defined in shader-lib.
|
||||
#define HEAD_DIM_QK 64
|
||||
#define HEAD_DIM_V 64
|
||||
|
||||
#define KV_GRANULARITY 8
|
||||
#define KV_TILE 16
|
||||
#define WG_SIZE 64
|
||||
|
||||
#define KV_BLOCKS (KV_TILE / KV_GRANULARITY)
|
||||
|
||||
struct Params {
|
||||
offset_q: u32,
|
||||
offset_k: u32,
|
||||
offset_v: u32,
|
||||
offset_mask: u32,
|
||||
offset_sinks: u32,
|
||||
offset_dst: u32,
|
||||
|
||||
// shapes of Q/K/V
|
||||
n_heads: u32,
|
||||
seq_len_q: u32,
|
||||
seq_len_kv: u32,
|
||||
|
||||
// strides (in elements)
|
||||
stride_q1: u32,
|
||||
stride_q2: u32,
|
||||
stride_q3: u32,
|
||||
stride_k1: u32,
|
||||
stride_k2: u32,
|
||||
stride_k3: u32,
|
||||
stride_v1: u32,
|
||||
stride_v2: u32,
|
||||
stride_v3: u32,
|
||||
stride_mask3: u32,
|
||||
|
||||
// repeat factors for K/V, e.g., MHA vs. MQA vs. GQA
|
||||
q_per_kv: u32,
|
||||
|
||||
// softmax params
|
||||
scale: f32,
|
||||
max_bias: f32,
|
||||
logit_softcap: f32,
|
||||
n_head_log2: f32,
|
||||
m0: f32,
|
||||
m1: f32,
|
||||
|
||||
#ifdef BLK
|
||||
blk_base: u32,
|
||||
blk_nblk0: u32,
|
||||
blk_nblk1: u32,
|
||||
#endif
|
||||
|
||||
tmp_data_base: u32,
|
||||
tmp_stats_base: u32,
|
||||
nwg: u32,
|
||||
};
|
||||
|
||||
@group(0) @binding(0) var<storage, read_write> Q: array<Q_TYPE>;
|
||||
#ifdef KV_OVERLAP
|
||||
#if defined(K_Q4_0) || defined(K_Q8_0)
|
||||
@group(0) @binding(1) var<storage, read_write> K: array<K_TYPE>;
|
||||
#else
|
||||
@group(0) @binding(1) var<storage, read_write> K: array<vec4<K_TYPE>>;
|
||||
#endif
|
||||
#define V K
|
||||
#else
|
||||
#if defined(K_Q4_0) || defined(K_Q8_0)
|
||||
@group(0) @binding(1) var<storage, read_write> K: array<K_TYPE>;
|
||||
#else
|
||||
@group(0) @binding(1) var<storage, read_write> K: array<vec4<K_TYPE>>;
|
||||
#endif
|
||||
#if defined(V_Q4_0) || defined(V_Q8_0)
|
||||
@group(0) @binding(2) var<storage, read_write> V: array<V_TYPE>;
|
||||
#else
|
||||
@group(0) @binding(2) var<storage, read_write> V: array<vec4<V_TYPE>>;
|
||||
#endif
|
||||
#endif
|
||||
#if defined(MASK) && defined(SINKS)
|
||||
#ifdef KV_OVERLAP
|
||||
@group(0) @binding(2) var<storage, read_write> mask: array<f16>;
|
||||
@group(0) @binding(3) var<storage, read_write> sinks: array<f32>;
|
||||
#ifdef BLK
|
||||
#define BLK_BINDING 4
|
||||
#define TMP_BINDING 5
|
||||
#define DST_BINDING 6
|
||||
#define PARAMS_BINDING 7
|
||||
#else
|
||||
#define TMP_BINDING 4
|
||||
#define DST_BINDING 5
|
||||
#define PARAMS_BINDING 6
|
||||
#endif
|
||||
#else
|
||||
@group(0) @binding(3) var<storage, read_write> mask: array<f16>;
|
||||
@group(0) @binding(4) var<storage, read_write> sinks: array<f32>;
|
||||
#ifdef BLK
|
||||
#define BLK_BINDING 5
|
||||
#define TMP_BINDING 6
|
||||
#define DST_BINDING 7
|
||||
#define PARAMS_BINDING 8
|
||||
#else
|
||||
#define TMP_BINDING 5
|
||||
#define DST_BINDING 6
|
||||
#define PARAMS_BINDING 7
|
||||
#endif
|
||||
#endif
|
||||
#elif defined(MASK)
|
||||
#ifdef KV_OVERLAP
|
||||
@group(0) @binding(2) var<storage, read_write> mask: array<f16>;
|
||||
#ifdef BLK
|
||||
#define BLK_BINDING 3
|
||||
#define TMP_BINDING 4
|
||||
#define DST_BINDING 5
|
||||
#define PARAMS_BINDING 6
|
||||
#else
|
||||
#define TMP_BINDING 3
|
||||
#define DST_BINDING 4
|
||||
#define PARAMS_BINDING 5
|
||||
#endif
|
||||
#else
|
||||
@group(0) @binding(3) var<storage, read_write> mask: array<f16>;
|
||||
#ifdef BLK
|
||||
#define BLK_BINDING 4
|
||||
#define TMP_BINDING 5
|
||||
#define DST_BINDING 6
|
||||
#define PARAMS_BINDING 7
|
||||
#else
|
||||
#define TMP_BINDING 4
|
||||
#define DST_BINDING 5
|
||||
#define PARAMS_BINDING 6
|
||||
#endif
|
||||
#endif
|
||||
#elif defined(SINKS)
|
||||
#ifdef KV_OVERLAP
|
||||
@group(0) @binding(2) var<storage, read_write> sinks: array<f32>;
|
||||
#define TMP_BINDING 3
|
||||
#define DST_BINDING 4
|
||||
#define PARAMS_BINDING 5
|
||||
#else
|
||||
@group(0) @binding(3) var<storage, read_write> sinks: array<f32>;
|
||||
#define TMP_BINDING 4
|
||||
#define DST_BINDING 5
|
||||
#define PARAMS_BINDING 6
|
||||
#endif
|
||||
#else
|
||||
#ifdef KV_OVERLAP
|
||||
#define TMP_BINDING 2
|
||||
#define DST_BINDING 3
|
||||
#define PARAMS_BINDING 4
|
||||
#else
|
||||
#define TMP_BINDING 3
|
||||
#define DST_BINDING 4
|
||||
#define PARAMS_BINDING 5
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef BLK
|
||||
@group(0) @binding(BLK_BINDING) var<storage, read_write> blk: array<u32>;
|
||||
#endif
|
||||
@group(0) @binding(TMP_BINDING) var<storage, read_write> tmp: array<f32>;
|
||||
@group(0) @binding(DST_BINDING) var<storage, read_write> dst: array<vec4<DST_TYPE>>;
|
||||
@group(0) @binding(PARAMS_BINDING) var<uniform> params: Params;
|
||||
|
||||
// Just a very small float value.
|
||||
const FLOAT_MIN: f32 = -1.0e9;
|
||||
const Q_CHUNKS: u32 = HEAD_DIM_QK / 4u;
|
||||
const V_CHUNKS: u32 = HEAD_DIM_V / 4u;
|
||||
const kv_shmem_size = KV_TILE * max(HEAD_DIM_QK, HEAD_DIM_V);
|
||||
|
||||
#if defined(K_DIRECT) || defined(V_DIRECT)
|
||||
// Shared memory for scale factor (d) in quantized K/V. Multiple threads use the same value,
|
||||
// so caching it is more efficient, even on the direct path.
|
||||
var<workgroup> d_shmem: array<f32, kv_shmem_size / 32>;
|
||||
#endif
|
||||
|
||||
// K/V shared memory handling
|
||||
#if !defined(K_DIRECT) || !defined(V_DIRECT)
|
||||
#define STAGING_SHMEM kv_shmem
|
||||
#define STAGING_OUT_TYPE f32
|
||||
#include "flash_attn_staging.tmpl"
|
||||
// we can reuse the same shmem for K and V since we only need one at a time
|
||||
var<workgroup> kv_shmem: array<f32, kv_shmem_size>;
|
||||
#endif
|
||||
|
||||
var<workgroup> q_shmem: array<f32, HEAD_DIM_QK>;
|
||||
var<workgroup> o_shmem: array<f32, HEAD_DIM_V>;
|
||||
// note that we reuse the same storage for both since we only need one at a time
|
||||
@@ -208,59 +43,6 @@ var<workgroup> inter_shmem: array<f32, KV_TILE>;
|
||||
var<workgroup> mask_shmem: array<f32, KV_TILE>;
|
||||
#endif
|
||||
|
||||
#if defined(K_DIRECT) || defined(V_DIRECT)
|
||||
// Shared memory for scale factor (d) in quantized K/V. Multiple threads use the same value,
|
||||
// so caching it is more efficient, even on the direct path.
|
||||
var<workgroup> d_shmem: array<f32, kv_shmem_size / 32>;
|
||||
#endif
|
||||
|
||||
// K/V shared memory handling
|
||||
#if !defined(K_DIRECT) || !defined(V_DIRECT)
|
||||
|
||||
// we can reuse the same shmem for K and V since we only need one at a time
|
||||
var<workgroup> kv_shmem: array<f32, kv_shmem_size>;
|
||||
|
||||
#define QUANT_SHMEM kv_shmem
|
||||
#define QUANT_OUT_TYPE f32
|
||||
#include "flash_attn_quant_staging.tmpl"
|
||||
|
||||
#if !defined(K_DIRECT) && !defined(K_Q4_0) && !defined(K_Q8_0)
|
||||
fn load_k_tile_block(local_x: u32, kv_count: u32, kv_tile: u32, k_head_offset: u32) {
|
||||
for (var elem_idx = local_x * 4u; elem_idx < KV_TILE * HEAD_DIM_QK; elem_idx += WG_SIZE * 4u) {
|
||||
let k_row = elem_idx / HEAD_DIM_QK;
|
||||
let k_col = elem_idx % HEAD_DIM_QK;
|
||||
let global_k_row = kv_tile + k_row;
|
||||
let global_k_row_offset = k_head_offset + global_k_row * params.stride_k1;
|
||||
let in_bounds = global_k_row < params.seq_len_kv && (k_col + 3u) < HEAD_DIM_QK;
|
||||
let vec_idx = (global_k_row_offset + k_col) >> 2u;
|
||||
let k4 = select(vec4<K_TYPE>(0.0), K[vec_idx], in_bounds);
|
||||
kv_shmem[elem_idx + 0u] = f32(k4.x);
|
||||
kv_shmem[elem_idx + 1u] = f32(k4.y);
|
||||
kv_shmem[elem_idx + 2u] = f32(k4.z);
|
||||
kv_shmem[elem_idx + 3u] = f32(k4.w);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(V_DIRECT) && !defined(V_Q4_0) && !defined(V_Q8_0)
|
||||
fn load_v_tile_block(local_x: u32, kv_count: u32, kv_tile: u32, v_head_offset: u32) {
|
||||
for (var elem_idx = local_x * 4u; elem_idx < KV_TILE * HEAD_DIM_V; elem_idx += WG_SIZE * 4u) {
|
||||
let v_row = elem_idx / HEAD_DIM_V;
|
||||
let v_col = elem_idx % HEAD_DIM_V;
|
||||
let global_v_row = kv_tile + v_row;
|
||||
let global_v_row_offset = v_head_offset + global_v_row * params.stride_v1;
|
||||
let in_bounds = global_v_row < params.seq_len_kv && (v_col + 3u) < HEAD_DIM_V;
|
||||
let vec_idx = (global_v_row_offset + v_col) >> 2u;
|
||||
let v4 = select(vec4<V_TYPE>(0.0), V[vec_idx], in_bounds);
|
||||
kv_shmem[elem_idx + 0u] = f32(v4.x);
|
||||
kv_shmem[elem_idx + 1u] = f32(v4.y);
|
||||
kv_shmem[elem_idx + 2u] = f32(v4.z);
|
||||
kv_shmem[elem_idx + 3u] = f32(v4.w);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif // !defined(K_DIRECT) || !defined(V_DIRECT)
|
||||
|
||||
// Storage for row max and exp sum during online softmax
|
||||
fn calc_softmax_term(kv_idx: u32, slope: f32, has_bias: bool, apply_mask: bool) -> f32 {
|
||||
var v = select(FLOAT_MIN,
|
||||
|
||||
@@ -1,19 +1,9 @@
|
||||
#include "common_decls.tmpl"
|
||||
enable f16;
|
||||
|
||||
@group(0) @binding(0)
|
||||
#if defined(INPUT_F32)
|
||||
var<storage, read_write> input: array<f32>;
|
||||
#elif defined(INPUT_F16)
|
||||
var<storage, read_write> input: array<f16>;
|
||||
#endif
|
||||
|
||||
var<storage, read_write> input: array<INPUT_TYPE>;
|
||||
@group(0) @binding(1)
|
||||
#if defined(OUTPUT_F32)
|
||||
var<storage, read_write> output: array<f32>;
|
||||
#elif defined(OUTPUT_F16)
|
||||
var<storage, read_write> output: array<f16>;
|
||||
#endif
|
||||
var<storage, read_write> output: array<OUTPUT_TYPE>;
|
||||
|
||||
struct Params {
|
||||
offset_i: u32,
|
||||
@@ -38,22 +28,6 @@ struct Params {
|
||||
@group(0) @binding(2)
|
||||
var<uniform> params: Params;
|
||||
|
||||
fn load_input(idx: u32) -> f32 {
|
||||
#if defined(INPUT_F32)
|
||||
return input[idx];
|
||||
#elif defined(INPUT_F16)
|
||||
return f32(input[idx]);
|
||||
#endif
|
||||
}
|
||||
|
||||
fn store_output(idx: u32, val: f32) {
|
||||
#if defined(OUTPUT_F32)
|
||||
output[idx] = val;
|
||||
#elif defined(OUTPUT_F16)
|
||||
output[idx] = f16(val);
|
||||
#endif
|
||||
}
|
||||
|
||||
@compute @workgroup_size(WG_SIZE)
|
||||
fn main(
|
||||
@builtin(global_invocation_id) gid: vec3<u32>,
|
||||
@@ -90,12 +64,14 @@ fn main(
|
||||
let iw_i32 = i32(ow * params.s0 + kw * params.d0) - i32(params.p0);
|
||||
let ih_i32 = i32(oh * params.s1 + kh * params.d1) - i32(params.p1);
|
||||
|
||||
let output_idx = params.offset_o + k * params.so0 + ow * params.so1 + oh * params.so2 + n * params.so3;
|
||||
|
||||
if (iw_i32 >= 0 && iw_i32 < i32(params.IW) && ih_i32 >= 0 && ih_i32 < i32(params.IH)) {
|
||||
let iw = u32(iw_i32);
|
||||
let ih = u32(ih_i32);
|
||||
let in_idx = params.offset_i + iw * params.si0 + ih * params.si1 + ic * params.si2 + n * params.si3;
|
||||
store_output(params.offset_o + k * params.so0 + ow * params.so1 + oh * params.so2 + n * params.so3, load_input(in_idx));
|
||||
output[output_idx] = OUTPUT_TYPE(input[in_idx]);
|
||||
} else {
|
||||
store_output(params.offset_o + k * params.so0 + ow * params.so1 + oh * params.so2 + n * params.so3, 0.0);
|
||||
output[output_idx] = OUTPUT_TYPE(0.0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,6 @@ struct Params {
|
||||
ne0: u32,
|
||||
ne1: u32,
|
||||
ne2: u32,
|
||||
ne3: u32,
|
||||
|
||||
eps: f32
|
||||
};
|
||||
|
||||
@@ -31,7 +31,6 @@ struct Params {
|
||||
ne0: u32,
|
||||
ne1: u32,
|
||||
ne2: u32,
|
||||
ne3: u32,
|
||||
|
||||
eps: f32
|
||||
};
|
||||
|
||||
@@ -27,7 +27,6 @@ struct Params {
|
||||
stride_dst3: u32,
|
||||
|
||||
// shape of src0/dst
|
||||
ne: u32,
|
||||
ne0: u32,
|
||||
ne1: u32,
|
||||
ne2: u32,
|
||||
@@ -43,71 +42,38 @@ struct Params {
|
||||
m1: f32,
|
||||
};
|
||||
|
||||
@group(0) @binding(0)
|
||||
#define SRC_BINDING 0
|
||||
@group(0) @binding(SRC_BINDING)
|
||||
var<storage, read_write> src: array<f32>;
|
||||
|
||||
#ifdef HAS_MASK
|
||||
#ifdef HAS_SINK
|
||||
@group(0) @binding(1)
|
||||
#define MASK_BINDING SRC_BINDING + 1
|
||||
@group(0) @binding(MASK_BINDING)
|
||||
var<storage, read_write> mask: array<MaskType>;
|
||||
@group(0) @binding(2)
|
||||
var<storage, read_write> sinks: array<f32>;
|
||||
|
||||
#ifdef INPLACE
|
||||
@group(0) @binding(3)
|
||||
var<uniform> params: Params;
|
||||
|
||||
#else
|
||||
@group(0) @binding(3)
|
||||
var<storage, read_write> dst: array<f32>;
|
||||
@group(0) @binding(4)
|
||||
var<uniform> params: Params;
|
||||
#define MASK_BINDING SRC_BINDING
|
||||
#endif
|
||||
|
||||
#else
|
||||
@group(0) @binding(1)
|
||||
var<storage, read_write> mask: array<MaskType>;
|
||||
|
||||
#ifdef INPLACE
|
||||
@group(0) @binding(2)
|
||||
var<uniform> params: Params;
|
||||
|
||||
#else
|
||||
@group(0) @binding(2)
|
||||
var<storage, read_write> dst: array<f32>;
|
||||
@group(0) @binding(3)
|
||||
var<uniform> params: Params;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#else
|
||||
#ifdef HAS_SINK
|
||||
@group(0) @binding(1)
|
||||
#define SINKS_BINDING MASK_BINDING + 1
|
||||
@group(0) @binding(SINKS_BINDING)
|
||||
var<storage, read_write> sinks: array<f32>;
|
||||
#else
|
||||
#define SINKS_BINDING MASK_BINDING
|
||||
#endif
|
||||
|
||||
#define DST_BINDING SINKS_BINDING + 1
|
||||
@group(0) @binding(DST_BINDING)
|
||||
var<storage, read_write> dst: array<f32>;
|
||||
|
||||
#ifdef INPLACE
|
||||
@group(0) @binding(2)
|
||||
var<uniform> params: Params;
|
||||
|
||||
#define PARAMS_BINDING DST_BINDING
|
||||
#else
|
||||
@group(0) @binding(2)
|
||||
var<storage, read_write> dst: array<f32>;
|
||||
@group(0) @binding(3)
|
||||
var<uniform> params: Params;
|
||||
#define PARAMS_BINDING (DST_BINDING + 1)
|
||||
#endif
|
||||
|
||||
#else
|
||||
#ifdef INPLACE
|
||||
@group(0) @binding(1)
|
||||
@group(0) @binding(PARAMS_BINDING)
|
||||
var<uniform> params: Params;
|
||||
#else
|
||||
@group(0) @binding(1)
|
||||
var<storage, read_write> dst: array<f32>;
|
||||
@group(0) @binding(2)
|
||||
var<uniform> params: Params;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef INPLACE
|
||||
fn inter_value(i: u32) -> f32 {
|
||||
@@ -242,4 +208,3 @@ fn main(@builtin(workgroup_id) wid: vec3<u32>,
|
||||
col += WG_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@ struct Params {
|
||||
|
||||
k: u32,
|
||||
ne2: u32,
|
||||
ne3: u32,
|
||||
};
|
||||
|
||||
@group(0) @binding(3)
|
||||
|
||||
@@ -39,7 +39,6 @@ struct Params {
|
||||
n_head: u32,
|
||||
n_group: u32,
|
||||
n_seq_tokens: u32,
|
||||
n_seqs: u32,
|
||||
|
||||
y_elems: u32,
|
||||
};
|
||||
|
||||
@@ -7200,6 +7200,10 @@ void ggml_build_forward_expand(struct ggml_cgraph * cgraph, struct ggml_tensor *
|
||||
ggml_build_forward_impl(cgraph, tensor, true, true);
|
||||
}
|
||||
|
||||
void ggml_build_forward_order(struct ggml_cgraph * cgraph, struct ggml_tensor * tensor) {
|
||||
ggml_build_forward_impl(cgraph, tensor, true, false);
|
||||
}
|
||||
|
||||
void ggml_build_backward_expand(
|
||||
struct ggml_context * ctx,
|
||||
struct ggml_cgraph * cgraph,
|
||||
|
||||
@@ -164,6 +164,13 @@ class Keys:
|
||||
NORM_BEFORE_RESIDUAL = "{arch}.norm_before_residual"
|
||||
NORM_BEFORE_FC = "{arch}.norm_before_fc"
|
||||
|
||||
class Adapters:
|
||||
COUNT = "{arch}.adapters.count"
|
||||
TOKEN_IDS_ACTIVATE = "{arch}.adapters.token_ids_activate"
|
||||
TOKEN_IDS_SUBSTITUTE = "{arch}.adapters.token_ids_substitute"
|
||||
LORA_RANK = "{arch}.adapters.lora_rank"
|
||||
ROUTER_GAIN = "{arch}.adapters.router_gain"
|
||||
|
||||
class Attention:
|
||||
HEAD_COUNT = "{arch}.attention.head_count"
|
||||
HEAD_COUNT_KV = "{arch}.attention.head_count_kv"
|
||||
@@ -527,6 +534,7 @@ class MODEL_ARCH(IntEnum):
|
||||
GRANITE = auto()
|
||||
GRANITE_MOE = auto()
|
||||
GRANITE_HYBRID = auto()
|
||||
GRANITE_SWITCH = auto()
|
||||
CHAMELEON = auto()
|
||||
WAVTOKENIZER_DEC = auto()
|
||||
PLM = auto()
|
||||
@@ -1198,6 +1206,7 @@ MODEL_ARCH_NAMES: dict[MODEL_ARCH, str] = {
|
||||
MODEL_ARCH.GRANITE: "granite",
|
||||
MODEL_ARCH.GRANITE_MOE: "granitemoe",
|
||||
MODEL_ARCH.GRANITE_HYBRID: "granitehybrid",
|
||||
MODEL_ARCH.GRANITE_SWITCH: "graniteswitch",
|
||||
MODEL_ARCH.CHAMELEON: "chameleon",
|
||||
MODEL_ARCH.WAVTOKENIZER_DEC: "wavtokenizer-dec",
|
||||
MODEL_ARCH.PLM: "plm",
|
||||
@@ -3972,6 +3981,21 @@ MODEL_TENSORS: dict[MODEL_ARCH, list[MODEL_TENSOR]] = {
|
||||
MODEL_TENSOR.FFN_DOWN,
|
||||
MODEL_TENSOR.FFN_UP,
|
||||
],
|
||||
MODEL_ARCH.GRANITE_SWITCH: [
|
||||
MODEL_TENSOR.TOKEN_EMBD,
|
||||
MODEL_TENSOR.OUTPUT_NORM,
|
||||
MODEL_TENSOR.OUTPUT,
|
||||
MODEL_TENSOR.ATTN_NORM,
|
||||
MODEL_TENSOR.ATTN_QKV,
|
||||
MODEL_TENSOR.ATTN_Q,
|
||||
MODEL_TENSOR.ATTN_K,
|
||||
MODEL_TENSOR.ATTN_V,
|
||||
MODEL_TENSOR.ATTN_OUT,
|
||||
MODEL_TENSOR.FFN_NORM,
|
||||
MODEL_TENSOR.FFN_GATE,
|
||||
MODEL_TENSOR.FFN_DOWN,
|
||||
MODEL_TENSOR.FFN_UP,
|
||||
],
|
||||
MODEL_ARCH.CHAMELEON: [
|
||||
MODEL_TENSOR.TOKEN_EMBD,
|
||||
MODEL_TENSOR.OUTPUT_NORM,
|
||||
|
||||
@@ -906,6 +906,21 @@ class GGUFWriter:
|
||||
def add_embedding_scale(self, value: float) -> None:
|
||||
self.add_float32(Keys.LLM.EMBEDDING_SCALE.format(arch=self.arch), value)
|
||||
|
||||
def add_adapter_count(self, count: int) -> None:
|
||||
self.add_uint32(Keys.Adapters.COUNT.format(arch=self.arch), count)
|
||||
|
||||
def add_adapter_token_ids_activate(self, ids: Sequence[int]) -> None:
|
||||
self.add_array(Keys.Adapters.TOKEN_IDS_ACTIVATE.format(arch=self.arch), ids)
|
||||
|
||||
def add_adapter_token_ids_substitute(self, ids: Sequence[int]) -> None:
|
||||
self.add_array(Keys.Adapters.TOKEN_IDS_SUBSTITUTE.format(arch=self.arch), ids)
|
||||
|
||||
def add_adapter_lora_rank(self, rank: int) -> None:
|
||||
self.add_uint32(Keys.Adapters.LORA_RANK.format(arch=self.arch), rank)
|
||||
|
||||
def add_adapter_router_gain(self, gain: float) -> None:
|
||||
self.add_float32(Keys.Adapters.ROUTER_GAIN.format(arch=self.arch), gain)
|
||||
|
||||
def add_wkv_head_size(self, size: int) -> None:
|
||||
self.add_uint32(Keys.WKV.HEAD_SIZE.format(arch=self.arch), size)
|
||||
|
||||
|
||||
@@ -59,11 +59,29 @@ def byteswap_q6_k(tensor, block_offs):
|
||||
delta.byteswap(inplace=True)
|
||||
|
||||
|
||||
def byteswap_q1_0(tensor, block_offs):
|
||||
# Each block_q1_0 consists of an f16 delta followed by 16 int8 quantizations.
|
||||
|
||||
# Byte-Swap f16 sized delta field
|
||||
delta = tensor.data[block_offs:block_offs + 2].view(dtype=np.uint16)
|
||||
delta.byteswap(inplace=True)
|
||||
|
||||
|
||||
def byteswap_tq2_0(tensor, block_offs):
|
||||
# Each block_tq2_0 consists of 64 int8 values followed by 1 f16 value.
|
||||
|
||||
# Byte-Swap f16 sized field
|
||||
delta = tensor.data[block_offs + 64:block_offs + 66].view(dtype=np.uint16)
|
||||
delta.byteswap(inplace=True)
|
||||
|
||||
|
||||
byteswap_tensors = {
|
||||
gguf.GGMLQuantizationType.Q1_0: byteswap_q1_0,
|
||||
gguf.GGMLQuantizationType.Q4_0: byteswap_q4_0,
|
||||
gguf.GGMLQuantizationType.Q8_0: byteswap_q8_0,
|
||||
gguf.GGMLQuantizationType.Q4_K: byteswap_q4_k,
|
||||
gguf.GGMLQuantizationType.Q6_K: byteswap_q6_k,
|
||||
gguf.GGMLQuantizationType.TQ2_0: byteswap_tq2_0,
|
||||
gguf.GGMLQuantizationType.MXFP4: byteswap_noop,
|
||||
gguf.GGMLQuantizationType.NVFP4: byteswap_noop,
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
90951f99af1fbebef3fbdd58ff5b8715b0bb9c43
|
||||
30bf8685ed4eb0a47f2b06229543327749904150
|
||||
|
||||
+22
-1
@@ -5,7 +5,7 @@ import os
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
HTTPLIB_VERSION = "refs/tags/v0.52.0"
|
||||
HTTPLIB_VERSION = "refs/tags/v0.53.0"
|
||||
|
||||
vendor = {
|
||||
"https://github.com/nlohmann/json/releases/latest/download/json.hpp": "vendor/nlohmann/json.hpp",
|
||||
@@ -24,10 +24,31 @@ vendor = {
|
||||
"https://raw.githubusercontent.com/sheredom/subprocess.h/8671cee1fc09f11a70ce3782a0ee13177c3aa387/subprocess.h": "vendor/sheredom/subprocess.h",
|
||||
}
|
||||
|
||||
# TODO @ngxson : this is temporary, to be removed in the future
|
||||
patches = [
|
||||
# https://github.com/sheredom/subprocess.h/pull/102
|
||||
"vendor/sheredom/patch-bsd.patch",
|
||||
# https://github.com/sheredom/subprocess.h/pull/101
|
||||
"vendor/sheredom/patch-windows-quote-backslash.patch",
|
||||
# https://github.com/sheredom/subprocess.h/pull/104
|
||||
# note: must be applied after patch-bsd.patch, they touch adjacent lines
|
||||
"vendor/sheredom/patch-glibc-older-than-2.29.patch",
|
||||
]
|
||||
|
||||
for url, filename in vendor.items():
|
||||
print(f"downloading {url} to {filename}") # noqa: NP100
|
||||
urllib.request.urlretrieve(url, filename)
|
||||
|
||||
for patch in patches:
|
||||
print(f"applying {patch}") # noqa: NP100
|
||||
try:
|
||||
subprocess.check_call([
|
||||
"git", "apply", "--directory", os.path.dirname(patch), patch
|
||||
])
|
||||
except Exception as e:
|
||||
print(f"Error: {e}") # noqa: NP100
|
||||
sys.exit(1)
|
||||
|
||||
print("Splitting httplib.h...") # noqa: NP100
|
||||
try:
|
||||
subprocess.check_call([
|
||||
|
||||
@@ -100,6 +100,7 @@ static const std::map<llm_arch, const char *> LLM_ARCH_NAMES = {
|
||||
{ LLM_ARCH_GRANITE, "granite" },
|
||||
{ LLM_ARCH_GRANITE_MOE, "granitemoe" },
|
||||
{ LLM_ARCH_GRANITE_HYBRID, "granitehybrid" },
|
||||
{ LLM_ARCH_GRANITE_SWITCH, "graniteswitch" },
|
||||
{ LLM_ARCH_CHAMELEON, "chameleon" },
|
||||
{ LLM_ARCH_WAVTOKENIZER_DEC, "wavtokenizer-dec" },
|
||||
{ LLM_ARCH_PLM, "plm" },
|
||||
@@ -220,6 +221,11 @@ static const std::map<llm_kv, const char *> LLM_KV_NAMES = {
|
||||
{ LLM_KV_TIME_DECAY_EXTRA_DIM, "%s.time_decay_extra_dim" },
|
||||
{ LLM_KV_RESIDUAL_SCALE, "%s.residual_scale" },
|
||||
{ LLM_KV_EMBEDDING_SCALE, "%s.embedding_scale" },
|
||||
{ LLM_KV_ADAPTER_COUNT, "%s.adapters.count" },
|
||||
{ LLM_KV_ADAPTER_TOKEN_IDS_ACTIVATE, "%s.adapters.token_ids_activate" },
|
||||
{ LLM_KV_ADAPTER_TOKEN_IDS_SUBSTITUTE, "%s.adapters.token_ids_substitute" },
|
||||
{ LLM_KV_ADAPTER_LORA_RANK, "%s.adapters.lora_rank" },
|
||||
{ LLM_KV_ADAPTER_ROUTER_GAIN, "%s.adapters.router_gain" },
|
||||
{ LLM_KV_TOKEN_SHIFT_COUNT, "%s.token_shift_count" },
|
||||
{ LLM_KV_INTERLEAVE_MOE_LAYER_STEP, "%s.interleave_moe_layer_step" },
|
||||
{ LLM_KV_FULL_ATTENTION_INTERVAL, "%s.full_attention_interval" },
|
||||
|
||||
@@ -105,6 +105,7 @@ enum llm_arch {
|
||||
LLM_ARCH_GRANITE,
|
||||
LLM_ARCH_GRANITE_MOE,
|
||||
LLM_ARCH_GRANITE_HYBRID,
|
||||
LLM_ARCH_GRANITE_SWITCH,
|
||||
LLM_ARCH_CHAMELEON,
|
||||
LLM_ARCH_WAVTOKENIZER_DEC,
|
||||
LLM_ARCH_PLM,
|
||||
@@ -225,6 +226,11 @@ enum llm_kv {
|
||||
LLM_KV_TIME_DECAY_EXTRA_DIM,
|
||||
LLM_KV_RESIDUAL_SCALE,
|
||||
LLM_KV_EMBEDDING_SCALE,
|
||||
LLM_KV_ADAPTER_COUNT,
|
||||
LLM_KV_ADAPTER_TOKEN_IDS_ACTIVATE,
|
||||
LLM_KV_ADAPTER_TOKEN_IDS_SUBSTITUTE,
|
||||
LLM_KV_ADAPTER_LORA_RANK,
|
||||
LLM_KV_ADAPTER_ROUTER_GAIN,
|
||||
LLM_KV_TOKEN_SHIFT_COUNT,
|
||||
LLM_KV_INTERLEAVE_MOE_LAYER_STEP,
|
||||
LLM_KV_FULL_ATTENTION_INTERVAL,
|
||||
|
||||
@@ -3602,8 +3602,9 @@ llama_context * llama_init_from_model(
|
||||
model->hparams.pooling_type, params.pooling_type);
|
||||
}
|
||||
|
||||
// router_layer >= 0 means n_layer_nextn is repurposed for a router layer, not real MTP
|
||||
if (params.ctx_type == LLAMA_CONTEXT_TYPE_MTP &&
|
||||
model->hparams.n_layer_nextn == 0) {
|
||||
(model->hparams.n_layer_nextn == 0 || model->hparams.router_layer >= 0)) {
|
||||
LLAMA_LOG_WARN("%s: context type MTP requested but model doesn't contain MTP layers\n", __func__);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -648,10 +648,12 @@ const char * llama_grammar_parser::parse_sequence(
|
||||
} else {
|
||||
throw std::runtime_error(std::string("expecting ',' at ") + pos);
|
||||
}
|
||||
bool has_max = max_times != UINT64_MAX;
|
||||
if (min_times > MAX_REPETITION_THRESHOLD || (has_max && max_times > MAX_REPETITION_THRESHOLD)) {
|
||||
if (min_times > MAX_REPETITION_THRESHOLD) {
|
||||
throw std::runtime_error(std::string("number of repetitions exceeds sane defaults, please reduce the number of repetitions"));
|
||||
}
|
||||
if (max_times != UINT64_MAX && max_times > MAX_REPETITION_THRESHOLD) {
|
||||
max_times = UINT64_MAX;
|
||||
}
|
||||
handle_repetitions(min_times, max_times);
|
||||
} else {
|
||||
break;
|
||||
|
||||
@@ -277,6 +277,16 @@ bool llama_hparams::has_kv(uint32_t il) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool llama_hparams::has_rope(uint32_t il) const {
|
||||
// the router layer stores adapter routing signal, not positional info,
|
||||
// so it must not be RoPE-shifted
|
||||
if (router_layer >= 0 && (int32_t) il == router_layer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t llama_hparams::n_layer() const {
|
||||
return n_layer_all - n_layer_nextn;
|
||||
}
|
||||
|
||||
@@ -53,6 +53,10 @@ struct llama_hparams {
|
||||
uint32_t n_embd;
|
||||
uint32_t n_layer_all;
|
||||
uint32_t n_layer_nextn = 0;
|
||||
|
||||
// granite-switch: index of the single-head "router" KV layer that encodes
|
||||
// per-token adapter selection. -1 when the model has no such layer.
|
||||
int32_t router_layer = -1;
|
||||
uint32_t n_expert = 0;
|
||||
uint32_t n_expert_used = 0;
|
||||
uint32_t n_rel_attn_bkts = 0;
|
||||
@@ -371,6 +375,8 @@ struct llama_hparams {
|
||||
|
||||
bool has_kv(uint32_t il) const;
|
||||
|
||||
bool has_rope(uint32_t il) const;
|
||||
|
||||
// number of effective layers (excludes nextn layers)
|
||||
uint32_t n_layer() const;
|
||||
|
||||
|
||||
@@ -1931,6 +1931,10 @@ ggml_cgraph * llama_kv_cache::build_graph_shift(llm_graph_result * res, llama_co
|
||||
for (const auto & layer : layers) {
|
||||
const uint32_t il = layer.il;
|
||||
|
||||
if (!hparams.has_rope(il)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const int64_t n_head_kv = hparams.n_head_kv(il);
|
||||
const int64_t n_embd_k_gqa = hparams.n_embd_k_gqa(il);
|
||||
|
||||
|
||||
+28
-14
@@ -937,10 +937,11 @@ static bool weight_buft_supported(const llama_hparams & hparams, ggml_tensor * w
|
||||
} break;
|
||||
case GGML_OP_MUL_MAT_ID:
|
||||
{
|
||||
const int n_expert_used = hparams.n_expert_used;
|
||||
GGML_ASSERT(n_expert_used > 0);
|
||||
ggml_tensor * b = ggml_new_tensor_3d(ctx, GGML_TYPE_F32, w->ne[0], n_expert_used, 512);
|
||||
ggml_tensor * ids = ggml_new_tensor_2d(ctx, GGML_TYPE_I32, n_expert_used, 512);
|
||||
// Used for either MoE expert routing or embedded adapter routing
|
||||
const int n_ids_used = hparams.router_layer >= 0 ? 1 : hparams.n_expert_used;
|
||||
GGML_ASSERT(n_ids_used > 0);
|
||||
ggml_tensor * b = ggml_new_tensor_3d(ctx, GGML_TYPE_F32, w->ne[0], n_ids_used, 512);
|
||||
ggml_tensor * ids = ggml_new_tensor_2d(ctx, GGML_TYPE_I32, n_ids_used, 512);
|
||||
op_tensor = ggml_mul_mat_id(ctx, w, b, ids);
|
||||
} break;
|
||||
case GGML_OP_ADD:
|
||||
@@ -1123,15 +1124,14 @@ struct ggml_tensor * llama_model_loader::create_tensor(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// tensors with "bias" suffix are always used with GGML_OP_ADD or GGML_OP_ADD_ID
|
||||
// tensors with "bias" suffix are always used with GGML_OP_ADD or GGML_OP_ADD_ID;
|
||||
// embedded-adapter ".lora_a"/".lora_b" tensors are always used with GGML_OP_MUL_MAT_ID
|
||||
ggml_op op;
|
||||
bool bias = tn.suffix != nullptr && strcmp(tn.suffix, "bias") == 0;
|
||||
if (bias) {
|
||||
if (info.op == GGML_OP_MUL_MAT_ID) {
|
||||
op = GGML_OP_ADD_ID;
|
||||
} else {
|
||||
op = GGML_OP_ADD;
|
||||
}
|
||||
if (tn.suffix != nullptr && strcmp(tn.suffix, "bias") == 0) {
|
||||
op = info.op == GGML_OP_MUL_MAT_ID ? GGML_OP_ADD_ID : GGML_OP_ADD;
|
||||
} else if (hparams.router_layer >= 0 && tn.suffix != nullptr &&
|
||||
(strcmp(tn.suffix, "lora_a") == 0 || strcmp(tn.suffix, "lora_b") == 0)) {
|
||||
op = GGML_OP_MUL_MAT_ID;
|
||||
} else {
|
||||
op = info.op;
|
||||
}
|
||||
@@ -1249,7 +1249,13 @@ struct ggml_tensor * llama_model_loader::create_tensor(
|
||||
for (size_t dim = 0; dim < GGML_MAX_DIMS; dim++) {
|
||||
t_meta.ne[dim] = dim < ne.size() ? ne.begin()[dim] : 1;
|
||||
GGML_ASSERT(t_meta.ne[dim] >= 1);
|
||||
t_meta.nb[dim] = dim == 0 ? ggml_type_size(type) : t_meta.ne[dim-1]*t_meta.nb[dim-1];
|
||||
if (dim == 0) {
|
||||
t_meta.nb[dim] = ggml_type_size(type);
|
||||
} else if (dim == 1) {
|
||||
t_meta.nb[dim] = ggml_row_size(type, t_meta.ne[dim-1]);
|
||||
} else {
|
||||
t_meta.nb[dim] = t_meta.nb[dim-1]*t_meta.ne[dim-1];
|
||||
}
|
||||
GGML_ASSERT(t_meta.nb[dim] >= 1);
|
||||
}
|
||||
ggml_set_name(&t_meta, tn.str().c_str());
|
||||
@@ -1272,10 +1278,18 @@ struct ggml_tensor * llama_model_loader::create_tensor(
|
||||
if (flags & TENSOR_ALLOW_RESHAPE) {
|
||||
for (size_t dim = 0; dim < GGML_MAX_DIMS; dim++) {
|
||||
t_meta.ne[dim] = dim < ne.size() ? ne.begin()[dim] : 1;
|
||||
t_meta.nb[dim] = dim == 0 ? ggml_type_size(t_meta.type) : t_meta.ne[dim-1]*t_meta.nb[dim-1];
|
||||
if (dim == 0) {
|
||||
t_meta.nb[dim] = ggml_type_size(t_meta.type);
|
||||
} else if (dim == 1) {
|
||||
t_meta.nb[dim] = ggml_row_size(t_meta.type, t_meta.ne[dim-1]);
|
||||
} else {
|
||||
t_meta.nb[dim] = t_meta.ne[dim-1]*t_meta.nb[dim-1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GGML_ASSERT(ggml_nbytes(&t_meta) == ggml_nbytes(cur));
|
||||
|
||||
ggml_backend_buffer_type_t buft = buft_for_tensor(&t_meta);
|
||||
if (buft == nullptr) {
|
||||
return nullptr;
|
||||
|
||||
@@ -213,7 +213,7 @@ void llama_model_saver::add_kv_from_model() {
|
||||
add_kv(LLM_KV_FEED_FORWARD_LENGTH, hparams.n_ff_arr, true);
|
||||
add_kv(LLM_KV_EXPERT_FEED_FORWARD_LENGTH, hparams.n_ff_exp);
|
||||
add_kv(LLM_KV_EXPERT_SHARED_FEED_FORWARD_LENGTH, hparams.n_ff_shexp);
|
||||
add_kv(LLM_KV_EXPERT_SHARED_FEED_FORWARD_LENGTH, hparams.n_ff_chexp);
|
||||
add_kv(LLM_KV_EXPERT_CHUNK_FEED_FORWARD_LENGTH, hparams.n_ff_chexp);
|
||||
add_kv(LLM_KV_SWIGLU_CLAMP_EXP, hparams.swiglu_clamp_exp);
|
||||
add_kv(LLM_KV_SWIGLU_CLAMP_SHEXP, hparams.swiglu_clamp_shexp);
|
||||
add_kv(LLM_KV_USE_PARALLEL_RESIDUAL, hparams.use_par_res);
|
||||
|
||||
@@ -234,6 +234,8 @@ static llama_model * llama_model_mapping(llm_arch arch, const llama_model_params
|
||||
return new llama_model_granite(params);
|
||||
case LLM_ARCH_GRANITE_MOE:
|
||||
return new llama_model_granite_moe(params);
|
||||
case LLM_ARCH_GRANITE_SWITCH:
|
||||
return new llama_model_granite_switch(params);
|
||||
case LLM_ARCH_MINICPM:
|
||||
return new llama_model_minicpm(params);
|
||||
case LLM_ARCH_GRANITE_HYBRID:
|
||||
@@ -1912,6 +1914,7 @@ void llama_model::print_info() const {
|
||||
arch == LLM_ARCH_GRANITE ||
|
||||
arch == LLM_ARCH_GRANITE_MOE ||
|
||||
arch == LLM_ARCH_GRANITE_HYBRID ||
|
||||
arch == LLM_ARCH_GRANITE_SWITCH ||
|
||||
arch == LLM_ARCH_NEMOTRON_H_MOE) {
|
||||
LLAMA_LOG_INFO("%s: f_embedding_scale = %f\n", __func__, hparams.f_embedding_scale);
|
||||
LLAMA_LOG_INFO("%s: f_residual_scale = %f\n", __func__, hparams.f_residual_scale);
|
||||
@@ -2596,6 +2599,7 @@ llama_rope_type llama_model_rope_type(const llama_model * model) {
|
||||
case LLM_ARCH_GRANITE:
|
||||
case LLM_ARCH_GRANITE_MOE:
|
||||
case LLM_ARCH_GRANITE_HYBRID:
|
||||
case LLM_ARCH_GRANITE_SWITCH:
|
||||
case LLM_ARCH_CHAMELEON:
|
||||
case LLM_ARCH_BAILINGMOE:
|
||||
case LLM_ARCH_NEO_BERT:
|
||||
@@ -2890,6 +2894,21 @@ void llama_model_base::create_tensor_qkv(llama_layer & layer, int bid,
|
||||
int64_t n_embd_, int64_t n_embd_q_, int64_t n_embd_k_, int64_t n_embd_v_,
|
||||
int flags) {
|
||||
const int64_t n_embd_qkv = n_embd_q_ + n_embd_k_ + n_embd_v_;
|
||||
|
||||
if (flags & TENSOR_SKIP) {
|
||||
const int skip = TENSOR_NOT_REQUIRED | TENSOR_SKIP;
|
||||
|
||||
create_tensor(tn(LLM_TENSOR_ATTN_QKV, "weight", bid), {n_embd_, n_embd_qkv}, skip | TENSOR_SKIP_IF_VIRTUAL);
|
||||
create_tensor(tn(LLM_TENSOR_ATTN_QKV, "bias", bid), {n_embd_qkv}, skip | TENSOR_SKIP_IF_VIRTUAL);
|
||||
create_tensor(tn(LLM_TENSOR_ATTN_Q, "weight", bid), {n_embd_, n_embd_q_}, skip);
|
||||
create_tensor(tn(LLM_TENSOR_ATTN_K, "weight", bid), {n_embd_, n_embd_k_}, skip);
|
||||
create_tensor(tn(LLM_TENSOR_ATTN_V, "weight", bid), {n_embd_, n_embd_v_}, skip);
|
||||
create_tensor(tn(LLM_TENSOR_ATTN_Q, "bias", bid), {n_embd_q_}, skip);
|
||||
create_tensor(tn(LLM_TENSOR_ATTN_K, "bias", bid), {n_embd_k_}, skip);
|
||||
create_tensor(tn(LLM_TENSOR_ATTN_V, "bias", bid), {n_embd_v_}, skip);
|
||||
return;
|
||||
}
|
||||
|
||||
layer.wqkv = create_tensor(tn(LLM_TENSOR_ATTN_QKV, "weight", bid), {n_embd_, n_embd_qkv}, TENSOR_NOT_REQUIRED | TENSOR_SKIP_IF_VIRTUAL);
|
||||
if (layer.wqkv) {
|
||||
layer.wqkv_b = create_tensor(tn(LLM_TENSOR_ATTN_QKV, "bias", bid), {n_embd_qkv}, TENSOR_NOT_REQUIRED | TENSOR_SKIP_IF_VIRTUAL);
|
||||
|
||||
@@ -223,6 +223,24 @@ struct llama_layer_nextn {
|
||||
struct ggml_tensor * shared_head_norm = nullptr;
|
||||
};
|
||||
|
||||
struct llama_layer_switch_lora {
|
||||
struct ggml_tensor * a_q = nullptr;
|
||||
struct ggml_tensor * b_q = nullptr;
|
||||
struct ggml_tensor * a_k = nullptr;
|
||||
struct ggml_tensor * b_k = nullptr;
|
||||
struct ggml_tensor * a_v = nullptr;
|
||||
struct ggml_tensor * b_v = nullptr;
|
||||
struct ggml_tensor * a_o = nullptr;
|
||||
struct ggml_tensor * b_o = nullptr;
|
||||
|
||||
struct ggml_tensor * a_gate = nullptr;
|
||||
struct ggml_tensor * b_gate = nullptr;
|
||||
struct ggml_tensor * a_up = nullptr;
|
||||
struct ggml_tensor * b_up = nullptr;
|
||||
struct ggml_tensor * a_down = nullptr;
|
||||
struct ggml_tensor * b_down = nullptr;
|
||||
};
|
||||
|
||||
struct llama_layer {
|
||||
// normalization
|
||||
struct ggml_tensor * attn_norm = nullptr;
|
||||
@@ -533,6 +551,8 @@ struct llama_layer {
|
||||
struct llama_layer_shortconv shortconv;
|
||||
|
||||
struct llama_layer_nextn nextn;
|
||||
|
||||
struct llama_layer_switch_lora switch_lora;
|
||||
};
|
||||
|
||||
struct llama_device {
|
||||
|
||||
@@ -0,0 +1,426 @@
|
||||
#include "models.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
void llama_model_granite_switch::load_arch_hparams(llama_model_loader & ml) {
|
||||
ml.get_key(LLM_KV_ATTENTION_LAYERNORM_RMS_EPS, hparams.f_norm_rms_eps);
|
||||
ml.get_key(LLM_KV_LOGIT_SCALE, hparams.f_logit_scale);
|
||||
ml.get_key(LLM_KV_RESIDUAL_SCALE, hparams.f_residual_scale, false);
|
||||
ml.get_key(LLM_KV_EMBEDDING_SCALE, hparams.f_embedding_scale, false);
|
||||
ml.get_key(LLM_KV_ATTENTION_SCALE, hparams.f_attention_scale, false);
|
||||
|
||||
bool rope_finetuned = true;
|
||||
ml.get_key(LLM_KV_ROPE_SCALING_FINETUNED, rope_finetuned, false);
|
||||
hparams.rope_finetuned = rope_finetuned;
|
||||
|
||||
switch (hparams.n_layer()) {
|
||||
case 40: type = hparams.n_embd == 4096 ? LLM_TYPE_8B : LLM_TYPE_3B; break;
|
||||
case 64: type = LLM_TYPE_30B; break;
|
||||
default: type = LLM_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
ml.get_key(LLM_KV_EXPERT_SHARED_FEED_FORWARD_LENGTH, hparams.n_ff_shexp, /* required */ false);
|
||||
|
||||
ml.get_key(LLM_KV_ADAPTER_COUNT, n_adapters);
|
||||
ml.get_key(LLM_KV_ADAPTER_LORA_RANK, max_lora_rank);
|
||||
ml.get_key(LLM_KV_ADAPTER_ROUTER_GAIN, router_gain, /* required */ false);
|
||||
|
||||
// bound counts that size tensors
|
||||
if (n_adapters > 4096) {
|
||||
throw std::runtime_error(format("graniteswitch: invalid adapter count %u", n_adapters));
|
||||
}
|
||||
if (max_lora_rank > 4096) {
|
||||
throw std::runtime_error(format("graniteswitch: invalid lora rank %u", max_lora_rank));
|
||||
}
|
||||
|
||||
std::vector<llama_token> token_ids;
|
||||
std::vector<llama_token> substitute_ids;
|
||||
ml.get_arr(LLM_KV_ADAPTER_TOKEN_IDS_ACTIVATE, token_ids);
|
||||
ml.get_arr(LLM_KV_ADAPTER_TOKEN_IDS_SUBSTITUTE, substitute_ids);
|
||||
|
||||
if (token_ids.size() != n_adapters || substitute_ids.size() != n_adapters) {
|
||||
throw std::runtime_error(format(
|
||||
"graniteswitch: adapter token id arrays (%zu activate, %zu substitute) do not match adapter count %u",
|
||||
token_ids.size(), substitute_ids.size(), n_adapters));
|
||||
}
|
||||
|
||||
adapter_token_to_slot.clear();
|
||||
adapter_token_to_substitute.clear();
|
||||
for (uint32_t i = 0; i < n_adapters; ++i) {
|
||||
// adapter i -> stacked slot i+1 (slot 0 is the base/zero delta)
|
||||
adapter_token_to_slot[token_ids[i]] = (int32_t) (i + 1);
|
||||
adapter_token_to_substitute[token_ids[i]] = substitute_ids[i];
|
||||
}
|
||||
|
||||
// extra single-head attention layer at the END (index n_real) holds the router
|
||||
// K/V. reusing n_layer_nextn keeps n_layer() == n_real, so the regular layers
|
||||
// keep their indices and the KV cache shift/defrag skips the router layer.
|
||||
// n_layer_nextn is repurposed here (no MTP): it leaks as 1 into the
|
||||
// llama_model_n_layer_nextn() getter and a re-saved nextn_predict_layers
|
||||
const uint32_t n_real = hparams.n_layer();
|
||||
if (n_real >= LLAMA_MAX_LAYERS) {
|
||||
throw std::runtime_error(format("graniteswitch: block count %u exceeds LLAMA_MAX_LAYERS", n_real));
|
||||
}
|
||||
hparams.router_layer = (int32_t) n_real;
|
||||
hparams.n_layer_all = n_real + 1;
|
||||
hparams.n_layer_nextn = 1;
|
||||
|
||||
hparams.n_head_arr[n_real] = 1;
|
||||
hparams.n_head_kv_arr[n_real] = 1;
|
||||
hparams.n_ff_arr[n_real] = 0;
|
||||
}
|
||||
|
||||
void llama_model_granite_switch::load_arch_tensors(llama_model_loader &) {
|
||||
LLAMA_LOAD_LOCALS;
|
||||
|
||||
const int64_t n_slots = (int64_t) n_adapters + 1; // slot 0 = base/zero delta
|
||||
const int64_t n_rank = (int64_t) max_lora_rank;
|
||||
const int64_t n_embd_q = n_embd_head_k * n_head;
|
||||
const int64_t n_embd_kv = n_embd_k_gqa;
|
||||
|
||||
tok_embd = create_tensor(tn(LLM_TENSOR_TOKEN_EMBD, "weight"), {n_embd, n_vocab}, 0);
|
||||
|
||||
// substitute ids index tok_embd rows directly; range-check against n_vocab
|
||||
for (const auto & kv : adapter_token_to_substitute) {
|
||||
const llama_token sub = kv.second;
|
||||
if (sub < 0 || (int64_t) sub >= n_vocab) {
|
||||
throw std::runtime_error(format(
|
||||
"graniteswitch: substitute token id %d out of range [0, %d)", sub, (int) n_vocab));
|
||||
}
|
||||
}
|
||||
|
||||
output_norm = create_tensor(tn(LLM_TENSOR_OUTPUT_NORM, "weight"), {n_embd}, 0);
|
||||
output = create_tensor(tn(LLM_TENSOR_OUTPUT, "weight"), {n_embd, n_vocab}, TENSOR_NOT_REQUIRED);
|
||||
if (output == NULL) {
|
||||
output = create_tensor(tn(LLM_TENSOR_TOKEN_EMBD, "weight"), {n_embd, n_vocab}, TENSOR_DUPLICATED);
|
||||
}
|
||||
|
||||
for (int i = 0; i < n_layer; ++i) {
|
||||
auto & layer = layers[i];
|
||||
|
||||
layer.attn_norm = create_tensor(tn(LLM_TENSOR_ATTN_NORM, "weight", i), {n_embd}, 0);
|
||||
|
||||
layer.wqkv = create_tensor(tn(LLM_TENSOR_ATTN_QKV, "weight", i), {n_embd, n_embd_q + 2*n_embd_kv}, 0);
|
||||
layer.wo = create_tensor(tn(LLM_TENSOR_ATTN_OUT, "weight", i), {n_embd_q, n_embd}, 0);
|
||||
|
||||
layer.ffn_norm = create_tensor(tn(LLM_TENSOR_FFN_NORM, "weight", i), {n_embd}, 0);
|
||||
|
||||
layer.ffn_gate = create_tensor(tn(LLM_TENSOR_FFN_GATE, "weight", i), {n_embd, n_ff}, 0);
|
||||
layer.ffn_down = create_tensor(tn(LLM_TENSOR_FFN_DOWN, "weight", i), { n_ff, n_embd}, 0);
|
||||
layer.ffn_up = create_tensor(tn(LLM_TENSOR_FFN_UP, "weight", i), {n_embd, n_ff}, 0);
|
||||
|
||||
auto & sl = layer.switch_lora;
|
||||
|
||||
sl.a_q = create_tensor(tn(LLM_TENSOR_ATTN_Q, "lora_a", i), {n_embd, n_rank, n_slots}, 0);
|
||||
sl.b_q = create_tensor(tn(LLM_TENSOR_ATTN_Q, "lora_b", i), {n_rank, n_embd_q, n_slots}, 0);
|
||||
sl.a_k = create_tensor(tn(LLM_TENSOR_ATTN_K, "lora_a", i), {n_embd, n_rank, n_slots}, 0);
|
||||
sl.b_k = create_tensor(tn(LLM_TENSOR_ATTN_K, "lora_b", i), {n_rank, n_embd_kv, n_slots}, 0);
|
||||
sl.a_v = create_tensor(tn(LLM_TENSOR_ATTN_V, "lora_a", i), {n_embd, n_rank, n_slots}, 0);
|
||||
sl.b_v = create_tensor(tn(LLM_TENSOR_ATTN_V, "lora_b", i), {n_rank, n_embd_kv, n_slots}, 0);
|
||||
|
||||
sl.a_o = create_tensor(tn(LLM_TENSOR_ATTN_OUT, "lora_a", i), {n_embd_q, n_rank, n_slots}, 0);
|
||||
sl.b_o = create_tensor(tn(LLM_TENSOR_ATTN_OUT, "lora_b", i), {n_rank, n_embd, n_slots}, 0);
|
||||
|
||||
sl.a_gate = create_tensor(tn(LLM_TENSOR_FFN_GATE, "lora_a", i), {n_embd, n_rank, n_slots}, 0);
|
||||
sl.b_gate = create_tensor(tn(LLM_TENSOR_FFN_GATE, "lora_b", i), {n_rank, n_ff, n_slots}, 0);
|
||||
sl.a_up = create_tensor(tn(LLM_TENSOR_FFN_UP, "lora_a", i), {n_embd, n_rank, n_slots}, 0);
|
||||
sl.b_up = create_tensor(tn(LLM_TENSOR_FFN_UP, "lora_b", i), {n_rank, n_ff, n_slots}, 0);
|
||||
sl.a_down = create_tensor(tn(LLM_TENSOR_FFN_DOWN, "lora_a", i), { n_ff, n_rank, n_slots}, 0);
|
||||
sl.b_down = create_tensor(tn(LLM_TENSOR_FFN_DOWN, "lora_b", i), {n_rank, n_embd, n_slots}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
class llm_graph_input_switch : public llm_graph_input_i {
|
||||
public:
|
||||
llm_graph_input_switch(const llama_model_granite_switch & smodel) : smodel(smodel) {}
|
||||
virtual ~llm_graph_input_switch() = default;
|
||||
|
||||
void set_input(const llama_ubatch * ubatch) override;
|
||||
|
||||
ggml_tensor * sub_tokens = nullptr; // I32 [n_tokens] adapter-substituted token ids
|
||||
ggml_tensor * router_ksig = nullptr; // F32 [n_tokens] router K signal (+/-gain)
|
||||
ggml_tensor * router_vval = nullptr; // F32 [n_tokens] router V value (adapter slot / 0)
|
||||
ggml_tensor * router_q = nullptr; // F32 [n_tokens] router Q value (constant 1.0)
|
||||
|
||||
const llama_model_granite_switch & smodel;
|
||||
};
|
||||
|
||||
// K dim-0 is +gain for an adapter token, -gain otherwise; the causal softmax then
|
||||
// lets a single visible adapter token dominate so the readback recovers its slot.
|
||||
void llm_graph_input_switch::set_input(const llama_ubatch * ubatch) {
|
||||
if (!ubatch->token) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int64_t n_tokens = ubatch->n_tokens;
|
||||
|
||||
std::vector<int32_t> sub (n_tokens);
|
||||
std::vector<float> ksig(n_tokens);
|
||||
std::vector<float> vval(n_tokens);
|
||||
std::vector<float> q (n_tokens, 1.0f);
|
||||
|
||||
for (int64_t i = 0; i < n_tokens; ++i) {
|
||||
const llama_token tok = ubatch->token[i];
|
||||
|
||||
const auto it = smodel.adapter_token_to_slot.find(tok);
|
||||
if (it != smodel.adapter_token_to_slot.end()) {
|
||||
ksig[i] = +smodel.router_gain;
|
||||
vval[i] = (float) it->second;
|
||||
} else {
|
||||
ksig[i] = -smodel.router_gain;
|
||||
vval[i] = 0.0f;
|
||||
}
|
||||
|
||||
const auto sit = smodel.adapter_token_to_substitute.find(tok);
|
||||
sub[i] = (sit != smodel.adapter_token_to_substitute.end())
|
||||
? (int32_t) sit->second
|
||||
: (int32_t) tok;
|
||||
}
|
||||
|
||||
ggml_backend_tensor_set(sub_tokens, sub.data(), 0, n_tokens*ggml_element_size(sub_tokens));
|
||||
ggml_backend_tensor_set(router_ksig, ksig.data(), 0, n_tokens*ggml_element_size(router_ksig));
|
||||
ggml_backend_tensor_set(router_vval, vval.data(), 0, n_tokens*ggml_element_size(router_vval));
|
||||
ggml_backend_tensor_set(router_q, q.data(), 0, n_tokens*ggml_element_size(router_q));
|
||||
}
|
||||
|
||||
std::unique_ptr<llm_graph_context> llama_model_granite_switch::build_arch_graph(const llm_graph_params & params) const {
|
||||
return std::make_unique<graph>(*this, params);
|
||||
}
|
||||
|
||||
// per-token switched LoRA delta: B_a*(A_a*x), adapter selected per token via ids.
|
||||
// cur: {n_in, n_tokens}, ids: {n_tokens} -> {n_out, n_tokens}
|
||||
ggml_tensor * llama_model_granite_switch::graph::build_switched_lora_delta(
|
||||
ggml_tensor * lora_a,
|
||||
ggml_tensor * lora_b,
|
||||
ggml_tensor * cur,
|
||||
ggml_tensor * ids) {
|
||||
const int64_t n_in = cur->ne[0];
|
||||
const int64_t n_tokens = cur->ne[1];
|
||||
|
||||
ggml_tensor * x = ggml_reshape_3d(ctx0, cur, n_in, 1, n_tokens);
|
||||
ggml_tensor * ids2 = ggml_reshape_2d(ctx0, ids, 1, n_tokens);
|
||||
|
||||
ggml_tensor * a = ggml_mul_mat_id(ctx0, lora_a, x, ids2); // {max_rank, 1, n_tokens}
|
||||
ggml_tensor * d = ggml_mul_mat_id(ctx0, lora_b, a, ids2); // {n_out, 1, n_tokens}
|
||||
|
||||
return ggml_reshape_2d(ctx0, d, d->ne[0], n_tokens);
|
||||
}
|
||||
|
||||
ggml_tensor * llama_model_granite_switch::graph::build_switched_lora_mm(
|
||||
ggml_tensor * w,
|
||||
ggml_tensor * lora_a,
|
||||
ggml_tensor * lora_b,
|
||||
ggml_tensor * cur,
|
||||
ggml_tensor * ids) {
|
||||
ggml_tensor * base = ggml_mul_mat(ctx0, w, cur);
|
||||
ggml_tensor * delta = build_switched_lora_delta(lora_a, lora_b, cur, ids);
|
||||
return ggml_add(ctx0, base, delta);
|
||||
}
|
||||
|
||||
llama_model_granite_switch::graph::graph(
|
||||
const llama_model & model,
|
||||
const llm_graph_params & params)
|
||||
: llm_graph_context(params) {
|
||||
|
||||
const auto & smodel = static_cast<const llama_model_granite_switch &>(model);
|
||||
|
||||
// TODO: support raw embedding input (multimodal / pre-embedded tokens) when needed
|
||||
GGML_ASSERT(ubatch.token && "granite-switch requires token input");
|
||||
|
||||
const int64_t n_embd_head = hparams.n_embd_head_v();
|
||||
GGML_ASSERT(n_embd_head == hparams.n_embd_head_k());
|
||||
GGML_ASSERT(n_embd_head == n_rot);
|
||||
|
||||
auto inp_switch = std::make_unique<llm_graph_input_switch>(smodel);
|
||||
inp_switch->sub_tokens = ggml_new_tensor_1d(ctx0, GGML_TYPE_I32, n_tokens);
|
||||
inp_switch->router_ksig = ggml_new_tensor_1d(ctx0, GGML_TYPE_F32, n_tokens);
|
||||
inp_switch->router_vval = ggml_new_tensor_1d(ctx0, GGML_TYPE_F32, n_tokens);
|
||||
inp_switch->router_q = ggml_new_tensor_1d(ctx0, GGML_TYPE_F32, n_tokens);
|
||||
ggml_set_input(inp_switch->sub_tokens);
|
||||
ggml_set_input(inp_switch->router_ksig);
|
||||
ggml_set_input(inp_switch->router_vval);
|
||||
ggml_set_input(inp_switch->router_q);
|
||||
ggml_tensor * sub_tokens = inp_switch->sub_tokens;
|
||||
ggml_tensor * router_ksig = inp_switch->router_ksig;
|
||||
ggml_tensor * router_vval = inp_switch->router_vval;
|
||||
ggml_tensor * router_q = inp_switch->router_q;
|
||||
res->add_input(std::move(inp_switch));
|
||||
|
||||
// embed the substituted ids directly; build_inp_embd would embed the raw tokens
|
||||
ggml_tensor * inpL = ggml_get_rows(ctx0, model.tok_embd, sub_tokens);
|
||||
if (hparams.f_embedding_scale != 0.0f) {
|
||||
inpL = ggml_scale(ctx0, inpL, hparams.f_embedding_scale);
|
||||
}
|
||||
cb(inpL, "inp_embd", -1);
|
||||
|
||||
ggml_tensor * inp_pos = nullptr;
|
||||
if (hparams.rope_finetuned) {
|
||||
inp_pos = build_inp_pos();
|
||||
}
|
||||
auto * inp_attn = build_attn_inp_kv();
|
||||
|
||||
// single causal head at layer R recovers the adapter index in-graph: only dim 0
|
||||
// carries signal (Q[0]=1, K[0]=+/-gain, V[0]=slot/0), the rest is zero-padded.
|
||||
const int R = hparams.router_layer;
|
||||
GGML_ASSERT(R >= 0);
|
||||
auto router_lane = [&](ggml_tensor * sig1d) {
|
||||
ggml_tensor * t = ggml_reshape_3d(ctx0, sig1d, 1, 1, n_tokens);
|
||||
return ggml_pad(ctx0, t, (int) n_embd_head - 1, 0, 0, 0);
|
||||
};
|
||||
ggml_tensor * Qr = router_lane(router_q);
|
||||
ggml_tensor * Kr = router_lane(router_ksig);
|
||||
ggml_tensor * Vr = router_lane(router_vval);
|
||||
|
||||
ggml_tensor * router_out = build_attn(inp_attn,
|
||||
nullptr, nullptr, nullptr,
|
||||
Qr, Kr, Vr, nullptr, nullptr, nullptr, /*kq_scale=*/1.0f, /*il=*/R);
|
||||
cb(router_out, "router_out", R);
|
||||
|
||||
// row 0 of router_out is the attended slot; clamp+round to an I32 index
|
||||
ggml_tensor * slot_f = ggml_cont(ctx0,
|
||||
ggml_view_2d(ctx0, router_out, 1, n_tokens, router_out->nb[1], 0));
|
||||
slot_f = ggml_reshape_1d(ctx0, slot_f, n_tokens);
|
||||
slot_f = ggml_clamp(ctx0, slot_f, 0.0f, (float) smodel.n_adapters);
|
||||
slot_f = ggml_round(ctx0, slot_f);
|
||||
ggml_tensor * adapter_ids = ggml_cast(ctx0, slot_f, GGML_TYPE_I32);
|
||||
cb(adapter_ids, "adapter_ids", -1);
|
||||
|
||||
ggml_tensor * inp_out_ids = build_inp_out_ids();
|
||||
|
||||
ggml_tensor * cur;
|
||||
|
||||
for (int il = 0; il < n_layer; ++il) {
|
||||
ggml_tensor * inpSA = inpL;
|
||||
|
||||
cur = build_norm(inpL, model.layers[il].attn_norm, NULL, LLM_NORM_RMS, il);
|
||||
cb(cur, "attn_norm", il);
|
||||
|
||||
cur = build_attention_layer(cur, inp_pos, adapter_ids, inp_attn, model, n_embd_head, il);
|
||||
|
||||
if (il == n_layer - 1 && inp_out_ids) {
|
||||
cur = ggml_get_rows(ctx0, cur, inp_out_ids);
|
||||
inpSA = ggml_get_rows(ctx0, inpSA, inp_out_ids);
|
||||
// keep adapter_ids aligned to the kept rows (2D round-trip for get_rows)
|
||||
const int64_t n_out = inp_out_ids->ne[0];
|
||||
adapter_ids = ggml_get_rows(ctx0,
|
||||
ggml_reshape_2d(ctx0, adapter_ids, 1, adapter_ids->ne[0]), inp_out_ids);
|
||||
adapter_ids = ggml_reshape_1d(ctx0, adapter_ids, n_out);
|
||||
}
|
||||
|
||||
cur = build_layer_ffn(cur, inpSA, adapter_ids, model, il);
|
||||
|
||||
inpL = cur;
|
||||
}
|
||||
|
||||
cur = inpL;
|
||||
|
||||
cur = build_norm(cur, model.output_norm, NULL, LLM_NORM_RMS, -1);
|
||||
cb(cur, "result_norm", -1);
|
||||
res->t_embd = cur;
|
||||
|
||||
cur = build_lora_mm(model.output, cur, model.output_s);
|
||||
|
||||
cur = ggml_scale(ctx0, cur, 1.0f / hparams.f_logit_scale);
|
||||
cb(cur, "result_output", -1);
|
||||
res->t_logits = cur;
|
||||
|
||||
ggml_build_forward_expand(gf, cur);
|
||||
}
|
||||
|
||||
ggml_tensor * llama_model_granite_switch::graph::build_attention_layer(
|
||||
ggml_tensor * cur,
|
||||
ggml_tensor * inp_pos,
|
||||
ggml_tensor * adapter_ids,
|
||||
llm_graph_input_attn_kv * inp_attn,
|
||||
const llama_model & model,
|
||||
const int64_t n_embd_head,
|
||||
const int il) {
|
||||
|
||||
const auto & layer = model.layers[il];
|
||||
const auto & sl = layer.switch_lora;
|
||||
|
||||
const int64_t n_head = hparams.n_head(il);
|
||||
const int64_t n_head_kv = hparams.n_head_kv(il);
|
||||
|
||||
ggml_tensor * qkv = ggml_mul_mat(ctx0, layer.wqkv, cur);
|
||||
cb(qkv, "wqkv", il);
|
||||
|
||||
const int64_t n_embd_q = n_embd_head * n_head;
|
||||
const int64_t n_embd_kv = n_embd_head * n_head_kv;
|
||||
|
||||
// slice fused qkv into Q/K/V, made contiguous so LoRA deltas can be added
|
||||
ggml_tensor * Qcur = ggml_cont(ctx0, ggml_view_2d(ctx0, qkv, n_embd_q, qkv->ne[1], qkv->nb[1], 0));
|
||||
ggml_tensor * Kcur = ggml_cont(ctx0, ggml_view_2d(ctx0, qkv, n_embd_kv, qkv->ne[1], qkv->nb[1], n_embd_q*ggml_element_size(qkv)));
|
||||
ggml_tensor * Vcur = ggml_cont(ctx0, ggml_view_2d(ctx0, qkv, n_embd_kv, qkv->ne[1], qkv->nb[1], (n_embd_q + n_embd_kv)*ggml_element_size(qkv)));
|
||||
|
||||
Qcur = ggml_add(ctx0, Qcur, build_switched_lora_delta(sl.a_q, sl.b_q, cur, adapter_ids));
|
||||
Kcur = ggml_add(ctx0, Kcur, build_switched_lora_delta(sl.a_k, sl.b_k, cur, adapter_ids));
|
||||
Vcur = ggml_add(ctx0, Vcur, build_switched_lora_delta(sl.a_v, sl.b_v, cur, adapter_ids));
|
||||
|
||||
Qcur = ggml_reshape_3d(ctx0, Qcur, n_embd_head, n_head, n_tokens);
|
||||
Kcur = ggml_reshape_3d(ctx0, Kcur, n_embd_head, n_head_kv, n_tokens);
|
||||
Vcur = ggml_reshape_3d(ctx0, Vcur, n_embd_head, n_head_kv, n_tokens);
|
||||
|
||||
if (hparams.rope_finetuned) {
|
||||
ggml_tensor * rope_factors = model.get_rope_factors(cparams, il);
|
||||
Qcur = ggml_rope_ext(ctx0, Qcur, inp_pos, rope_factors,
|
||||
n_rot, rope_type, n_ctx_orig, freq_base, freq_scale,
|
||||
ext_factor, attn_factor, beta_fast, beta_slow);
|
||||
Kcur = ggml_rope_ext(ctx0, Kcur, inp_pos, rope_factors,
|
||||
n_rot, rope_type, n_ctx_orig, freq_base, freq_scale,
|
||||
ext_factor, attn_factor, beta_fast, beta_slow);
|
||||
}
|
||||
cb(Qcur, "Qcur", il);
|
||||
cb(Kcur, "Kcur", il);
|
||||
cb(Vcur, "Vcur", il);
|
||||
|
||||
const float kq_scale = hparams.f_attention_scale == 0.0f
|
||||
? 1.0f/sqrtf(float(n_embd_head)) : hparams.f_attention_scale;
|
||||
|
||||
// wo = nullptr so build_attn returns concatenated heads; o-proj is switched below
|
||||
ggml_tensor * attn = build_attn(inp_attn,
|
||||
nullptr, nullptr, nullptr,
|
||||
Qcur, Kcur, Vcur, nullptr, nullptr, nullptr, kq_scale, il);
|
||||
cb(attn, "attn_pre_o", il);
|
||||
|
||||
cur = build_switched_lora_mm(layer.wo, sl.a_o, sl.b_o, attn, adapter_ids);
|
||||
cb(cur, "attn_out", il);
|
||||
return cur;
|
||||
}
|
||||
|
||||
ggml_tensor * llama_model_granite_switch::graph::build_layer_ffn(
|
||||
ggml_tensor * cur,
|
||||
ggml_tensor * inpSA,
|
||||
ggml_tensor * adapter_ids,
|
||||
const llama_model & model,
|
||||
const int il) {
|
||||
|
||||
const auto & layer = model.layers[il];
|
||||
const auto & sl = layer.switch_lora;
|
||||
|
||||
if (hparams.f_residual_scale) {
|
||||
cur = ggml_scale(ctx0, cur, hparams.f_residual_scale);
|
||||
}
|
||||
ggml_tensor * ffn_inp = ggml_add(ctx0, cur, inpSA);
|
||||
cb(ffn_inp, "ffn_inp", il);
|
||||
|
||||
cur = build_norm(ffn_inp, layer.ffn_norm, NULL, LLM_NORM_RMS, il);
|
||||
cb(cur, "ffn_norm", il);
|
||||
|
||||
ggml_tensor * g = build_switched_lora_mm(layer.ffn_gate, sl.a_gate, sl.b_gate, cur, adapter_ids);
|
||||
ggml_tensor * u = build_switched_lora_mm(layer.ffn_up, sl.a_up, sl.b_up, cur, adapter_ids);
|
||||
g = ggml_silu(ctx0, g);
|
||||
ggml_tensor * gu = ggml_mul(ctx0, g, u);
|
||||
cur = build_switched_lora_mm(layer.ffn_down, sl.a_down, sl.b_down, gu, adapter_ids);
|
||||
cb(cur, "ffn_out", il);
|
||||
|
||||
if (hparams.f_residual_scale) {
|
||||
cur = ggml_scale(ctx0, cur, hparams.f_residual_scale);
|
||||
}
|
||||
cur = ggml_add(ctx0, cur, ffn_inp);
|
||||
|
||||
cur = build_cvec(cur, il);
|
||||
cb(cur, "l_out", il);
|
||||
|
||||
return cur;
|
||||
}
|
||||
@@ -1596,6 +1596,56 @@ struct llama_model_granite_moe : public llama_model_base {
|
||||
};
|
||||
|
||||
|
||||
struct llama_model_granite_switch : public llama_model_base {
|
||||
llama_model_granite_switch(const struct llama_model_params & params) : llama_model_base(params) {}
|
||||
void load_arch_hparams(llama_model_loader & ml) override;
|
||||
void load_arch_tensors(llama_model_loader & ml) override;
|
||||
|
||||
uint32_t n_adapters = 0;
|
||||
uint32_t max_lora_rank = 0;
|
||||
float router_gain = 15.0f;
|
||||
|
||||
std::unordered_map<llama_token, int32_t> adapter_token_to_slot;
|
||||
std::unordered_map<llama_token, llama_token> adapter_token_to_substitute;
|
||||
|
||||
struct graph : public llm_graph_context {
|
||||
graph(const llama_model & model, const llm_graph_params & params);
|
||||
|
||||
private:
|
||||
ggml_tensor * build_switched_lora_delta(
|
||||
ggml_tensor * lora_a,
|
||||
ggml_tensor * lora_b,
|
||||
ggml_tensor * cur,
|
||||
ggml_tensor * ids);
|
||||
|
||||
ggml_tensor * build_switched_lora_mm(
|
||||
ggml_tensor * w,
|
||||
ggml_tensor * lora_a,
|
||||
ggml_tensor * lora_b,
|
||||
ggml_tensor * cur,
|
||||
ggml_tensor * ids);
|
||||
|
||||
ggml_tensor * build_attention_layer(
|
||||
ggml_tensor * cur,
|
||||
ggml_tensor * inp_pos,
|
||||
ggml_tensor * adapter_ids,
|
||||
llm_graph_input_attn_kv * inp_attn,
|
||||
const llama_model & model,
|
||||
const int64_t n_embd_head,
|
||||
const int il);
|
||||
|
||||
ggml_tensor * build_layer_ffn(
|
||||
ggml_tensor * cur,
|
||||
ggml_tensor * inpSA,
|
||||
ggml_tensor * adapter_ids,
|
||||
const llama_model & model,
|
||||
const int il);
|
||||
};
|
||||
|
||||
std::unique_ptr<llm_graph_context> build_arch_graph(const llm_graph_params & params) const override;
|
||||
};
|
||||
|
||||
|
||||
struct llama_model_minicpm : public llama_model_base {
|
||||
llama_model_minicpm(const struct llama_model_params & params) : llama_model_base(params) {}
|
||||
void load_arch_hparams(llama_model_loader & ml) override;
|
||||
|
||||
+38
-14
@@ -2584,6 +2584,7 @@ struct test_rms_norm_mul_rope : public test_case {
|
||||
const float eps;
|
||||
const bool multi_add; // test a sequence of adds feeding into rms_norm
|
||||
const bool set_rows;
|
||||
const bool broadcast; // multiply by a 1D [ne0] weight, as model norm weights are
|
||||
int mode;
|
||||
|
||||
std::string op_desc(ggml_tensor * t) override {
|
||||
@@ -2594,12 +2595,12 @@ struct test_rms_norm_mul_rope : public test_case {
|
||||
bool run_whole_graph() override { return true; }
|
||||
|
||||
std::string vars() override {
|
||||
return VARS_TO_STR5(ne, eps, multi_add, set_rows, mode);
|
||||
return VARS_TO_STR6(ne, eps, multi_add, set_rows, broadcast, mode);
|
||||
}
|
||||
|
||||
test_rms_norm_mul_rope(std::array<int64_t, 4> ne, float eps = 1e-6f, bool multi_add = false,
|
||||
bool set_rows = false, int mode = GGML_ROPE_TYPE_NORMAL)
|
||||
: ne(ne), eps(eps), multi_add(multi_add), set_rows(set_rows), mode(mode) {}
|
||||
bool set_rows = false, bool broadcast = false, int mode = GGML_ROPE_TYPE_NORMAL)
|
||||
: ne(ne), eps(eps), multi_add(multi_add), set_rows(set_rows), broadcast(broadcast), mode(mode) {}
|
||||
|
||||
ggml_tensor * build_graph(ggml_context * ctx) override {
|
||||
ggml_tensor * a = ggml_new_tensor_4d(ctx, GGML_TYPE_F32, ne[0], ne[1], ne[2], 1);
|
||||
@@ -2610,7 +2611,9 @@ struct test_rms_norm_mul_rope : public test_case {
|
||||
a = ggml_add(ctx, ggml_add(ctx, a, b), c);
|
||||
}
|
||||
|
||||
a = ggml_mul(ctx, ggml_rms_norm(ctx, a, eps), b);
|
||||
ggml_tensor * w = broadcast ? ggml_new_tensor_1d(ctx, GGML_TYPE_F32, ne[0]) : b;
|
||||
|
||||
a = ggml_mul(ctx, ggml_rms_norm(ctx, a, eps), w);
|
||||
|
||||
ggml_tensor * pos = ggml_new_tensor_1d(ctx, GGML_TYPE_I32, ne[2]);
|
||||
|
||||
@@ -8576,6 +8579,9 @@ static std::vector<std::unique_ptr<test_case>> make_test_cases_eval() {
|
||||
test_cases.emplace_back(new test_cpy(type_src, type_dst, {256, 2, 3, 4}, {-1,-1,-1,-1}, {1, 0, 2, 3})); // cpy not-contiguous
|
||||
}
|
||||
}
|
||||
// quant block count not a multiple of the kernel block size
|
||||
test_cases.emplace_back(new test_cpy(GGML_TYPE_F32, GGML_TYPE_Q4_0, {96, 1, 1, 1}));
|
||||
test_cases.emplace_back(new test_cpy(GGML_TYPE_Q4_0, GGML_TYPE_F32, {96, 1, 1, 1}));
|
||||
test_cases.emplace_back(new test_cpy(GGML_TYPE_F32, GGML_TYPE_I32, {256, 2, 3, 4}));
|
||||
test_cases.emplace_back(new test_cpy(GGML_TYPE_F32, GGML_TYPE_I32, {256, 2, 3, 4}, {-1,-1,-1,-1}, {1, 0, 2, 3}));
|
||||
test_cases.emplace_back(new test_cpy(GGML_TYPE_I32, GGML_TYPE_F32, {256, 2, 3, 4}));
|
||||
@@ -8722,6 +8728,13 @@ static std::vector<std::unique_ptr<test_case>> make_test_cases_eval() {
|
||||
test_cases.emplace_back(new test_l2_norm(GGML_TYPE_F32, { n, 5, 4, 3 }, eps, true));
|
||||
test_cases.emplace_back(new test_l2_norm(GGML_TYPE_F32, { n, 5, 4, 3 }, eps, false, true));
|
||||
}
|
||||
// row lengths that are not a multiple of 32, for the scalar (33) and float4 (132, 260) paths
|
||||
for (uint32_t n : { 33, 132, 260 }) {
|
||||
for (bool v : { false, true }) {
|
||||
test_cases.emplace_back(new test_norm(GGML_TYPE_F32, { n, 5, 4, 3 }, v, eps));
|
||||
test_cases.emplace_back(new test_rms_norm(GGML_TYPE_F32, { n, 5, 4, 3 }, v, eps));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// in-place tests
|
||||
@@ -8746,16 +8759,18 @@ static std::vector<std::unique_ptr<test_case>> make_test_cases_eval() {
|
||||
|
||||
for (auto multi_add : {false, true}) {
|
||||
for (auto set_rows : {false, true}) {
|
||||
for (auto rope : {GGML_ROPE_TYPE_NORMAL, GGML_ROPE_TYPE_NEOX}) {
|
||||
test_cases.emplace_back(new test_rms_norm_mul_rope({768, 1, 1, 1}, 1e-6f, multi_add, set_rows, rope));
|
||||
test_cases.emplace_back(new test_rms_norm_mul_rope({768, 3, 1, 1}, 1e-6f, multi_add, set_rows, rope));
|
||||
test_cases.emplace_back(new test_rms_norm_mul_rope({768, 3, 5, 1}, 1e-6f, multi_add, set_rows, rope));
|
||||
test_cases.emplace_back(new test_rms_norm_mul_rope({128, 32, 2, 1}, 1e-6f, multi_add, set_rows, rope));
|
||||
test_cases.emplace_back(new test_rms_norm_mul_rope({128, 4, 2, 1}, 1e-6f, multi_add, set_rows, rope));
|
||||
test_cases.emplace_back(new test_rms_norm_mul_rope({128, 32, 50, 1}, 1e-6f, multi_add, set_rows, rope));
|
||||
test_cases.emplace_back(new test_rms_norm_mul_rope({128, 4, 50, 1}, 1e-6f, multi_add, set_rows, rope));
|
||||
test_cases.emplace_back(new test_rms_norm_mul_rope({8192, 2, 2, 1}, 1e-6f, multi_add, set_rows, rope));
|
||||
test_cases.emplace_back(new test_rms_norm_mul_rope({8192, 2, 2, 1}, 1e-6f, multi_add, set_rows, rope));
|
||||
for (auto broadcast : {false, true}) {
|
||||
for (auto rope : {GGML_ROPE_TYPE_NORMAL, GGML_ROPE_TYPE_NEOX}) {
|
||||
test_cases.emplace_back(new test_rms_norm_mul_rope({768, 1, 1, 1}, 1e-6f, multi_add, set_rows, broadcast, rope));
|
||||
test_cases.emplace_back(new test_rms_norm_mul_rope({768, 3, 1, 1}, 1e-6f, multi_add, set_rows, broadcast, rope));
|
||||
test_cases.emplace_back(new test_rms_norm_mul_rope({768, 3, 5, 1}, 1e-6f, multi_add, set_rows, broadcast, rope));
|
||||
test_cases.emplace_back(new test_rms_norm_mul_rope({128, 32, 2, 1}, 1e-6f, multi_add, set_rows, broadcast, rope));
|
||||
test_cases.emplace_back(new test_rms_norm_mul_rope({128, 4, 2, 1}, 1e-6f, multi_add, set_rows, broadcast, rope));
|
||||
test_cases.emplace_back(new test_rms_norm_mul_rope({128, 32, 50, 1}, 1e-6f, multi_add, set_rows, broadcast, rope));
|
||||
test_cases.emplace_back(new test_rms_norm_mul_rope({128, 4, 50, 1}, 1e-6f, multi_add, set_rows, broadcast, rope));
|
||||
test_cases.emplace_back(new test_rms_norm_mul_rope({8192, 2, 2, 1}, 1e-6f, multi_add, set_rows, broadcast, rope));
|
||||
test_cases.emplace_back(new test_rms_norm_mul_rope({8192, 2, 2, 1}, 1e-6f, multi_add, set_rows, broadcast, rope));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9747,6 +9762,15 @@ static std::vector<std::unique_ptr<test_case>> make_test_cases_eval() {
|
||||
static std::vector<std::unique_ptr<test_case>> make_test_cases_perf() {
|
||||
std::vector<std::unique_ptr<test_case>> test_cases;
|
||||
|
||||
// SWIGLU at a 27B-class FFN width, fused [gate|up] vs split operands
|
||||
// note: same bytes either way, so a backend that indexes them differently shows it here
|
||||
for (ggml_type type : {GGML_TYPE_F16, GGML_TYPE_F32}) {
|
||||
for (int64_t n_tokens : {512, 2048}) {
|
||||
test_cases.emplace_back(new test_glu(GGML_GLU_OP_SWIGLU, type, { 2*17408, n_tokens, 1, 1 }, 0, false));
|
||||
test_cases.emplace_back(new test_glu_split(GGML_GLU_OP_SWIGLU, type, { 17408, n_tokens, 1, 1 }, 0));
|
||||
}
|
||||
}
|
||||
|
||||
// Conv2d: K=CRS=NPQ=4096 matmul performance
|
||||
uint32_t iwh_idx = 0;
|
||||
uint32_t kwh_idx = 1;
|
||||
|
||||
@@ -1668,9 +1668,18 @@ static std::vector<const backend_test_case *> collect_tests_to_run(const std::st
|
||||
}
|
||||
} else {
|
||||
for (const auto & test : BACKEND_TESTS) {
|
||||
if (test.enabled_by_default) {
|
||||
selected.push_back(&test);
|
||||
if (!test.enabled_by_default) {
|
||||
continue;
|
||||
}
|
||||
#ifdef GGML_USE_HIP
|
||||
// TODO: remove this when https://github.com/ggml-org/llama.cpp/pull/26592 is merged
|
||||
if (test.name == "penalties" || test.name == "set_sampler" ||
|
||||
test.name == "mixed" || test.name == "top_p") {
|
||||
fprintf(stderr, "Skipping test '%s' on HIP backend (no backend TOP_K support)\n", test.name.c_str());
|
||||
continue;
|
||||
}
|
||||
#endif // GGML_USE_HIP
|
||||
selected.push_back(&test);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -153,6 +153,53 @@ int main()
|
||||
root ::= "a"{,10}"
|
||||
)""");
|
||||
|
||||
verify_failure(R"""(
|
||||
root ::= "a"{5000}
|
||||
)""");
|
||||
|
||||
verify_failure(R"""(
|
||||
root ::= "a"{5000,}
|
||||
)""");
|
||||
|
||||
verify_failure(R"""(
|
||||
root ::= "a"{5000,6000}
|
||||
)""");
|
||||
|
||||
verify_parsing(R"""(
|
||||
root ::= "a"{0,5000}
|
||||
)""", {
|
||||
{"root", 0},
|
||||
{"root_1", 1},
|
||||
}, {
|
||||
// root (index 0)
|
||||
{LLAMA_GRETYPE_RULE_REF, /* root_1 */ 1},
|
||||
{LLAMA_GRETYPE_END, 0},
|
||||
// root_1 (index 1)
|
||||
{LLAMA_GRETYPE_CHAR, 'a'},
|
||||
{LLAMA_GRETYPE_RULE_REF, /* root_1 */ 1},
|
||||
{LLAMA_GRETYPE_ALT, 0},
|
||||
{LLAMA_GRETYPE_END, 0},
|
||||
});
|
||||
|
||||
verify_parsing(R"""(
|
||||
root ::= "a"{3,5000}
|
||||
)""", {
|
||||
{"root", 0},
|
||||
{"root_1", 1},
|
||||
}, {
|
||||
// root (index 0)
|
||||
{LLAMA_GRETYPE_CHAR, 'a'},
|
||||
{LLAMA_GRETYPE_CHAR, 'a'},
|
||||
{LLAMA_GRETYPE_CHAR, 'a'},
|
||||
{LLAMA_GRETYPE_RULE_REF, /* root_1 */ 1},
|
||||
{LLAMA_GRETYPE_END, 0},
|
||||
// root_1 (index 1)
|
||||
{LLAMA_GRETYPE_CHAR, 'a'},
|
||||
{LLAMA_GRETYPE_RULE_REF, /* root_1 */ 1},
|
||||
{LLAMA_GRETYPE_ALT, 0},
|
||||
{LLAMA_GRETYPE_END, 0},
|
||||
});
|
||||
|
||||
verify_parsing(R"""(
|
||||
root ::= "a"
|
||||
)""", {
|
||||
|
||||
@@ -217,6 +217,7 @@ static gguf_context_ptr get_gguf_ctx(const llm_arch arch, const bool moe) {
|
||||
|
||||
if (moe) {
|
||||
ms.add_kv(LLM_KV_EXPERT_FEED_FORWARD_LENGTH, n_ff);
|
||||
ms.add_kv(LLM_KV_EXPERT_SHARED_FEED_FORWARD_LENGTH, n_ff / 2); // distinct from n_ff so a saver key-clobber surfaces on reload
|
||||
ms.add_kv(LLM_KV_INTERLEAVE_MOE_LAYER_STEP, uint32_t(2));
|
||||
ms.add_kv(LLM_KV_EXPERT_COUNT, uint32_t(2));
|
||||
ms.add_kv(LLM_KV_EXPERT_USED_COUNT, uint32_t(1));
|
||||
@@ -410,6 +411,9 @@ static bool arch_supported(const llm_arch arch) {
|
||||
if (arch == LLM_ARCH_GEMMA4 || arch == LLM_ARCH_GEMMA4_ASSISTANT) {
|
||||
return false; // FIXME @ngxson
|
||||
}
|
||||
if (arch == LLM_ARCH_GRANITE_SWITCH) {
|
||||
return false; // FIXME adapter fixture
|
||||
}
|
||||
if (arch == LLM_ARCH_LLAMA_EMBED || arch == LLM_ARCH_GEMMA_EMBEDDING || arch == LLM_ARCH_T5ENCODER) {
|
||||
return false; // FIXME Embedding (?) models produce inconsistent results.
|
||||
}
|
||||
@@ -432,11 +436,19 @@ static bool arch_supported(const llm_arch arch) {
|
||||
|
||||
// FIXME: these hit scheduler/view-backed-output issues with WebGPU on CI.
|
||||
#ifdef GGML_USE_WEBGPU
|
||||
if (arch == LLM_ARCH_DEEPSEEK32 || arch == LLM_ARCH_GLM_DSA || arch == LLM_ARCH_MINIMAX_M3) {
|
||||
if (arch == LLM_ARCH_DEEPSEEK32 || arch == LLM_ARCH_GLM_DSA) {
|
||||
return false;
|
||||
}
|
||||
#endif // GGML_USE_WEBGPU
|
||||
|
||||
// FIXME: jamba produces incorrect output (~0.55 NMSE vs CPU) on the HIP
|
||||
// backend on RDNA3.5 (gfx1151); the SSM kernels need investigation.
|
||||
#ifdef GGML_USE_HIP
|
||||
if (arch == LLM_ARCH_JAMBA) {
|
||||
return false;
|
||||
}
|
||||
#endif // GGML_USE_HIP
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -195,7 +195,7 @@ static const std::vector<std::string> dspark_dflash = {
|
||||
|
||||
struct plan_case {
|
||||
const char * name;
|
||||
const std::vector<std::string> & files;
|
||||
const std::vector<std::string> files;
|
||||
const char * hf_repo;
|
||||
const char * hf_file;
|
||||
bool sidecars; // request mmproj + mtp + dflash + eagle3 + dspark
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "mtmd.h"
|
||||
@@ -62,6 +64,72 @@ int main(void) {
|
||||
}
|
||||
}
|
||||
|
||||
// test chunk save/load round-trip
|
||||
for (size_t i = 0; i < n_chunks; i++) {
|
||||
const mtmd_input_chunk * chunk = mtmd_input_chunks_get(chunks, i);
|
||||
assert(chunk != NULL);
|
||||
enum mtmd_input_chunk_type type = mtmd_input_chunk_get_type(chunk);
|
||||
|
||||
// query the required buffer size (out_buf == NULL)
|
||||
size_t expected_len = 0;
|
||||
int32_t rc = mtmd_input_chunk_save(chunk, NULL, 0, &expected_len);
|
||||
printf(" Chunk %zu: save query rc = %d, expected_len = %zu\n", i, rc, expected_len);
|
||||
assert(rc == 0);
|
||||
assert(expected_len > 0);
|
||||
|
||||
// saving into a too-small buffer must fail, not crash
|
||||
char tiny_buf[1];
|
||||
rc = mtmd_input_chunk_save(chunk, tiny_buf, sizeof(tiny_buf), NULL);
|
||||
printf(" Chunk %zu: save into too-small buffer rc = %d (expect non-zero)\n", i, rc);
|
||||
assert(rc != 0);
|
||||
|
||||
// save into a properly-sized buffer
|
||||
char * buf = (char *) malloc(expected_len);
|
||||
assert(buf != NULL);
|
||||
rc = mtmd_input_chunk_save(chunk, buf, expected_len, NULL);
|
||||
assert(rc == 0);
|
||||
|
||||
// loading from a truncated buffer must fail gracefully, not crash
|
||||
if (expected_len > 1) {
|
||||
mtmd_input_chunk * bad = mtmd_input_chunk_load(buf, expected_len - 1);
|
||||
printf(" Chunk %zu: load from truncated buffer = %p (expect NULL)\n", i, (void *) bad);
|
||||
assert(bad == NULL);
|
||||
}
|
||||
|
||||
// load it back
|
||||
mtmd_input_chunk * loaded = mtmd_input_chunk_load(buf, expected_len);
|
||||
assert(loaded != NULL);
|
||||
|
||||
// metadata must match the original chunk
|
||||
assert(mtmd_input_chunk_get_type(loaded) == type);
|
||||
assert(mtmd_input_chunk_get_n_tokens(loaded) == mtmd_input_chunk_get_n_tokens(chunk));
|
||||
assert(mtmd_input_chunk_get_n_pos(loaded) == mtmd_input_chunk_get_n_pos(chunk));
|
||||
|
||||
if (type == MTMD_INPUT_CHUNK_TYPE_TEXT) {
|
||||
size_t n_tok_orig, n_tok_loaded;
|
||||
const llama_token * tok_orig = mtmd_input_chunk_get_tokens_text(chunk, &n_tok_orig);
|
||||
const llama_token * tok_loaded = mtmd_input_chunk_get_tokens_text(loaded, &n_tok_loaded);
|
||||
printf(" Chunk %zu: loaded %zu text tokens (orig %zu), first token %d (orig %d)\n",
|
||||
i, n_tok_loaded, n_tok_orig,
|
||||
n_tok_loaded > 0 ? tok_loaded[0] : -1,
|
||||
n_tok_orig > 0 ? tok_orig[0] : -1);
|
||||
assert(n_tok_orig == n_tok_loaded);
|
||||
for (size_t j = 0; j < n_tok_orig; j++) {
|
||||
assert(tok_orig[j] == tok_loaded[j]);
|
||||
}
|
||||
} else if (type == MTMD_INPUT_CHUNK_TYPE_IMAGE || type == MTMD_INPUT_CHUNK_TYPE_AUDIO) {
|
||||
const char * id_orig = mtmd_input_chunk_get_id(chunk);
|
||||
const char * id_loaded = mtmd_input_chunk_get_id(loaded);
|
||||
printf(" Chunk %zu: loaded id '%s' (orig '%s')\n", i, id_loaded, id_orig);
|
||||
assert(id_orig != NULL && id_loaded != NULL);
|
||||
assert(strcmp(id_orig, id_loaded) == 0);
|
||||
}
|
||||
|
||||
mtmd_input_chunk_free(loaded);
|
||||
free(buf);
|
||||
}
|
||||
printf("Chunk save/load round-trip OK\n");
|
||||
|
||||
// Free the chunks
|
||||
mtmd_input_chunks_free(chunks);
|
||||
|
||||
|
||||
@@ -54,7 +54,6 @@
|
||||
| `-ctv, --cache-type-v TYPE` | KV cache data type for V<br/>allowed values: f32, f16, bf16, q8_0, q4_0, q4_1, iq4_nl, q5_0, q5_1<br/>(default: f16)<br/>(env: LLAMA_ARG_CACHE_TYPE_V) |
|
||||
| `-dt, --defrag-thold N` | KV cache defragmentation threshold (DEPRECATED)<br/>(env: LLAMA_ARG_DEFRAG_THOLD) |
|
||||
| `-np, --parallel N` | number of parallel sequences to decode (default: 1)<br/>(env: LLAMA_ARG_N_PARALLEL) |
|
||||
| `--rpc SERVERS` | comma-separated list of RPC servers (host:port)<br/>(env: LLAMA_ARG_RPC) |
|
||||
| `--mlock` | DEPRECATED in favor of `--load-mode`: force system to keep model in RAM rather than swapping or compressing<br/>(env: LLAMA_ARG_MLOCK) |
|
||||
| `--mmap, --no-mmap` | DEPRECATED in favor of `--load-mode`: whether to memory-map model. (if mmap disabled, slower load but may reduce pageouts if not using mlock)<br/>(env: LLAMA_ARG_MMAP) |
|
||||
| `-dio, --direct-io, -ndio, --no-direct-io` | DEPRECATED in favor of `--load-mode`: use DirectIO if available<br/>(env: LLAMA_ARG_DIO) |
|
||||
|
||||
@@ -137,7 +137,6 @@ llama-completion.exe -m models\gemma-1.1-7b-it.Q4_K_M.gguf --ignore-eos -n -1
|
||||
| `-ctv, --cache-type-v TYPE` | KV cache data type for V<br/>allowed values: f32, f16, bf16, q8_0, q4_0, q4_1, iq4_nl, q5_0, q5_1<br/>(default: f16)<br/>(env: LLAMA_ARG_CACHE_TYPE_V) |
|
||||
| `-dt, --defrag-thold N` | KV cache defragmentation threshold (DEPRECATED)<br/>(env: LLAMA_ARG_DEFRAG_THOLD) |
|
||||
| `-np, --parallel N` | number of parallel sequences to decode (default: 1)<br/>(env: LLAMA_ARG_N_PARALLEL) |
|
||||
| `--rpc SERVERS` | comma-separated list of RPC servers (host:port)<br/>(env: LLAMA_ARG_RPC) |
|
||||
| `--mlock` | DEPRECATED in favor of `--load-mode`: force system to keep model in RAM rather than swapping or compressing<br/>(env: LLAMA_ARG_MLOCK) |
|
||||
| `--mmap, --no-mmap` | DEPRECATED in favor of `--load-mode`: whether to memory-map model. (if mmap disabled, slower load but may reduce pageouts if not using mlock)<br/>(env: LLAMA_ARG_MMAP) |
|
||||
| `-dio, --direct-io, -ndio, --no-direct-io` | DEPRECATED in favor of `--load-mode`: use DirectIO if available<br/>(env: LLAMA_ARG_DIO) |
|
||||
|
||||
@@ -591,6 +591,8 @@ struct clip_image_u8 {
|
||||
}
|
||||
};
|
||||
|
||||
struct mtmd_serialization; // forward declaration
|
||||
|
||||
// For images, buf.size() == nx*ny*3
|
||||
// Memory layout: RGBRGBRGB...
|
||||
// For seq, buf.size() == nx*ny*3*nt
|
||||
@@ -671,6 +673,9 @@ struct clip_image_f32 {
|
||||
return buf.empty();
|
||||
}
|
||||
|
||||
void serialize(struct mtmd_serialization & ser) const;
|
||||
void deserialize(struct mtmd_serialization & ser);
|
||||
|
||||
private:
|
||||
std::vector<float> buf;
|
||||
int nx_ = 0;
|
||||
@@ -752,6 +757,9 @@ struct clip_image_f32_batch {
|
||||
}
|
||||
return new_batch;
|
||||
}
|
||||
|
||||
void serialize(struct mtmd_serialization & ser) const;
|
||||
void deserialize(struct mtmd_serialization & ser);
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
@@ -170,6 +170,17 @@ struct clip_hparams {
|
||||
warmup_image_size = static_cast<int>(std::sqrt(image_max_pixels));
|
||||
}
|
||||
|
||||
// used by longest_edge preprocessor (no model-specific value for min/max tokens)
|
||||
void set_limit_image_tokens() {
|
||||
const int patch_area = patch_size * patch_size * n_merge * n_merge;
|
||||
if (custom_image_min_tokens > 0) {
|
||||
image_min_pixels = custom_image_min_tokens * patch_area;
|
||||
}
|
||||
if (custom_image_max_tokens > 0) {
|
||||
image_max_pixels = custom_image_max_tokens * patch_area;
|
||||
}
|
||||
}
|
||||
|
||||
void set_warmup_n_tokens(int n_tokens) {
|
||||
int n_tok_per_side = static_cast<int>(std::sqrt(n_tokens));
|
||||
GGML_ASSERT(n_tok_per_side * n_tok_per_side == n_tokens && "n_tokens must be n*n");
|
||||
|
||||
+14
-3
@@ -708,9 +708,10 @@ ggml_tensor * clip_graph::build_attn(
|
||||
ggml_tensor * sinks) const {
|
||||
// these nodes are added to the graph together so that they are not reordered
|
||||
// by doing so, the number of splits in the graph is reduced
|
||||
ggml_build_forward_expand(gf, q_cur);
|
||||
ggml_build_forward_expand(gf, k_cur);
|
||||
ggml_build_forward_expand(gf, v_cur);
|
||||
// the order is fixed without the compute flag, so an unselected branch stays out of the compute set
|
||||
ggml_build_forward_order(gf, q_cur);
|
||||
ggml_build_forward_order(gf, k_cur);
|
||||
ggml_build_forward_order(gf, v_cur);
|
||||
|
||||
ggml_tensor * q = ggml_permute(ctx0, q_cur, 0, 2, 1, 3);
|
||||
//cb(q, "q", il);
|
||||
@@ -1433,6 +1434,7 @@ struct clip_model_loader {
|
||||
// use default llava-uhd preprocessing params
|
||||
get_u32(KEY_PROJ_SCALE_FACTOR, hparams.n_merge, false);
|
||||
get_u32(KEY_PREPROC_IMAGE_SIZE, hparams.image_longest_edge, false);
|
||||
hparams.set_limit_image_tokens();
|
||||
} break;
|
||||
case PROJECTOR_TYPE_LFM2:
|
||||
{
|
||||
@@ -1470,6 +1472,7 @@ struct clip_model_loader {
|
||||
get_u32(KEY_SPATIAL_MERGE_SIZE, hparams.n_merge, false);
|
||||
hparams.image_longest_edge = hparams.image_size;
|
||||
get_u32(KEY_PREPROC_IMAGE_SIZE, hparams.image_longest_edge, false);
|
||||
hparams.set_limit_image_tokens();
|
||||
hparams.set_warmup_n_tokens(256); // avoid OOM on warmup
|
||||
} break;
|
||||
case PROJECTOR_TYPE_DOTS_OCR:
|
||||
@@ -1594,6 +1597,7 @@ struct clip_model_loader {
|
||||
if (hparams.image_longest_edge == 0) {
|
||||
hparams.image_longest_edge = 3024;
|
||||
}
|
||||
// note: the step3vl preprocessor slices based on a fixed window grid, so it does not support custom min/max image tokens
|
||||
hparams.warmup_image_size = hparams.image_size;
|
||||
} break;
|
||||
case PROJECTOR_TYPE_YOUTUVL:
|
||||
@@ -1761,6 +1765,10 @@ struct clip_model_loader {
|
||||
// qwen2 encoder is GQA, requires KEY_N_HEAD_KV
|
||||
get_u32(string_format(KEY_N_HEAD_KV, "vision"), hparams.n_head_kv);
|
||||
}
|
||||
// unlimited-ocr shares the v1 projector but tiles up to 32
|
||||
get_u32(KEY_PREPROC_MIN_TILES, hparams.preproc_min_tiles, false);
|
||||
get_u32(KEY_PREPROC_MAX_TILES, hparams.preproc_max_tiles, false);
|
||||
GGML_ASSERT(hparams.preproc_min_tiles <= hparams.preproc_max_tiles);
|
||||
} break;
|
||||
case PROJECTOR_TYPE_HUNYUANVL:
|
||||
{
|
||||
@@ -1909,6 +1917,9 @@ struct clip_model_loader {
|
||||
if (hparams.image_max_pixels > 0) {
|
||||
LOG_INF("%s: image_max_pixels: %d%s\n", __func__, hparams.image_max_pixels, hparams.custom_image_max_tokens > 0 ? " (custom value)" : "");
|
||||
}
|
||||
if (hparams.preproc_max_tiles > 0) {
|
||||
LOG_INF("%s: preproc_tiles: %d - %d\n", __func__, hparams.preproc_min_tiles, hparams.preproc_max_tiles);
|
||||
}
|
||||
} else if (is_audio) {
|
||||
LOG_INF("\n--- audio hparams ---\n");
|
||||
LOG_INF("%s: n_mel_bins: %d\n", __func__, hparams.n_mel_bins);
|
||||
|
||||
@@ -253,6 +253,9 @@ ggml_cgraph * clip_graph_deepseekocr::build() {
|
||||
|
||||
bool is_overview = img.add_viewsep;
|
||||
int n_tiles_per_row = 0;
|
||||
// number of separate "row" images batched together in this graph call
|
||||
// (captured now, before n_batch below gets repurposed as the SAM/ViT batch size)
|
||||
const int n_rows_batch = n_batch;
|
||||
|
||||
// note: we expect either a batch of rows or a batch of overviews, but not a mix of both
|
||||
|
||||
@@ -272,16 +275,18 @@ ggml_cgraph * clip_graph_deepseekocr::build() {
|
||||
GGML_ASSERT(img.ny() % img.nx() == 0);
|
||||
n_tiles_per_row = img.ny() / img.nx();
|
||||
|
||||
// input shape: [tile_size, tile_size * n_tiles_per_row, 3]
|
||||
// we want to reshape it to [tile_size, tile_size, 3, n_tiles_per_row]
|
||||
inp_raw = ggml_reshape_4d(ctx0, inp_raw, img.nx(), img.nx(), n_tiles_per_row, 3);
|
||||
inp_raw = ggml_cont(ctx0, ggml_permute(ctx0, inp_raw, 0, 1, 3, 2));
|
||||
// each entry is one "row" image of shape [tile_size, tile_size * n_tiles_per_row, 3];
|
||||
// merge the tile axis into the batch axis, giving a combined SAM input of shape
|
||||
// [tile_size, tile_size, 3, n_tiles_per_row * n_rows_batch] (tile fast, row slow)
|
||||
inp_raw = ggml_reshape_4d(ctx0, inp_raw, img.nx() * img.nx(), n_tiles_per_row, 3, n_rows_batch);
|
||||
inp_raw = ggml_cont(ctx0, ggml_permute(ctx0, inp_raw, 0, 2, 1, 3));
|
||||
inp_raw = ggml_reshape_4d(ctx0, inp_raw, img.nx(), img.nx(), 3, n_tiles_per_row * n_rows_batch);
|
||||
}
|
||||
|
||||
ggml_tensor * sam_out = build_sam(inp_raw);
|
||||
|
||||
if (!is_overview) {
|
||||
n_batch = n_tiles_per_row;
|
||||
n_batch = n_tiles_per_row * n_rows_batch;
|
||||
}
|
||||
|
||||
const int clip_n_patches = sam_out->ne[0] * sam_out->ne[1];
|
||||
@@ -354,34 +359,36 @@ ggml_cgraph * clip_graph_deepseekocr::build() {
|
||||
const auto w = h;
|
||||
const auto n_dim = cur->ne[0];
|
||||
|
||||
ggml_tensor * imgnl = ggml_repeat_4d(ctx0, model.image_newline, n_dim, 1, h, 1);
|
||||
cur = ggml_reshape_3d(ctx0, cur, n_dim, w, h);
|
||||
cur = ggml_reshape_2d(ctx0, ggml_concat(ctx0, cur, imgnl, 1), n_dim, (w + 1) * h);
|
||||
cur = ggml_concat(ctx0, cur, model.view_seperator, 1); // (n_dim, h*(w+1) + 1)
|
||||
ggml_tensor * imgnl = ggml_repeat_4d(ctx0, model.image_newline, n_dim, 1, h, n_batch);
|
||||
cur = ggml_reshape_4d(ctx0, cur, n_dim, w, h, n_batch);
|
||||
cur = ggml_reshape_3d(ctx0, ggml_concat(ctx0, cur, imgnl, 1), n_dim, (w + 1) * h, n_batch);
|
||||
ggml_tensor * vs = ggml_repeat_4d(ctx0, model.view_seperator, n_dim, 1, n_batch, 1);
|
||||
cur = ggml_concat(ctx0, cur, vs, 1); // (n_dim, h*(w+1) + 1, n_batch)
|
||||
} else {
|
||||
// tile row: interleave tiles within each row, add newline per row
|
||||
const int grid_x = static_cast<int>(std::sqrt(static_cast<float>(clip_n_patches)));
|
||||
const int grid_y = grid_x;
|
||||
const auto n_dim = cur->ne[0];
|
||||
const int grid_x = static_cast<int>(std::sqrt(static_cast<float>(clip_n_patches)));
|
||||
const int grid_y = grid_x;
|
||||
const auto n_dim = cur->ne[0];
|
||||
|
||||
// (n_dim, clip_n_patches, n_batch) -> (n_dim, grid_x, grid_y, n_batch)
|
||||
cur = ggml_reshape_4d(ctx0, cur, n_dim, grid_x, grid_y, n_batch);
|
||||
// merge n_dim into the grid_x axis, freeing the 4th axis for n_rows_batch
|
||||
// (n_dim, clip_n_patches, n_tiles_per_row * n_rows_batch) -> (n_dim*grid_x, grid_y, n_tiles_per_row, n_rows_batch)
|
||||
cur = ggml_reshape_4d(ctx0, cur, n_dim * grid_x, grid_y, n_tiles_per_row, n_rows_batch);
|
||||
|
||||
// tiles: re-order from A.row0 A.row1 B.row0 B.row1 ...
|
||||
// to A.row0 B.row0 A.row1 B.row1 ...
|
||||
// then add nl: A.row0 B.row0 [nl] A.row1 B.row1 [nl] ...
|
||||
// interleave tiles: (n_dim, grid_x, grid_y, n_batch) -> (n_dim, grid_x, n_batch, grid_y)
|
||||
cur = ggml_cont(ctx0, ggml_permute(ctx0, cur, 0, 1, 3, 2));
|
||||
// interleave tiles: -> (n_dim*grid_x, n_tiles_per_row, grid_y, n_rows_batch)
|
||||
cur = ggml_cont(ctx0, ggml_permute(ctx0, cur, 0, 2, 1, 3));
|
||||
|
||||
// merge: (n_dim, grid_x, n_batch, grid_y) -> (n_dim, grid_x*n_batch, grid_y, 1)
|
||||
cur = ggml_reshape_4d(ctx0, cur, n_dim, grid_x * n_batch, grid_y, 1);
|
||||
// merge: -> (n_dim, grid_x*n_tiles_per_row, grid_y, n_rows_batch)
|
||||
cur = ggml_reshape_4d(ctx0, cur, n_dim, grid_x * n_tiles_per_row, grid_y, n_rows_batch);
|
||||
|
||||
// append newline per row: (n_dim, grid_x*n_batch+1, grid_y, 1)
|
||||
ggml_tensor * imgnl = ggml_repeat_4d(ctx0, model.image_newline, n_dim, 1, grid_y, 1);
|
||||
// append newline per row: (n_dim, grid_x*n_tiles_per_row+1, grid_y, n_rows_batch)
|
||||
ggml_tensor * imgnl = ggml_repeat_4d(ctx0, model.image_newline, n_dim, 1, grid_y, n_rows_batch);
|
||||
cur = ggml_concat(ctx0, cur, imgnl, 1);
|
||||
|
||||
// flatten: (n_dim, (grid_x*n_batch+1)*grid_y)
|
||||
cur = ggml_reshape_2d(ctx0, cur, n_dim, (grid_x * n_batch + 1) * grid_y);
|
||||
// flatten: (n_dim, (grid_x*n_tiles_per_row+1)*grid_y, n_rows_batch)
|
||||
cur = ggml_reshape_3d(ctx0, cur, n_dim, (grid_x * n_tiles_per_row + 1) * grid_y, n_rows_batch);
|
||||
}
|
||||
|
||||
cb(cur, "dsocr_output", -1);
|
||||
|
||||
@@ -14,8 +14,9 @@ ggml_cgraph * clip_graph_deepseekocr2::build() {
|
||||
{
|
||||
ggml_tensor * inp;
|
||||
|
||||
inp = ggml_reshape_2d(ctx0, sam_out, sam_out->ne[0] * sam_out->ne[1], sam_out->ne[2]); // H*W, C
|
||||
inp = ggml_cont(ctx0, ggml_permute(ctx0, inp, 1, 0, 2, 3));
|
||||
// H*W, C, B
|
||||
inp = ggml_reshape_3d(ctx0, sam_out, sam_out->ne[0] * sam_out->ne[1], sam_out->ne[2], sam_out->ne[3]);
|
||||
inp = ggml_cont(ctx0, ggml_permute(ctx0, inp, 1, 0, 2, 3)); // C, H*W, B
|
||||
|
||||
auto num_image_tokens = inp->ne[1]; // H*W
|
||||
GGML_ASSERT(num_image_tokens == 144 || num_image_tokens == 256);
|
||||
@@ -32,8 +33,10 @@ ggml_cgraph * clip_graph_deepseekocr2::build() {
|
||||
num_queries = 144;
|
||||
}
|
||||
|
||||
// (B, num_image_tokens + num_queries, C)
|
||||
inp = ggml_concat(ctx0, inp, ggml_cast(ctx0, query_embed, inp->type), 1);
|
||||
// repeat the query embedding per batch item, then append: (C, num_image_tokens + num_queries, B)
|
||||
query_embed = ggml_cast(ctx0, query_embed, inp->type);
|
||||
query_embed = ggml_repeat_4d(ctx0, query_embed, query_embed->ne[0], num_queries, inp->ne[2], 1);
|
||||
inp = ggml_concat(ctx0, inp, query_embed, 1);
|
||||
|
||||
auto seq_len = inp->ne[1];
|
||||
|
||||
@@ -57,7 +60,7 @@ ggml_cgraph * clip_graph_deepseekocr2::build() {
|
||||
/* learned_pos_embd */ nullptr, add_rope, vit_opts);
|
||||
|
||||
cur = ggml_cont(ctx0,
|
||||
ggml_view_2d(ctx0, cur, cur->ne[0], num_queries, cur->nb[1],
|
||||
ggml_view_3d(ctx0, cur, cur->ne[0], num_queries, cur->ne[2], cur->nb[1], cur->nb[2],
|
||||
cur->nb[1] * (cur->ne[1] - num_queries))); // only take query tokens for output
|
||||
|
||||
ggml_build_forward_expand(gf, cur);
|
||||
@@ -71,7 +74,8 @@ ggml_cgraph * clip_graph_deepseekocr2::build() {
|
||||
|
||||
// view_seperator only after the global view
|
||||
if (img.add_viewsep) {
|
||||
cur = ggml_concat(ctx0, cur, model.view_seperator, 1); // (n_dim, 257)
|
||||
ggml_tensor * vs = ggml_repeat_4d(ctx0, model.view_seperator, model.view_seperator->ne[0], 1, cur->ne[2], 1);
|
||||
cur = ggml_concat(ctx0, cur, vs, 1); // (n_dim, 257, n_batch)
|
||||
}
|
||||
|
||||
cb(cur, "dsocr2_output", -1);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user