mirror of
https://github.com/ggml-org/llama.cpp.git
synced 2026-11-08 11:57:39 -06:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7d7f028753 | ||
|
|
b65bf69213 | ||
|
|
a3c7cf08f9 | ||
|
|
57d04820df | ||
|
|
9982004913 | ||
|
|
cf34d31133 | ||
|
|
a691b23458 | ||
|
|
2277e75297 | ||
|
|
12ab597986 | ||
|
|
d6be065572 | ||
|
|
a2b301831d | ||
|
|
c19043f67e | ||
|
|
372dc5ca15 | ||
|
|
f477f795cb | ||
|
|
76a67730ff | ||
|
|
12e9084dc1 | ||
|
|
818ac6b078 | ||
|
|
e9a2a44fe9 | ||
|
|
a2654ec431 | ||
|
|
9f0e5098a5 | ||
|
|
e95426f169 | ||
|
|
f7591a6a01 | ||
|
|
80d2c0c2c5 | ||
|
|
0956684529 | ||
|
|
cf659f240b | ||
|
|
1938152648 | ||
|
|
5d7d4aec16 | ||
|
|
c0ab6e5c0b | ||
|
|
31424b7cf1 | ||
|
|
fd27b20349 | ||
|
|
ca89968a23 | ||
|
|
bcb0152876 | ||
|
|
669204ee2b | ||
|
|
954de248ac | ||
|
|
6c01da6278 | ||
|
|
8820b088de | ||
|
|
9a1d03c7ca | ||
|
|
18ab62a8ec | ||
|
|
52c9bad946 | ||
|
|
5d3ed2ae7e | ||
|
|
80088fa60b | ||
|
|
c4fb579695 | ||
|
|
3ed7284f2d | ||
|
|
d9cf1870be | ||
|
|
240d68fcfe | ||
|
|
bbc2e4b657 | ||
|
|
4b77dee052 | ||
|
|
67107ac34f | ||
|
|
e14a779719 | ||
|
|
d38bea3422 | ||
|
|
186eab1cb8 | ||
|
|
6023692b1e | ||
|
|
b1c902f026 | ||
|
|
e8df20d238 | ||
|
|
fecdc81eec | ||
|
|
45b6604b20 | ||
|
|
e30ad80fd7 | ||
|
|
e0f96a1a12 | ||
|
|
468fde90e8 | ||
|
|
1416f76aa1 | ||
|
|
10d4846a57 | ||
|
|
61d4472344 | ||
|
|
016c1d914c | ||
|
|
da3416d807 | ||
|
|
cc78da97c0 | ||
|
|
ea40a3a1e1 | ||
|
|
15e50990bb | ||
|
|
69ee2ecc01 | ||
|
|
2bc46baa92 | ||
|
|
3b83d12b08 | ||
|
|
e152332a15 | ||
|
|
1fa7f1c488 | ||
|
|
9c9074e14e | ||
|
|
f7b41cca4f | ||
|
|
c55b094880 | ||
|
|
2c192444c9 | ||
|
|
553d2c2e7e | ||
|
|
040ce199a1 | ||
|
|
d4c345d6c4 | ||
|
|
2ada83079a | ||
|
|
5a081c0a70 | ||
|
|
7e42b95f23 | ||
|
|
3259ab6e5d | ||
|
|
a01dff908b | ||
|
|
44f91a02b2 | ||
|
|
330f0189c9 | ||
|
|
7d516e25ea | ||
|
|
8bed7cfb99 | ||
|
|
8415bd7bb3 | ||
|
|
5ce06fc71f | ||
|
|
e56f006ed6 | ||
|
|
3de52ac388 | ||
|
|
6f1e654370 | ||
|
|
9e2a04a439 | ||
|
|
c6a0ff11a0 | ||
|
|
5851a8e505 | ||
|
|
efbf6e80a5 | ||
|
|
b393d73bb0 | ||
|
|
00df7c22d9 | ||
|
|
034e2535a9 | ||
|
|
52e53a76df | ||
|
|
cd959bae99 | ||
|
|
13ec8f614c | ||
|
|
cca14f64fe | ||
|
|
e853ec9a8c | ||
|
|
feaf800060 | ||
|
|
4c4ca5b188 | ||
|
|
162e2bb2e4 | ||
|
|
6900fb5ac8 | ||
|
|
bbb02c93e9 | ||
|
|
960b1d51b7 | ||
|
|
4b29d02629 | ||
|
|
bee23322f1 | ||
|
|
149f5641b9 | ||
|
|
b97627967c | ||
|
|
7071ba378a | ||
|
|
6cb3e672e8 | ||
|
|
6b9c0cfcba | ||
|
|
d1c4e5bec1 | ||
|
|
20a51f24a8 | ||
|
|
0f35d6d7b0 | ||
|
|
a464960ed3 | ||
|
|
9309bf1bcf | ||
|
|
d1044bc827 | ||
|
|
28b812d6cb | ||
|
|
749db7f034 | ||
|
|
0943ca5472 | ||
|
|
f9448cddc4 | ||
|
|
0978a6e902 | ||
|
|
0ef27309b7 | ||
|
|
8fc0376721 | ||
|
|
740251a920 | ||
|
|
71efc559a0 | ||
|
|
19e8a86fe8 | ||
|
|
259d91709d | ||
|
|
36ee3caf7a | ||
|
|
fac3a894fc | ||
|
|
b74298c109 | ||
|
|
37b0f9c36a | ||
|
|
ca8daad199 | ||
|
|
0f663d2471 | ||
|
|
00f113eceb | ||
|
|
e6192de0a6 | ||
|
|
4402e65401 | ||
|
|
74101b3cda | ||
|
|
713319e284 | ||
|
|
ee17f293b6 | ||
|
|
51fe42c5d1 | ||
|
|
2cbca389f5 | ||
|
|
29c720eaf7 | ||
|
|
d02b4c0d66 | ||
|
|
e4b6c8ca6a | ||
|
|
1b6935b227 | ||
|
|
3f8af15a76 | ||
|
|
cd8427d018 | ||
|
|
6b00d5627b | ||
|
|
458fcfc340 | ||
|
|
6ed812057c | ||
|
|
ea24b952cd | ||
|
|
84d9ce0fad | ||
|
|
dcbb091677 | ||
|
|
07ec7c8af0 | ||
|
|
cb02250b5b | ||
|
|
2c93f0b6e1 |
@@ -1,4 +1,4 @@
|
||||
ARG UBUNTU_VERSION=24.04
|
||||
ARG UBUNTU_VERSION=26.04
|
||||
ARG BUILD_DATE=N/A
|
||||
ARG APP_VERSION=N/A
|
||||
ARG APP_REVISION=N/A
|
||||
@@ -22,9 +22,7 @@ FROM docker.io/ubuntu:$UBUNTU_VERSION AS build
|
||||
ARG TARGETARCH
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y gcc-14 g++-14 build-essential git cmake libssl-dev
|
||||
|
||||
ENV CC=gcc-14 CXX=g++-14
|
||||
apt-get install -y build-essential git cmake libssl-dev
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
|
||||
@@ -84,6 +84,9 @@ RUN apt-get update \
|
||||
&& find /var/cache/apt/archives /var/lib/apt/lists -not -name lock -type f -delete \
|
||||
&& find /var/cache -type f -delete
|
||||
|
||||
# Some hosts (e.g. GKE) only mount the driver here, and CUDA 12.8.1-12.9.1 base images don't set these paths
|
||||
ENV LD_LIBRARY_PATH=/usr/local/nvidia/lib64:/usr/local/nvidia/lib:${LD_LIBRARY_PATH}
|
||||
|
||||
COPY --from=build /app/lib/ /app
|
||||
|
||||
### Full
|
||||
|
||||
@@ -64,7 +64,7 @@ RUN mkdir -p /app/full \
|
||||
&& cp requirements.txt /app/full \
|
||||
&& cp .devops/tools.sh /app/full/tools.sh
|
||||
|
||||
FROM docker.io/intel/oneapi-toolkit:$ONEAPI_VERSION AS base
|
||||
FROM docker.io/intel/deep-learning-essentials:$ONEAPI_VERSION AS base
|
||||
|
||||
ARG BUILD_DATE=N/A
|
||||
ARG APP_VERSION=N/A
|
||||
@@ -79,6 +79,8 @@ LABEL org.opencontainers.image.created=$BUILD_DATE \
|
||||
org.opencontainers.image.url=$IMAGE_URL \
|
||||
org.opencontainers.image.source=$IMAGE_SOURCE
|
||||
|
||||
COPY --from=build /opt/intel/oneapi/dnnl /opt/intel/oneapi/dnnl
|
||||
|
||||
#Following versions are for multiple GPUs, since 26.x has known issue:
|
||||
# https://github.com/ggml-org/llama.cpp/issues/21747,
|
||||
# https://github.com/intel/compute-runtime/issues/921.
|
||||
|
||||
@@ -82,20 +82,14 @@ COPY --from=build /app/full /app
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
ENV PATH="/root/.venv/bin:/root/.local/bin:${PATH}"
|
||||
|
||||
# Flag for compatibility with pip
|
||||
ARG UV_INDEX_STRATEGY="unsafe-best-match"
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y \
|
||||
build-essential \
|
||||
curl \
|
||||
git \
|
||||
ca-certificates \
|
||||
&& curl -LsSf https://astral.sh/uv/install.sh | sh \
|
||||
&& uv python install 3.13 \
|
||||
&& uv venv --python 3.13 /root/.venv \
|
||||
&& uv pip install --python /root/.venv/bin/python -r requirements.txt \
|
||||
python3 \
|
||||
python3-pip \
|
||||
python3-wheel \
|
||||
&& pip install --break-system-packages --upgrade setuptools \
|
||||
&& pip install --break-system-packages -r requirements.txt \
|
||||
&& apt autoremove -y \
|
||||
&& apt clean -y \
|
||||
&& rm -rf /tmp/* /var/tmp/* \
|
||||
|
||||
@@ -100,56 +100,56 @@ runs:
|
||||
echo "CUDA_PATH=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.1" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
||||
echo "CUDA_PATH_V13_1=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.1" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
||||
|
||||
- name: Install Cuda Toolkit 13.4 for x64
|
||||
if: ${{ inputs.cuda_version == '13.4' && inputs.cuda_arch == 'x64' }}
|
||||
- name: Install Cuda Toolkit 13.5 for x64
|
||||
if: ${{ inputs.cuda_version == '13.5' && inputs.cuda_arch == 'x64' }}
|
||||
shell: pwsh
|
||||
run: |
|
||||
mkdir -p "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4"
|
||||
mkdir -p "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5"
|
||||
choco install unzip -y
|
||||
curl -O "https://developer.download.nvidia.com/compute/cuda/redist/cuda_crt/windows-x86_64/cuda_crt-windows-x86_64-13.4.59-archive.zip"
|
||||
curl -O "https://developer.download.nvidia.com/compute/cuda/redist/cuda_cudart/windows-x86_64/cuda_cudart-windows-x86_64-13.4.49-archive.zip"
|
||||
curl -O "https://developer.download.nvidia.com/compute/cuda/redist/cuda_nvcc/windows-x86_64/cuda_nvcc-windows-x86_64-13.4.59-archive.zip"
|
||||
curl -O "https://developer.download.nvidia.com/compute/cuda/redist/cuda_nvrtc/windows-x86_64/cuda_nvrtc-windows-x86_64-13.4.59-archive.zip"
|
||||
curl -O "https://developer.download.nvidia.com/compute/cuda/redist/libcublas/windows-x86_64/libcublas-windows-x86_64-13.7.0.27-archive.zip"
|
||||
curl -O "https://developer.download.nvidia.com/compute/cuda/redist/libnvvm/windows-x86_64/libnvvm-windows-x86_64-13.4.59-archive.zip"
|
||||
curl -O "https://developer.download.nvidia.com/compute/cuda/redist/cuda_nvtx/windows-x86_64/cuda_nvtx-windows-x86_64-13.4.49-archive.zip"
|
||||
curl -O "https://developer.download.nvidia.com/compute/cuda/redist/cuda_profiler_api/windows-x86_64/cuda_profiler_api-windows-x86_64-13.4.49-archive.zip"
|
||||
curl -O "https://developer.download.nvidia.com/compute/cuda/redist/visual_studio_integration/windows-x86_64/visual_studio_integration-windows-x86_64-13.4.49-archive.zip"
|
||||
curl -O "https://developer.download.nvidia.com/compute/cuda/redist/cccl/windows-x86_64/cccl-windows-x86_64-13.3.4.2.1-archive.zip"
|
||||
unzip '*.zip' -d "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4"
|
||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4\cuda_crt-windows-x86_64-13.4.59-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4" /E /I /H /Y
|
||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4\cuda_cudart-windows-x86_64-13.4.49-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4" /E /I /H /Y
|
||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4\cuda_nvcc-windows-x86_64-13.4.59-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4" /E /I /H /Y
|
||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4\cuda_nvrtc-windows-x86_64-13.4.59-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4" /E /I /H /Y
|
||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4\libcublas-windows-x86_64-13.7.0.27-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4" /E /I /H /Y
|
||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4\libnvvm-windows-x86_64-13.4.59-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4" /E /I /H /Y
|
||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4\cuda_nvtx-windows-x86_64-13.4.49-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4" /E /I /H /Y
|
||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4\cuda_profiler_api-windows-x86_64-13.4.49-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4" /E /I /H /Y
|
||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4\visual_studio_integration-windows-x86_64-13.4.49-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4" /E /I /H /Y
|
||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4\cccl-windows-x86_64-13.3.4.2.1-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4" /E /I /H /Y
|
||||
echo "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
||||
echo "CUDA_PATH=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
||||
echo "CUDA_PATH_V13_4=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
||||
curl -O "https://developer.download.nvidia.com/compute/cuda/redist/cuda_crt/windows-x86_64/cuda_crt-windows-x86_64-13.5.37-archive.zip"
|
||||
curl -O "https://developer.download.nvidia.com/compute/cuda/redist/cuda_cudart/windows-x86_64/cuda_cudart-windows-x86_64-13.5.37-archive.zip"
|
||||
curl -O "https://developer.download.nvidia.com/compute/cuda/redist/cuda_nvcc/windows-x86_64/cuda_nvcc-windows-x86_64-13.5.37-archive.zip"
|
||||
curl -O "https://developer.download.nvidia.com/compute/cuda/redist/cuda_nvrtc/windows-x86_64/cuda_nvrtc-windows-x86_64-13.5.37-archive.zip"
|
||||
curl -O "https://developer.download.nvidia.com/compute/cuda/redist/libcublas/windows-x86_64/libcublas-windows-x86_64-13.10.0.20-archive.zip"
|
||||
curl -O "https://developer.download.nvidia.com/compute/cuda/redist/libnvvm/windows-x86_64/libnvvm-windows-x86_64-13.5.37-archive.zip"
|
||||
curl -O "https://developer.download.nvidia.com/compute/cuda/redist/cuda_nvtx/windows-x86_64/cuda_nvtx-windows-x86_64-13.5.25-archive.zip"
|
||||
curl -O "https://developer.download.nvidia.com/compute/cuda/redist/cuda_profiler_api/windows-x86_64/cuda_profiler_api-windows-x86_64-13.5.25-archive.zip"
|
||||
curl -O "https://developer.download.nvidia.com/compute/cuda/redist/visual_studio_integration/windows-x86_64/visual_studio_integration-windows-x86_64-13.5.25-archive.zip"
|
||||
curl -O "https://developer.download.nvidia.com/compute/cuda/redist/cccl/windows-x86_64/cccl-windows-x86_64-13.3.5.0.6-archive.zip"
|
||||
unzip '*.zip' -d "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5"
|
||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5\cuda_crt-windows-x86_64-13.5.37-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5" /E /I /H /Y
|
||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5\cuda_cudart-windows-x86_64-13.5.37-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5" /E /I /H /Y
|
||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5\cuda_nvcc-windows-x86_64-13.5.37-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5" /E /I /H /Y
|
||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5\cuda_nvrtc-windows-x86_64-13.5.37-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5" /E /I /H /Y
|
||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5\libcublas-windows-x86_64-13.10.0.20-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5" /E /I /H /Y
|
||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5\libnvvm-windows-x86_64-13.5.37-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5" /E /I /H /Y
|
||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5\cuda_nvtx-windows-x86_64-13.5.25-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5" /E /I /H /Y
|
||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5\cuda_profiler_api-windows-x86_64-13.5.25-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5" /E /I /H /Y
|
||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5\visual_studio_integration-windows-x86_64-13.5.25-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5" /E /I /H /Y
|
||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5\cccl-windows-x86_64-13.3.5.0.6-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5" /E /I /H /Y
|
||||
echo "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
||||
echo "CUDA_PATH=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
||||
echo "CUDA_PATH_V13_5=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
||||
|
||||
- name: Install Cuda Toolkit 13.4 for ARM64
|
||||
if: ${{ inputs.cuda_version == '13.4' && inputs.cuda_arch == 'arm64' }}
|
||||
- name: Install Cuda Toolkit 13.5 for ARM64
|
||||
if: ${{ inputs.cuda_version == '13.5' && inputs.cuda_arch == 'arm64' }}
|
||||
shell: pwsh
|
||||
run: |
|
||||
mkdir -p "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4"
|
||||
mkdir -p "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5"
|
||||
choco install unzip -y
|
||||
curl -O "https://developer.download.nvidia.com/compute/cuda/redist/cccl/windows-x86_64/cccl-windows-x86_64-13.3.4.2.1-archive.zip"
|
||||
curl -O "https://developer.download.nvidia.com/compute/cuda/redist/cuda_crt/windows-x86_64/cuda_crt-windows-x86_64-13.4.59-archive.zip"
|
||||
curl -O "https://developer.download.nvidia.com/compute/cuda/redist/cuda_nvcc/windows-x86_64/cuda_nvcc-windows-x86_64-13.4.59-archive.zip"
|
||||
curl -O "https://developer.download.nvidia.com/compute/cuda/redist/libnvvm/windows-x86_64/libnvvm-windows-x86_64-13.4.59-archive.zip"
|
||||
curl -O "https://developer.download.nvidia.com/compute/cuda/redist/cuda_cudart/windows-arm64/cuda_cudart-windows-arm64-13.4.49-archive.zip"
|
||||
curl -O "https://developer.download.nvidia.com/compute/cuda/redist/libcublas/windows-arm64/libcublas-windows-arm64-13.7.0.27-archive.zip"
|
||||
unzip '*.zip' -d "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4"
|
||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4\cccl-windows-x86_64-13.3.4.2.1-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4" /E /I /H /Y
|
||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4\cuda_crt-windows-x86_64-13.4.59-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4" /E /I /H /Y
|
||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4\cuda_nvcc-windows-x86_64-13.4.59-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4" /E /I /H /Y
|
||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4\libnvvm-windows-x86_64-13.4.59-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4" /E /I /H /Y
|
||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4\cuda_cudart-windows-arm64-13.4.49-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4" /E /I /H /Y
|
||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4\libcublas-windows-arm64-13.7.0.27-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4" /E /I /H /Y
|
||||
echo "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
||||
echo "CUDA_PATH=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
||||
echo "CUDA_PATH_V13_4=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
||||
curl -O "https://developer.download.nvidia.com/compute/cuda/redist/cccl/windows-x86_64/cccl-windows-x86_64-13.3.5.0.6-archive.zip"
|
||||
curl -O "https://developer.download.nvidia.com/compute/cuda/redist/cuda_crt/windows-x86_64/cuda_crt-windows-x86_64-13.5.37-archive.zip"
|
||||
curl -O "https://developer.download.nvidia.com/compute/cuda/redist/cuda_nvcc/windows-x86_64/cuda_nvcc-windows-x86_64-13.5.37-archive.zip"
|
||||
curl -O "https://developer.download.nvidia.com/compute/cuda/redist/libnvvm/windows-x86_64/libnvvm-windows-x86_64-13.5.37-archive.zip"
|
||||
curl -O "https://developer.download.nvidia.com/compute/cuda/redist/cuda_cudart/windows-arm64/cuda_cudart-windows-arm64-13.5.37-archive.zip"
|
||||
curl -O "https://developer.download.nvidia.com/compute/cuda/redist/libcublas/windows-arm64/libcublas-windows-arm64-13.10.0.20-archive.zip"
|
||||
unzip '*.zip' -d "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5"
|
||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5\cccl-windows-x86_64-13.3.5.0.6-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5" /E /I /H /Y
|
||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5\cuda_crt-windows-x86_64-13.5.37-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5" /E /I /H /Y
|
||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5\cuda_nvcc-windows-x86_64-13.5.37-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5" /E /I /H /Y
|
||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5\libnvvm-windows-x86_64-13.5.37-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5" /E /I /H /Y
|
||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5\cuda_cudart-windows-arm64-13.5.37-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5" /E /I /H /Y
|
||||
xcopy "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5\libcublas-windows-arm64-13.10.0.20-archive\*" "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5" /E /I /H /Y
|
||||
echo "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
||||
echo "CUDA_PATH=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
||||
echo "CUDA_PATH_V13_5=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.5" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
||||
|
||||
@@ -31,8 +31,8 @@ env:
|
||||
LLAMA_ARG_LOG_TIMESTAMPS: 1
|
||||
|
||||
jobs:
|
||||
ubuntu-24-llguidance:
|
||||
runs-on: ${{ 'ubuntu-24.04-arm' || 'ubuntu-24.04' }}
|
||||
ubuntu-26-llguidance:
|
||||
runs-on: ${{ 'ubuntu-26.04-arm' || 'ubuntu-26.04' }}
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
|
||||
@@ -33,7 +33,7 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
android-ndk-snapdragon:
|
||||
runs-on: ubuntu-24.04 # previously ubuntu-latest
|
||||
runs-on: ubuntu-26.04
|
||||
container:
|
||||
image: 'ghcr.io/snapdragon-toolchain/arm64-android:v0.8'
|
||||
defaults:
|
||||
@@ -67,7 +67,7 @@ jobs:
|
||||
path: pkg-snapdragon/llama.cpp
|
||||
|
||||
linux-iot-snapdragon:
|
||||
runs-on: ubuntu-24.04 # previously ubuntu-latest
|
||||
runs-on: ubuntu-26.04
|
||||
container:
|
||||
image: 'ghcr.io/snapdragon-toolchain/arm64-linux:v0.8'
|
||||
defaults:
|
||||
@@ -103,7 +103,7 @@ jobs:
|
||||
test-snapdragon-qdc:
|
||||
name: Test on QDC Device (${{ matrix.device }})
|
||||
needs: [android-ndk-snapdragon, linux-iot-snapdragon]
|
||||
runs-on: ubuntu-24.04-arm
|
||||
runs-on: ubuntu-26.04-arm
|
||||
timeout-minutes: 180
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
@@ -37,7 +37,7 @@ env:
|
||||
|
||||
jobs:
|
||||
default:
|
||||
runs-on: ubuntu-24.04 # previously ubuntu-latest
|
||||
runs-on: ubuntu-26.04
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
@@ -56,6 +56,7 @@ jobs:
|
||||
uses: android-actions/setup-android@be39fa834029ff78f1a44aa3bb0819b8fc2bd8fd # v4.0.4
|
||||
with:
|
||||
log-accepted-android-sdk-licenses: false
|
||||
packages: platform-tools cmake;3.31.6
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
@@ -63,7 +64,7 @@ jobs:
|
||||
./gradlew build --no-daemon
|
||||
|
||||
ndk:
|
||||
runs-on: ubuntu-24.04 # previously ubuntu-latest
|
||||
runs-on: ubuntu-26.04
|
||||
container:
|
||||
image: 'ghcr.io/snapdragon-toolchain/arm64-android:v0.3'
|
||||
defaults:
|
||||
@@ -101,7 +102,7 @@ jobs:
|
||||
path: pkg-adb/llama.cpp
|
||||
|
||||
arm64:
|
||||
runs-on: ubuntu-24.04 # previously ubuntu-latest
|
||||
runs-on: ubuntu-26.04
|
||||
|
||||
env:
|
||||
NDK_VERSION: "29.0.14206865"
|
||||
|
||||
@@ -40,8 +40,8 @@ jobs:
|
||||
# path: ./spacemit_toolchain
|
||||
# version: ${{ env.SPACEMIT_IME_TOOLCHAIN_VERSION }}
|
||||
|
||||
ubuntu-24-openvino-cache:
|
||||
runs-on: ubuntu-24.04
|
||||
ubuntu-26-openvino-cache:
|
||||
runs-on: ubuntu-26.04
|
||||
|
||||
env:
|
||||
# Sync versions in build-openvino.yml, ci-self-hosted-openvino.yml, release.yml, release-publish.yml, build-cache.yml, .devops/openvino.Dockerfile, docs/backend/OPENVINO.md
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
name: Build relocatable cmake package
|
||||
on:
|
||||
workflow_dispatch:
|
||||
workflow_call:
|
||||
|
||||
cache-mode: none
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
linux:
|
||||
runs-on: [self-hosted, Linux, fast]
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
PREFIX="$(pwd)"/inst
|
||||
cmake -S . -B build \
|
||||
-DCMAKE_PREFIX_PATH="$PREFIX" \
|
||||
-DLLAMA_OPENSSL=OFF \
|
||||
-DLLAMA_BUILD_TESTS=OFF \
|
||||
-DLLAMA_BUILD_TOOLS=OFF \
|
||||
-DLLAMA_BUILD_EXAMPLES=OFF \
|
||||
-DLLAMA_BUILD_APP=OFF \
|
||||
-DLLAMA_BUILD_IS_DEV=OFF \
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
cmake --build build --config Release -j $(nproc)
|
||||
cmake --install build --prefix "$PREFIX" --config Release
|
||||
|
||||
export LLAMA_CONFIG="$PREFIX"/lib/cmake/llama/llama-config.cmake
|
||||
build_commit=$(git rev-parse --short HEAD | xargs)
|
||||
build_number=$(git rev-list --count HEAD | xargs)
|
||||
|
||||
major=$(grep -oE "set\(LLAMA_VERSION_MAJOR[[:space:]]+[0-9]+" CMakeLists.txt | grep -oE "[0-9]+$")
|
||||
minor=$(grep -oE "set\(LLAMA_VERSION_MINOR[[:space:]]+[0-9]+" CMakeLists.txt | grep -oE "[0-9]+$")
|
||||
patch=$(grep -oE "set\(LLAMA_VERSION_PATCH[[:space:]]+[0-9]+" CMakeLists.txt | grep -oE "[0-9]+$")
|
||||
build_version="$major.$minor.$patch"
|
||||
|
||||
checks=("set\(LLAMA_VERSION[[:space:]]+$build_version\)"
|
||||
"set\(LLAMA_BUILD_COMMIT[[:space:]]+$build_commit\)"
|
||||
"set\(LLAMA_BUILD_NUMBER[[:space:]]+$build_number\)")
|
||||
|
||||
for check in "${checks[@]}"; do
|
||||
if ! grep -qE "$check" "$LLAMA_CONFIG"; then
|
||||
echo "Checking llama-config.cmake version... \"$check\" failed!"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Checking llama-config.cmake version... success."
|
||||
|
||||
cd examples/simple-cmake-pkg
|
||||
cmake -S . -B build -DCMAKE_PREFIX_PATH="$PREFIX"/lib/cmake
|
||||
cmake --build build -j $(nproc)
|
||||
@@ -7,7 +7,6 @@ on:
|
||||
- master
|
||||
paths: [
|
||||
'.github/workflows/build-cpu.yml',
|
||||
'.github/workflows/build-cmake-pkg.yml',
|
||||
'**/CMakeLists.txt',
|
||||
'**/.cmake',
|
||||
'**/*.h',
|
||||
@@ -20,7 +19,6 @@ on:
|
||||
types: [opened, synchronize, reopened]
|
||||
paths: [
|
||||
'.github/workflows/build-cpu.yml',
|
||||
'.github/workflows/build-cmake-pkg.yml',
|
||||
'ggml/src/ggml-rpc/**',
|
||||
'**/CMakeLists.txt',
|
||||
'**/.cmake',
|
||||
@@ -47,17 +45,14 @@ env:
|
||||
LLAMA_ARG_LOG_TIMESTAMPS: 1
|
||||
|
||||
jobs:
|
||||
build-cmake-pkg:
|
||||
uses: ./.github/workflows/build-cmake-pkg.yml
|
||||
|
||||
ubuntu:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- build: 'x64'
|
||||
os: ubuntu-22.04
|
||||
os: ubuntu-26.04
|
||||
- build: 'arm64'
|
||||
os: ubuntu-24.04-arm
|
||||
os: ubuntu-26.04-arm
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
@@ -81,13 +76,6 @@ jobs:
|
||||
libjpeg-dev build-essential libssl-dev \
|
||||
git-lfs
|
||||
|
||||
- name: Toolchain workaround (GCC 14)
|
||||
if: ${{ contains(matrix.os, 'ubuntu-24.04') }}
|
||||
run: |
|
||||
sudo apt-get install -y gcc-14 g++-14
|
||||
echo "CC=gcc-14" >> "$GITHUB_ENV"
|
||||
echo "CXX=g++-14" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Python Dependencies
|
||||
id: python_depends
|
||||
run: |
|
||||
@@ -242,3 +230,79 @@ jobs:
|
||||
older: 5m
|
||||
min: 1
|
||||
dry-run: ${{ github.event_name != 'push' || github.ref != 'refs/heads/master' }}
|
||||
|
||||
build-cmake-pkg:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Clone
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: ccache
|
||||
uses: ggml-org/ccache-action@v1.2.24
|
||||
with:
|
||||
restore: false
|
||||
save: false
|
||||
|
||||
- name: ccache-buckets-restore
|
||||
uses: ./.github/actions/ccache-buckets
|
||||
env:
|
||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CI }}
|
||||
with:
|
||||
key: build-cmake-pkg
|
||||
folder: llama.cpp
|
||||
hf_bucket: ggml-org/cache
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
PREFIX="$(pwd)"/inst
|
||||
cmake -S . -B build \
|
||||
-DCMAKE_PREFIX_PATH="$PREFIX" \
|
||||
-DLLAMA_OPENSSL=OFF \
|
||||
-DLLAMA_BUILD_TESTS=OFF \
|
||||
-DLLAMA_BUILD_TOOLS=OFF \
|
||||
-DLLAMA_BUILD_EXAMPLES=OFF \
|
||||
-DLLAMA_BUILD_APP=OFF \
|
||||
-DLLAMA_BUILD_IS_DEV=OFF \
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
cmake --build build --config Release -j $(nproc)
|
||||
cmake --install build --prefix "$PREFIX" --config Release
|
||||
|
||||
export LLAMA_CONFIG="$PREFIX"/lib/cmake/llama/llama-config.cmake
|
||||
build_commit=$(git rev-parse --short HEAD | xargs)
|
||||
build_number=$(git rev-list --count HEAD | xargs)
|
||||
|
||||
major=$(grep -oE "set\(LLAMA_VERSION_MAJOR[[:space:]]+[0-9]+" CMakeLists.txt | grep -oE "[0-9]+$")
|
||||
minor=$(grep -oE "set\(LLAMA_VERSION_MINOR[[:space:]]+[0-9]+" CMakeLists.txt | grep -oE "[0-9]+$")
|
||||
patch=$(grep -oE "set\(LLAMA_VERSION_PATCH[[:space:]]+[0-9]+" CMakeLists.txt | grep -oE "[0-9]+$")
|
||||
build_version="$major.$minor.$patch"
|
||||
|
||||
checks=("set\(LLAMA_VERSION[[:space:]]+$build_version\)"
|
||||
"set\(LLAMA_BUILD_COMMIT[[:space:]]+$build_commit\)"
|
||||
"set\(LLAMA_BUILD_NUMBER[[:space:]]+$build_number\)")
|
||||
|
||||
for check in "${checks[@]}"; do
|
||||
if ! grep -qE "$check" "$LLAMA_CONFIG"; then
|
||||
echo "Checking llama-config.cmake version... \"$check\" failed!"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Checking llama-config.cmake version... success."
|
||||
|
||||
cd examples/simple-cmake-pkg
|
||||
cmake -S . -B build -DCMAKE_PREFIX_PATH="$PREFIX"/lib/cmake
|
||||
cmake --build build -j $(nproc)
|
||||
|
||||
- name: ccache-buckets-save
|
||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||
uses: ./.github/actions/ccache-buckets
|
||||
env:
|
||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CACHE_OUTPUT }}
|
||||
with:
|
||||
key: build-cmake-pkg
|
||||
folder: llama.cpp
|
||||
evict-old-files: 1d
|
||||
hf_bucket: ggml-org/cache
|
||||
save: true
|
||||
|
||||
@@ -163,7 +163,7 @@ jobs:
|
||||
# cmake --build build --config Release -j $(nproc)
|
||||
|
||||
debian-13-loongarch64-cpu-cross:
|
||||
runs-on: ${{ 'ubuntu-24.04-arm' || 'ubuntu-24.04' }}
|
||||
runs-on: ${{ 'ubuntu-26.04-arm' || 'ubuntu-26.04' }}
|
||||
container: debian@sha256:653dfb9f86c3782e8369d5f7d29bb8faba1f4bff9025db46e807fa4c22903671
|
||||
|
||||
steps:
|
||||
@@ -218,7 +218,7 @@ jobs:
|
||||
cmake --build build --config Release -j $(nproc)
|
||||
|
||||
debian-13-loongarch64-vulkan-cross:
|
||||
runs-on: ${{ 'ubuntu-24.04-arm' || 'ubuntu-24.04' }}
|
||||
runs-on: ${{ 'ubuntu-26.04-arm' || 'ubuntu-26.04' }}
|
||||
container: debian@sha256:653dfb9f86c3782e8369d5f7d29bb8faba1f4bff9025db46e807fa4c22903671
|
||||
|
||||
steps:
|
||||
@@ -276,8 +276,8 @@ jobs:
|
||||
|
||||
cmake --build build --config Release -j $(nproc)
|
||||
|
||||
ubuntu-24-riscv64-cpu-spacemit-ime-cross:
|
||||
runs-on: ubuntu-24.04
|
||||
ubuntu-26-riscv64-cpu-spacemit-ime-cross:
|
||||
runs-on: ubuntu-26.04
|
||||
|
||||
env:
|
||||
# Make sure this is in sync with build-cache.yml
|
||||
|
||||
@@ -40,12 +40,12 @@ jobs:
|
||||
- cuda: '12.4'
|
||||
arch: x64
|
||||
defines: '-DGGML_CUDA_CCCL_VERSION=v3.4.3'
|
||||
- cuda: '13.4'
|
||||
- cuda: '13.5'
|
||||
arch: x64
|
||||
defines: '-DGGML_CUDA_CCCL_VERSION=v3.4.3'
|
||||
- cuda: '13.4'
|
||||
defines: ''
|
||||
- cuda: '13.5'
|
||||
arch: arm64
|
||||
defines: '-DGGML_CUDA_CCCL_VERSION=v3.4.3 -DCMAKE_TOOLCHAIN_FILE=cmake/arm64-windows-msvc-cuda.cmake'
|
||||
defines: '-DCMAKE_TOOLCHAIN_FILE=cmake/arm64-windows-msvc-cuda.cmake'
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
|
||||
@@ -43,13 +43,12 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
# thread and address doesn't run properly on some self hosted machines, so run it on Github instead
|
||||
- sanitizer: ADDRESS
|
||||
machine: ubuntu-24.04
|
||||
machine: ubuntu-26.04
|
||||
- sanitizer: THREAD
|
||||
machine: ubuntu-24.04
|
||||
machine: ubuntu-26.04
|
||||
- sanitizer: UNDEFINED
|
||||
machine: [self-hosted, X64, Linux, CPU]
|
||||
machine: ubuntu-26.04
|
||||
|
||||
runs-on: ${{ matrix.machine }}
|
||||
|
||||
@@ -58,31 +57,24 @@ jobs:
|
||||
id: checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
# - name: ccache
|
||||
# uses: ggml-org/ccache-action@v1.2.24
|
||||
# if: ${{ matrix.sanitizer != 'UNDEFINED' }}
|
||||
# with:
|
||||
# key: ctest-${{ matrix.sanitizer }}-ubuntu-24.04
|
||||
# variant: ccache
|
||||
# evict-old-files: 1d
|
||||
# save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||
- name: ccache
|
||||
uses: ggml-org/ccache-action@v1.2.24
|
||||
with:
|
||||
restore: false
|
||||
save: false
|
||||
|
||||
# with UNDEFINED sanitizer, we have to build in Debug to avoid GCC 13 false-positive warnings
|
||||
- name: Build (undefined)
|
||||
id: cmake_build_undefined
|
||||
if: ${{ matrix.sanitizer == 'UNDEFINED' }}
|
||||
run: |
|
||||
cmake -B build \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DLLAMA_FATAL_WARNINGS=ON \
|
||||
-DLLAMA_SANITIZE_${{ matrix.sanitizer }}=ON \
|
||||
-DGGML_SANITIZE_${{ matrix.sanitizer }}=ON
|
||||
|
||||
cmake --build build --config Debug -j $(nproc)
|
||||
- name: ccache-buckets-restore
|
||||
uses: ./.github/actions/ccache-buckets
|
||||
env:
|
||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CI }}
|
||||
with:
|
||||
key: ctest-sanitizer-${{ matrix.sanitizer }}
|
||||
folder: llama.cpp
|
||||
hf_bucket: ggml-org/cache
|
||||
|
||||
- name: Build
|
||||
id: cmake_build
|
||||
if: ${{ matrix.sanitizer == 'ADDRESS' }}
|
||||
if: ${{ matrix.sanitizer == 'ADDRESS' || matrix.sanitizer == 'UNDEFINED' }}
|
||||
run: |
|
||||
cmake -B build \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
@@ -103,6 +95,18 @@ jobs:
|
||||
|
||||
cmake --build build --config RelWithDebInfo -j $(nproc)
|
||||
|
||||
- name: ccache-buckets-save
|
||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||
uses: ./.github/actions/ccache-buckets
|
||||
env:
|
||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CACHE_OUTPUT }}
|
||||
with:
|
||||
key: ctest-sanitizer-${{ matrix.sanitizer }}
|
||||
folder: llama.cpp
|
||||
evict-old-files: 1d
|
||||
hf_bucket: ggml-org/cache
|
||||
save: true
|
||||
|
||||
- name: Test
|
||||
id: cmake_test
|
||||
run: |
|
||||
|
||||
@@ -38,7 +38,7 @@ env:
|
||||
LLAMA_ARG_LOG_TIMESTAMPS: 1
|
||||
|
||||
jobs:
|
||||
ubuntu-24-sycl:
|
||||
ubuntu-26-sycl:
|
||||
strategy:
|
||||
matrix:
|
||||
build: [fp32, fp16]
|
||||
@@ -48,7 +48,7 @@ jobs:
|
||||
- build: fp16
|
||||
fp16: ON
|
||||
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
|
||||
env:
|
||||
ONEAPI_ROOT: /opt/intel/oneapi/
|
||||
@@ -103,7 +103,7 @@ jobs:
|
||||
env:
|
||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CI }}
|
||||
with:
|
||||
key: sycl-ubuntu-24-${{ matrix.build }}
|
||||
key: sycl-ubuntu-26-${{ matrix.build }}
|
||||
folder: llama.cpp
|
||||
hf_bucket: ggml-org/cache
|
||||
|
||||
@@ -131,7 +131,7 @@ jobs:
|
||||
env:
|
||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CACHE_OUTPUT }}
|
||||
with:
|
||||
key: sycl-ubuntu-24-${{ matrix.build }}
|
||||
key: sycl-ubuntu-26-${{ matrix.build }}
|
||||
folder: llama.cpp
|
||||
evict-old-files: 1d
|
||||
hf_bucket: ggml-org/cache
|
||||
|
||||
@@ -31,8 +31,8 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
ubuntu-24-virtgpu:
|
||||
runs-on: ${{ 'ubuntu-24.04-arm' || 'ubuntu-24.04' }}
|
||||
ubuntu-26-virtgpu:
|
||||
runs-on: ${{ 'ubuntu-26.04-arm' || 'ubuntu-26.04' }}
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
|
||||
@@ -42,7 +42,7 @@ env:
|
||||
|
||||
jobs:
|
||||
ubuntu-arm64:
|
||||
runs-on: ubuntu-24.04-arm
|
||||
runs-on: ubuntu-26.04-arm
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
@@ -53,9 +53,7 @@ jobs:
|
||||
id: depends
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y gcc-14 g++-14 build-essential glslc libvulkan-dev spirv-headers libssl-dev ninja-build
|
||||
echo "CC=gcc-14" >> "$GITHUB_ENV"
|
||||
echo "CXX=g++-14" >> "$GITHUB_ENV"
|
||||
sudo apt-get install -y build-essential glslc libvulkan-dev spirv-headers libssl-dev ninja-build
|
||||
|
||||
- name: ccache
|
||||
uses: ggml-org/ccache-action@v1.2.24
|
||||
@@ -69,7 +67,7 @@ jobs:
|
||||
env:
|
||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CI }}
|
||||
with:
|
||||
key: vulkan-ubuntu-24.04-arm
|
||||
key: vulkan-ubuntu-26.04-arm
|
||||
folder: llama.cpp
|
||||
hf_bucket: ggml-org/cache
|
||||
|
||||
@@ -92,14 +90,14 @@ jobs:
|
||||
env:
|
||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CACHE_OUTPUT }}
|
||||
with:
|
||||
key: vulkan-ubuntu-24.04-arm
|
||||
key: vulkan-ubuntu-26.04-arm
|
||||
folder: llama.cpp
|
||||
evict-old-files: 1d
|
||||
hf_bucket: ggml-org/cache
|
||||
save: true
|
||||
|
||||
ubuntu-llvmpipe:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
@@ -137,7 +135,7 @@ jobs:
|
||||
env:
|
||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CI }}
|
||||
with:
|
||||
key: vulkan-ubuntu-24.04-llvmpipe
|
||||
key: vulkan-ubuntu-26.04-llvmpipe
|
||||
folder: llama.cpp
|
||||
hf_bucket: ggml-org/cache
|
||||
|
||||
@@ -156,7 +154,7 @@ jobs:
|
||||
env:
|
||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CACHE_OUTPUT }}
|
||||
with:
|
||||
key: vulkan-ubuntu-24.04-llvmpipe
|
||||
key: vulkan-ubuntu-26.04-llvmpipe
|
||||
folder: llama.cpp
|
||||
evict-old-files: 1d
|
||||
hf_bucket: ggml-org/cache
|
||||
|
||||
@@ -49,7 +49,7 @@ env:
|
||||
|
||||
jobs:
|
||||
ubuntu-webgpu:
|
||||
runs-on: ubuntu-24.04-arm
|
||||
runs-on: ubuntu-26.04-arm
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
@@ -97,7 +97,7 @@ jobs:
|
||||
env:
|
||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CI }}
|
||||
with:
|
||||
key: webgpu-ubuntu-24.04-arm-wasi
|
||||
key: webgpu-ubuntu-26.04-arm-wasi
|
||||
folder: llama.cpp
|
||||
hf_bucket: ggml-org/cache
|
||||
|
||||
@@ -135,7 +135,7 @@ jobs:
|
||||
env:
|
||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CACHE_OUTPUT }}
|
||||
with:
|
||||
key: webgpu-ubuntu-24.04-arm-wasi
|
||||
key: webgpu-ubuntu-26.04-arm-wasi
|
||||
folder: llama.cpp
|
||||
evict-old-files: 1d
|
||||
hf_bucket: ggml-org/cache
|
||||
|
||||
@@ -50,7 +50,7 @@ env:
|
||||
|
||||
jobs:
|
||||
ubuntu-webgpu:
|
||||
runs-on: ubuntu-24.04-arm
|
||||
runs-on: ubuntu-26.04-arm
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
@@ -84,7 +84,7 @@ jobs:
|
||||
env:
|
||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CI }}
|
||||
with:
|
||||
key: webgpu-ubuntu-24.04-arm-wasm
|
||||
key: webgpu-ubuntu-26.04-arm-wasm
|
||||
folder: llama.cpp
|
||||
hf_bucket: ggml-org/cache
|
||||
|
||||
@@ -107,7 +107,7 @@ jobs:
|
||||
env:
|
||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CACHE_OUTPUT }}
|
||||
with:
|
||||
key: webgpu-ubuntu-24.04-arm-wasm
|
||||
key: webgpu-ubuntu-26.04-arm-wasm
|
||||
folder: llama.cpp
|
||||
evict-old-files: 1d
|
||||
hf_bucket: ggml-org/cache
|
||||
|
||||
@@ -34,7 +34,7 @@ env:
|
||||
|
||||
jobs:
|
||||
format:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key |
|
||||
sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc > /dev/null
|
||||
sudo add-apt-repository -y \
|
||||
"deb http://apt.llvm.org/noble/ llvm-toolchain-noble-22 main"
|
||||
"deb http://apt.llvm.org/resolute/ llvm-toolchain-resolute-22 main"
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y clang-format-22
|
||||
|
||||
|
||||
@@ -46,18 +46,55 @@ env:
|
||||
|
||||
jobs:
|
||||
cpu-x64-high-perf:
|
||||
runs-on: [self-hosted, Linux, X64, CPU]
|
||||
runs-on: hf-jobs-cpu-upgrade:ubuntu26_04
|
||||
|
||||
# note: this runner has 8 CPUs, but std::thread::hardware_concurrency reports the cores of the
|
||||
# host (https://github.com/ggml-org/llama.cpp/pull/31439#issuecomment-6683386059)
|
||||
env:
|
||||
TEST_ARG_HARDWARE_CONCURRENCY: 8
|
||||
TEST_ARG_PARALLEL_WORKERS: 4
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
id: checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Dependencies
|
||||
id: depends
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y build-essential cmake libssl-dev time unzip wget python3 python3-venv python3-dev
|
||||
|
||||
- name: ccache
|
||||
uses: ggml-org/ccache-action@v1.2.24
|
||||
with:
|
||||
restore: false
|
||||
save: false
|
||||
|
||||
- name: ccache-buckets-restore
|
||||
uses: ./.github/actions/ccache-buckets
|
||||
with:
|
||||
key: self-hosted-cpu-x64-high-perf
|
||||
folder: llama.cpp
|
||||
hf_bucket: ggml-org/cache
|
||||
|
||||
- name: Test
|
||||
id: ggml-ci
|
||||
run: |
|
||||
LLAMA_ARG_THREADS=$(nproc) GG_BUILD_HIGH_PERF=1 GG_BUILD_EXTRA_TESTS_0=1 bash ./ci/run.sh ~/results/llama.cpp/$RUNNER_NAME ~/mnt/llama.cpp
|
||||
|
||||
- name: ccache-buckets-save
|
||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||
uses: ./.github/actions/ccache-buckets
|
||||
env:
|
||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CACHE_OUTPUT }}
|
||||
with:
|
||||
key: self-hosted-cpu-x64-high-perf
|
||||
folder: llama.cpp
|
||||
evict-old-files: 1d
|
||||
hf_bucket: ggml-org/cache
|
||||
save: true
|
||||
|
||||
cpu-arm64-high-perf-graviton4:
|
||||
runs-on: ah-ubuntu_24_04-c8g_8x
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ cache-mode: none
|
||||
jobs:
|
||||
# The job MUST be called `copilot-setup-steps` or it will not be picked up by Copilot.
|
||||
copilot-setup-steps:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
|
||||
# Set the permissions to the lowest permissions possible needed for your steps.
|
||||
# Copilot will be given its own token for its operations.
|
||||
|
||||
@@ -70,7 +70,7 @@ jobs:
|
||||
|
||||
prepare_matrices:
|
||||
name: Prepare Docker matrices
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
outputs:
|
||||
build_matrix: ${{ steps.matrices.outputs.build_matrix }}
|
||||
merge_matrix: ${{ steps.matrices.outputs.merge_matrix }}
|
||||
@@ -87,19 +87,19 @@ jobs:
|
||||
# Keep all build targets in one place and derive merge targets from it.
|
||||
cat > build-matrix.json <<'JSON'
|
||||
[
|
||||
{ "tag": "cpu", "dockerfile": ".devops/cpu.Dockerfile", "platforms": "linux/amd64", "full": true, "light": true, "server": true, "free_disk_space": false, "runs_on": "ubuntu-24.04" },
|
||||
{ "tag": "cpu", "dockerfile": ".devops/cpu.Dockerfile", "platforms": "linux/arm64", "full": true, "light": true, "server": true, "free_disk_space": false, "runs_on": "ubuntu-24.04-arm" },
|
||||
{ "tag": "cpu", "dockerfile": ".devops/s390x.Dockerfile", "platforms": "linux/s390x", "full": true, "light": true, "server": true, "free_disk_space": false, "runs_on": "ubuntu-24.04-s390x", "prebuilt_ui": true },
|
||||
{ "tag": "cuda cuda12", "dockerfile": ".devops/cuda.Dockerfile", "cuda_version": "12.8.1", "platforms": "linux/amd64", "full": true, "light": true, "server": true, "free_disk_space": true, "runs_on": "ubuntu-24.04" },
|
||||
{ "tag": "cuda cuda12", "dockerfile": ".devops/cuda.Dockerfile", "cuda_version": "12.8.1", "platforms": "linux/arm64", "full": true, "light": true, "server": true, "free_disk_space": true, "runs_on": "ubuntu-24.04-arm" },
|
||||
{ "tag": "cuda13", "dockerfile": ".devops/cuda.Dockerfile", "cuda_version": "13.4.1", "platforms": "linux/amd64", "full": true, "light": true, "server": true, "free_disk_space": true, "runs_on": "ubuntu-24.04" },
|
||||
{ "tag": "cuda13", "dockerfile": ".devops/cuda.Dockerfile", "cuda_version": "13.4.1", "platforms": "linux/arm64", "full": true, "light": true, "server": true, "free_disk_space": true, "runs_on": "ubuntu-24.04-arm" },
|
||||
{ "tag": "musa", "dockerfile": ".devops/musa.Dockerfile", "platforms": "linux/amd64", "full": true, "light": true, "server": true, "free_disk_space": true, "runs_on": "ubuntu-24.04" },
|
||||
{ "tag": "intel", "dockerfile": ".devops/intel.Dockerfile", "platforms": "linux/amd64", "full": true, "light": true, "server": true, "free_disk_space": true, "runs_on": "ubuntu-24.04" },
|
||||
{ "tag": "vulkan", "dockerfile": ".devops/vulkan.Dockerfile", "platforms": "linux/amd64", "full": true, "light": true, "server": true, "free_disk_space": false, "runs_on": "ubuntu-24.04" },
|
||||
{ "tag": "vulkan", "dockerfile": ".devops/vulkan.Dockerfile", "platforms": "linux/arm64", "full": true, "light": true, "server": true, "free_disk_space": false, "runs_on": "ubuntu-24.04-arm" },
|
||||
{ "tag": "rocm", "dockerfile": ".devops/rocm.Dockerfile", "platforms": "linux/amd64", "full": true, "light": true, "server": true, "free_disk_space": true, "runs_on": "ubuntu-24.04" },
|
||||
{ "tag": "openvino", "dockerfile": ".devops/openvino.Dockerfile", "platforms": "linux/amd64", "full": true, "light": true, "server": true, "free_disk_space": false, "runs_on": "ubuntu-24.04" }
|
||||
{ "tag": "cpu", "dockerfile": ".devops/cpu.Dockerfile", "platforms": "linux/amd64", "full": true, "light": true, "server": true, "free_disk_space": false, "runs_on": "ubuntu-26.04" },
|
||||
{ "tag": "cpu", "dockerfile": ".devops/cpu.Dockerfile", "platforms": "linux/arm64", "full": true, "light": true, "server": true, "free_disk_space": false, "runs_on": "ubuntu-26.04-arm" },
|
||||
{ "tag": "cpu", "dockerfile": ".devops/s390x.Dockerfile", "platforms": "linux/s390x", "full": true, "light": true, "server": true, "free_disk_space": false, "runs_on": "ubuntu-26.04-s390x", "prebuilt_ui": true },
|
||||
{ "tag": "cuda cuda12", "dockerfile": ".devops/cuda.Dockerfile", "cuda_version": "12.8.1", "platforms": "linux/amd64", "full": true, "light": true, "server": true, "free_disk_space": true, "runs_on": "ubuntu-26.04" },
|
||||
{ "tag": "cuda cuda12", "dockerfile": ".devops/cuda.Dockerfile", "cuda_version": "12.8.1", "platforms": "linux/arm64", "full": true, "light": true, "server": true, "free_disk_space": true, "runs_on": "ubuntu-26.04-arm" },
|
||||
{ "tag": "cuda13", "dockerfile": ".devops/cuda.Dockerfile", "cuda_version": "13.5.0", "platforms": "linux/amd64", "full": true, "light": true, "server": true, "free_disk_space": true, "runs_on": "ubuntu-26.04" },
|
||||
{ "tag": "cuda13", "dockerfile": ".devops/cuda.Dockerfile", "cuda_version": "13.5.0", "platforms": "linux/arm64", "full": true, "light": true, "server": true, "free_disk_space": true, "runs_on": "ubuntu-26.04-arm" },
|
||||
{ "tag": "musa", "dockerfile": ".devops/musa.Dockerfile", "platforms": "linux/amd64", "full": true, "light": true, "server": true, "free_disk_space": true, "runs_on": "ubuntu-26.04" },
|
||||
{ "tag": "intel", "dockerfile": ".devops/intel.Dockerfile", "platforms": "linux/amd64", "full": true, "light": true, "server": true, "free_disk_space": true, "runs_on": "ubuntu-26.04" },
|
||||
{ "tag": "vulkan", "dockerfile": ".devops/vulkan.Dockerfile", "platforms": "linux/amd64", "full": true, "light": true, "server": true, "free_disk_space": false, "runs_on": "ubuntu-26.04" },
|
||||
{ "tag": "vulkan", "dockerfile": ".devops/vulkan.Dockerfile", "platforms": "linux/arm64", "full": true, "light": true, "server": true, "free_disk_space": false, "runs_on": "ubuntu-26.04-arm" },
|
||||
{ "tag": "rocm", "dockerfile": ".devops/rocm.Dockerfile", "platforms": "linux/amd64", "full": true, "light": true, "server": true, "free_disk_space": true, "runs_on": "ubuntu-26.04" },
|
||||
{ "tag": "openvino", "dockerfile": ".devops/openvino.Dockerfile", "platforms": "linux/amd64", "full": true, "light": true, "server": true, "free_disk_space": false, "runs_on": "ubuntu-26.04" }
|
||||
]
|
||||
JSON
|
||||
|
||||
@@ -400,7 +400,7 @@ jobs:
|
||||
merge_arch_tags:
|
||||
name: Create shared tags from digests
|
||||
needs: [prepare_matrices, push_to_registry, create_tag]
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-26.04
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
@@ -24,7 +24,7 @@ permissions:
|
||||
jobs:
|
||||
deploy:
|
||||
|
||||
runs-on: ubuntu-24.04 # previously ubuntu-latest
|
||||
runs-on: ubuntu-26.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
@@ -39,7 +39,7 @@ permissions:
|
||||
|
||||
jobs:
|
||||
make-release:
|
||||
runs-on: ubuntu-24.04 # previously ubuntu-latest
|
||||
runs-on: ubuntu-26.04
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
|
||||
@@ -11,7 +11,8 @@ on:
|
||||
'tests/fusion/**',
|
||||
'tests/test-fusion.cpp',
|
||||
'tests/test-llama-archs.cpp',
|
||||
'src/llama-graph.cpp',
|
||||
'src/llama-graph*',
|
||||
'src/llama-kv-cache*',
|
||||
'src/llama-model*',
|
||||
'src/models/**'
|
||||
]
|
||||
@@ -24,7 +25,8 @@ on:
|
||||
'tests/fusion/**',
|
||||
'tests/test-fusion.cpp',
|
||||
'tests/test-llama-archs.cpp',
|
||||
'src/llama-graph.cpp',
|
||||
'src/llama-graph*',
|
||||
'src/llama-kv-cache*',
|
||||
'src/llama-model*',
|
||||
'src/models/**'
|
||||
]
|
||||
@@ -145,6 +147,11 @@ jobs:
|
||||
rm -rf build-ci-models && mkdir -p build-ci-models
|
||||
./build/bin/test-llama-archs -o build-ci-models
|
||||
|
||||
- name: Test KV shift
|
||||
id: test_kv_shift
|
||||
run: |
|
||||
./build/bin/test-llama-archs --kv-shift
|
||||
|
||||
- name: Test fusion
|
||||
id: test_fusion
|
||||
run: |
|
||||
@@ -293,6 +300,11 @@ jobs:
|
||||
# run: |
|
||||
# ./build/bin/test-fusion --models build-ci-models --device Vulkan0 --check tests/fusion/Vulkan.csv
|
||||
|
||||
- name: Test KV shift
|
||||
id: test_kv_shift
|
||||
run: |
|
||||
./build/bin/test-llama-archs --kv-shift
|
||||
|
||||
- name: Test archs
|
||||
id: test_archs
|
||||
run: |
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
name: "PR video demo label"
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, edited, reopened, synchronize]
|
||||
|
||||
cache-mode: none
|
||||
permissions:
|
||||
pull-requests: write
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
video-demo-label:
|
||||
runs-on: ubuntu-slim
|
||||
steps:
|
||||
- name: Add or remove the video demo label
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
PR_URL: ${{ github.event.pull_request.html_url }}
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
# passed through env, so the body is only matched, never run, and is safe to read from a fork
|
||||
BODY: ${{ github.event.pull_request.body }}
|
||||
HAS_LABEL: ${{ contains(github.event.pull_request.labels.*.name, 'video demo') }}
|
||||
run: |
|
||||
# sections written by demo:pr (see tools/ui/demo/cli.ts): the managed comment
|
||||
# markers, or a preview linking to a demo video uploaded for this PR
|
||||
has_demo=false
|
||||
if { grep -qF '<!-- demo:start -->' <<< "$BODY" && grep -qF '<!-- demo:end -->' <<< "$BODY"; } ||
|
||||
grep -qE "/resolve/videos/pr/$PR_NUMBER/[0-9a-f]{10}(-[0-9]+)?\.mp4" <<< "$BODY"; then
|
||||
has_demo=true
|
||||
fi
|
||||
|
||||
if [ "$has_demo" = true ] && [ "$HAS_LABEL" = false ]; then
|
||||
gh pr edit "$PR_URL" --add-label 'video demo'
|
||||
elif [ "$has_demo" = false ] && [ "$HAS_LABEL" = true ]; then
|
||||
gh pr edit "$PR_URL" --remove-label 'video demo'
|
||||
fi
|
||||
@@ -24,7 +24,7 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
python-check-requirements:
|
||||
runs-on: ${{ 'ubuntu-24.04-arm' || 'ubuntu-24.04' }}
|
||||
runs-on: ${{ 'ubuntu-26.04-arm' || 'ubuntu-26.04' }}
|
||||
name: check-requirements
|
||||
steps:
|
||||
- name: Check out source repository
|
||||
|
||||
@@ -171,14 +171,14 @@ jobs:
|
||||
**Linux:**
|
||||
- [Ubuntu x64 (CPU)](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/llama-${{ steps.tag.outputs.name }}-bin-ubuntu-x64.tar.gz)
|
||||
- [Ubuntu arm64 (CPU)](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/llama-${{ steps.tag.outputs.name }}-bin-ubuntu-arm64.tar.gz)
|
||||
- [Ubuntu s390x (CPU)](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/llama-${{ steps.tag.outputs.name }}-bin-ubuntu-s390x.tar.gz)
|
||||
- [Ubuntu 24.04 s390x (CPU)](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/llama-${{ steps.tag.outputs.name }}-bin-ubuntu-s390x.tar.gz)
|
||||
- [Ubuntu 26.04 s390x (CPU)](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/llama-${{ steps.tag.outputs.name }}-bin-ubuntu-26.04-s390x.tar.gz)
|
||||
- [Ubuntu 26.04 s390x (zDNN)](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/llama-${{ steps.tag.outputs.name }}-bin-ubuntu-zdnn-s390x.tar.gz)
|
||||
- [Ubuntu x64 (Vulkan)](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/llama-${{ steps.tag.outputs.name }}-bin-ubuntu-vulkan-x64.tar.gz)
|
||||
- [Ubuntu arm64 (Vulkan)](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/llama-${{ steps.tag.outputs.name }}-bin-ubuntu-vulkan-arm64.tar.gz)
|
||||
- [Ubuntu x64 (CUDA 12)](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/llama-${{ steps.tag.outputs.name }}-bin-ubuntu-cuda-12.8-x64.tar.gz) - [CUDA 12.8 libraries](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/cudart-llama-${{ steps.tag.outputs.name }}-bin-ubuntu-cuda-12.8-x64.tar.gz)
|
||||
- [Ubuntu x64 (CUDA 13)](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/llama-${{ steps.tag.outputs.name }}-bin-ubuntu-cuda-13.4-x64.tar.gz) - [CUDA 13.4 libraries](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/cudart-llama-${{ steps.tag.outputs.name }}-bin-ubuntu-cuda-13.4-x64.tar.gz)
|
||||
- [Ubuntu arm64 (CUDA 13)](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/llama-${{ steps.tag.outputs.name }}-bin-ubuntu-cuda-13.4-arm64.tar.gz) - [CUDA 13.4 libraries](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/cudart-llama-${{ steps.tag.outputs.name }}-bin-ubuntu-cuda-13.4-arm64.tar.gz)
|
||||
- [Ubuntu x64 (CUDA 13)](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/llama-${{ steps.tag.outputs.name }}-bin-ubuntu-cuda-13.5-x64.tar.gz) - [CUDA 13.5 libraries](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/cudart-llama-${{ steps.tag.outputs.name }}-bin-ubuntu-cuda-13.5-x64.tar.gz)
|
||||
- [Ubuntu arm64 (CUDA 13)](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/llama-${{ steps.tag.outputs.name }}-bin-ubuntu-cuda-13.5-arm64.tar.gz) - [CUDA 13.5 libraries](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/cudart-llama-${{ steps.tag.outputs.name }}-bin-ubuntu-cuda-13.5-arm64.tar.gz)
|
||||
- [Ubuntu x64 (ROCm 10.0)](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/llama-${{ steps.tag.outputs.name }}-bin-ubuntu-rocm-10.0-x64.tar.gz)
|
||||
- [Ubuntu x64 (OpenVINO)](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/llama-${{ steps.tag.outputs.name }}-bin-ubuntu-openvino-2026.4.1-x64.tar.gz)
|
||||
- [Ubuntu x64 (SYCL FP32)](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/llama-${{ steps.tag.outputs.name }}-bin-ubuntu-sycl-fp32-x64.tar.gz)
|
||||
@@ -194,8 +194,8 @@ jobs:
|
||||
- [Windows arm64 (CPU)](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/llama-${{ steps.tag.outputs.name }}-bin-win-cpu-arm64.zip)
|
||||
- [Windows arm64 (OpenCL Adreno)](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/llama-${{ steps.tag.outputs.name }}-bin-win-opencl-adreno-arm64.zip)
|
||||
- [Windows x64 (CUDA 12)](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/llama-${{ steps.tag.outputs.name }}-bin-win-cuda-12.4-x64.zip) - [CUDA 12.4 DLLs](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/cudart-llama-bin-win-cuda-12.4-x64.zip)
|
||||
- [Windows x64 (CUDA 13)](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/llama-${{ steps.tag.outputs.name }}-bin-win-cuda-13.4-x64.zip) - [CUDA 13.4 DLLs](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/cudart-llama-bin-win-cuda-13.4-x64.zip)
|
||||
- [Windows arm64 (CUDA 13)](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/llama-${{ steps.tag.outputs.name }}-bin-win-cuda-13.4-arm64.zip) - [CUDA 13.4 DLLs](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/cudart-llama-bin-win-cuda-13.4-arm64.zip)
|
||||
- [Windows x64 (CUDA 13)](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/llama-${{ steps.tag.outputs.name }}-bin-win-cuda-13.5-x64.zip) - [CUDA 13.5 DLLs](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/cudart-llama-bin-win-cuda-13.5-x64.zip)
|
||||
- [Windows arm64 (CUDA 13)](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/llama-${{ steps.tag.outputs.name }}-bin-win-cuda-13.5-arm64.zip) - [CUDA 13.5 DLLs](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/cudart-llama-bin-win-cuda-13.5-arm64.zip)
|
||||
- [Windows x64 (Vulkan)](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/llama-${{ steps.tag.outputs.name }}-bin-win-vulkan-x64.zip)
|
||||
- [Windows arm64 (Vulkan)](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/llama-${{ steps.tag.outputs.name }}-bin-win-vulkan-arm64.zip)
|
||||
- [Windows x64 (OpenVINO)](https://github.com/ggml-org/llama.cpp/releases/download/${{ steps.tag.outputs.name }}/llama-${{ steps.tag.outputs.name }}-bin-win-openvino-2026.4.1-x64.zip)
|
||||
|
||||
@@ -345,14 +345,14 @@ jobs:
|
||||
defines: '-DGGML_CUDA_CCCL_VERSION=v3.4.3'
|
||||
- build: 'x64'
|
||||
os: ubuntu-24.04
|
||||
cuda: '13.4.1'
|
||||
label: '13.4'
|
||||
defines: '-DGGML_CUDA_CCCL_VERSION=v3.4.3'
|
||||
cuda: '13.5.0'
|
||||
label: '13.5'
|
||||
defines: ''
|
||||
- build: 'arm64'
|
||||
os: ubuntu-24.04-arm
|
||||
cuda: '13.4.1'
|
||||
label: '13.4'
|
||||
defines: '-DGGML_CUDA_CCCL_VERSION=v3.4.3'
|
||||
cuda: '13.5.0'
|
||||
label: '13.5'
|
||||
defines: ''
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
container: nvidia/cuda:${{ matrix.cuda }}-devel-ubuntu24.04
|
||||
@@ -463,7 +463,7 @@ jobs:
|
||||
needs: [check-release, ui-build]
|
||||
if: ${{ needs.check-release.outputs.should_release == 'true' }}
|
||||
|
||||
runs-on: ubuntu-24.04 # previously ubuntu-latest
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
env:
|
||||
NDK_VERSION: "29.0.14206865"
|
||||
@@ -548,7 +548,7 @@ jobs:
|
||||
needs: [check-release, ui-build]
|
||||
if: ${{ needs.check-release.outputs.should_release == 'true' }}
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-24.04
|
||||
container: 'ghcr.io/snapdragon-toolchain/arm64-android:v0.8'
|
||||
|
||||
defaults:
|
||||
@@ -601,7 +601,7 @@ jobs:
|
||||
needs: [check-release, ui-build]
|
||||
if: ${{ needs.check-release.outputs.should_release == 'true' }}
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-24.04
|
||||
container: 'ghcr.io/snapdragon-toolchain/arm64-linux:v0.8'
|
||||
|
||||
defaults:
|
||||
@@ -1211,12 +1211,12 @@ jobs:
|
||||
- cuda: '12.4'
|
||||
arch: x64
|
||||
defines: '-DGGML_CUDA_CCCL_VERSION=v3.4.3'
|
||||
- cuda: '13.4'
|
||||
- cuda: '13.5'
|
||||
arch: x64
|
||||
defines: '-DGGML_CUDA_CCCL_VERSION=v3.4.3'
|
||||
- cuda: '13.4'
|
||||
defines: ''
|
||||
- cuda: '13.5'
|
||||
arch: arm64
|
||||
defines: '-DGGML_CUDA_CCCL_VERSION=v3.4.3 -DCMAKE_TOOLCHAIN_FILE=cmake/arm64-windows-msvc-cuda.cmake'
|
||||
defines: '-DCMAKE_TOOLCHAIN_FILE=cmake/arm64-windows-msvc-cuda.cmake'
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
|
||||
@@ -59,7 +59,7 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
ubuntu:
|
||||
runs-on: ubuntu-24.04-arm
|
||||
runs-on: ubuntu-26.04-arm
|
||||
|
||||
steps:
|
||||
- name: Dependencies
|
||||
@@ -94,7 +94,7 @@ jobs:
|
||||
env:
|
||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CI }}
|
||||
with:
|
||||
key: server-ubuntu-24.04-arm
|
||||
key: server-ubuntu-26.04-arm
|
||||
folder: llama.cpp
|
||||
hf_bucket: ggml-org/cache
|
||||
|
||||
@@ -111,7 +111,7 @@ jobs:
|
||||
env:
|
||||
HF_TOKEN: ${{ secrets.HF_TOKEN_CACHE_OUTPUT }}
|
||||
with:
|
||||
key: server-ubuntu-24.04-arm
|
||||
key: server-ubuntu-26.04-arm
|
||||
folder: llama.cpp
|
||||
evict-old-files: 1d
|
||||
hf_bucket: ggml-org/cache
|
||||
|
||||
@@ -12,7 +12,7 @@ permissions:
|
||||
jobs:
|
||||
update:
|
||||
name: Update Winget Package
|
||||
runs-on: ubuntu-24.04 # previously ubuntu-latest
|
||||
runs-on: ubuntu-26.04
|
||||
if: github.repository_owner == 'ggml-org'
|
||||
|
||||
steps:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# date: Wed Oct 28 12:38:26 EET 2026
|
||||
# date: Wed Nov 4 12:03:31 EET 2026
|
||||
# this file is auto-generated by scripts/gen-authors.sh
|
||||
|
||||
Нияз Гарифзянов <112617865+garrnizon@users.noreply.github.com>
|
||||
@@ -48,6 +48,7 @@ Abheek Gulati <abheekg@hotmail.com>
|
||||
abhijain1204fujitsu <139222713+abhijain1204fujitsu@users.noreply.github.com>
|
||||
Abhijit Ramesh <abhijitramesh2k@gmail.com>
|
||||
abhijitb11 <113058133+abhijitb11@users.noreply.github.com>
|
||||
Abhijith Jajam <129675815+jajamabhijith@users.noreply.github.com>
|
||||
Abhilash Majumder <30946547+abhilash1910@users.noreply.github.com>
|
||||
Abhinay Krishna <abhinaykrishna60@gmail.com>
|
||||
Abhiram <78226909+geckguy@users.noreply.github.com>
|
||||
@@ -203,14 +204,17 @@ Ankit Khandelwal <ankk98@gmail.com>
|
||||
Ankur Verma <31362771+ankurvdev@users.noreply.github.com>
|
||||
anon998 <131767832+anon998@users.noreply.github.com>
|
||||
Anri Lombard <anri.m.lombard@gmail.com>
|
||||
Anthony Maltsev <77708730+anthonymaltsev@users.noreply.github.com>
|
||||
Anthony Umfer <aumfer@gmail.com>
|
||||
Anthony Van de Gejuchte <anthonyvdgent@gmail.com>
|
||||
Anthony Wang <anthonywang903@gmail.com>
|
||||
antichristHater <142441588+antichristHater@users.noreply.github.com>
|
||||
Antoine Viallon <antoine@lesviallon.fr>
|
||||
Anton I <inflyer@hotmail.com>
|
||||
Anton Mitkov <anton_b_mitkov@abv.bg>
|
||||
Anton Mitkov <anton.mitkov@codeplay.com>
|
||||
Antonis Makropoulos <benuix@gmail.com>
|
||||
anubhavfujitsu <Anubhav.Srivastava@fujitsu.com>
|
||||
Anudit Nagar <nagaranudit@gmail.com>
|
||||
Anuj Attri <anujattri01@gmail.com>
|
||||
anujj <ajalota@nvidia.com>
|
||||
@@ -293,6 +297,7 @@ Bernat Vadell <hounter.caza@gmail.com>
|
||||
Bernhard M. Wiedemann <githubbmwprimary@lsmod.de>
|
||||
Bert Wagner <github@bertwagner.com>
|
||||
Bertay Eren <39909689+bertaye@users.noreply.github.com>
|
||||
Bhargav Krish <bkrishnamurt@nvidia.com>
|
||||
Bhavik Sharda <10757940+BLSharda@users.noreply.github.com>
|
||||
bhubbb <79117352+bhubbb@users.noreply.github.com>
|
||||
Bill Sideris <bill88t@feline.gr>
|
||||
@@ -533,6 +538,7 @@ Don Mahurin <dmahurin@users.noreply.github.com>
|
||||
Dong Won Kim <63934649+ddwkim@users.noreply.github.com>
|
||||
Donghyeon Jeong <54725479+djeong20@users.noreply.github.com>
|
||||
Dongliang Wei <121270393+wdl339@users.noreply.github.com>
|
||||
Dongsheng Luo <luods1995@outlook.com>
|
||||
Doomsdayrs <38189170+Doomsdayrs@users.noreply.github.com>
|
||||
DooWoong Lee (David) <manics99@naver.com>
|
||||
DorianRudolph <dorianrudo97@googlemail.com>
|
||||
@@ -612,6 +618,7 @@ Faez Shakil <faez.shakil@gmail.com>
|
||||
fairydreaming <166155368+fairydreaming@users.noreply.github.com>
|
||||
Faisal Zaghloul <faisal.zaghloul@gmail.com>
|
||||
Faisal Zaghloul <quic_fzaghlou@quicinc.com>
|
||||
FamousMonsterr <famousmonster@ya.ru>
|
||||
Fan Shupei <dymarkfan@outlook.com>
|
||||
FantasyGmm <16450052+FantasyGmm@users.noreply.github.com>
|
||||
fanyang <fanyang89@outlook.com>
|
||||
@@ -654,6 +661,7 @@ Frederik Vogel <Schaltfehler@users.noreply.github.com>
|
||||
Fredrik Hultin <noname@nurd.se>
|
||||
fredzillman <fzillman@gmail.com>
|
||||
frob <rick+github@frob.com.au>
|
||||
frogscooper <frogscooper@gmail.com>
|
||||
Frost-54 <91168148+Frost-54@users.noreply.github.com>
|
||||
Frosty40 <newjordan@gmail.com>
|
||||
Funtowicz Morgan <mfuntowicz@users.noreply.github.com>
|
||||
@@ -694,6 +702,7 @@ Gilad S. <7817232+giladgd@users.noreply.github.com>
|
||||
Giovanni Rivera <rivera.giovanni271@gmail.com>
|
||||
github-actions[bot] <github-actions[bot]@users.noreply.github.com>
|
||||
GittyBurstein <g0534163997@gmail.com>
|
||||
Giulianno <lernexbusiness@gmail.com>
|
||||
Giuseppe Scrivano <giuseppe@scrivano.org>
|
||||
Giuseppe Scrivano <gscrivan@redhat.com>
|
||||
GiviMAD <GiviMAD@users.noreply.github.com>
|
||||
@@ -762,6 +771,7 @@ Henry147147 <44851451+Henry147147@users.noreply.github.com>
|
||||
Herman Semenoff <GermanAizek@yandex.ru>
|
||||
Herman Semenov <GermanAizek@yandex.ru>
|
||||
Hesen Peng <hesen.peng@gmail.com>
|
||||
hesiru <siruhe666@gmail.com>
|
||||
hey-gm <heitorgm@outlook.com>
|
||||
HighDoping <highdoping@gmail.com>
|
||||
HimariO <dsfhe49854@gmail.com>
|
||||
@@ -919,6 +929,7 @@ Jesse Ikonen <jesse.ikonen@gmail.com>
|
||||
Jesse Jojo Johnson <williamsaintgeorge@gmail.com>
|
||||
Jesse LaRose <jesse@taey.ai>
|
||||
Jesse Posner <jesse.posner@gmail.com>
|
||||
Jesse Symons <155509533+Torchit1@users.noreply.github.com>
|
||||
Jesus Gulfo <jesdga95@gmail.com>
|
||||
Jesus Talavera <145992175+jesus-talavera-ibm@users.noreply.github.com>
|
||||
Jetson Tan <tanzongyouyi@outlook.com>
|
||||
@@ -1071,6 +1082,7 @@ Kevin Liu <4396kevinliu@gmail.com>
|
||||
Kevin Lo <kevlo@kevlo.org>
|
||||
Kevin Pouget <kpouget@redhat.com>
|
||||
Kevin Wang <kevmo314@gmail.com>
|
||||
Keyu Zhu <inuebisu@outlook.com>
|
||||
Khashayar Ghafouri <43180261+khashayarghafouri@users.noreply.github.com>
|
||||
khimaros <me@khimaros.com>
|
||||
Kilian Hu <90606809+kilian-hu@users.noreply.github.com>
|
||||
@@ -1078,6 +1090,7 @@ Kilian Krampf <kilian@krampf.de>
|
||||
kiltyj <kiltyj@gmail.com>
|
||||
Kim S. <polydecay@users.noreply.github.com>
|
||||
kimminsu <80271594+kimminsu38oo@users.noreply.github.com>
|
||||
Kirill A. Korinsky <kirill@korins.ky>
|
||||
KITAITI Makoto <KitaitiMakoto@gmail.com>
|
||||
kiwi <122582483+kiwi142857@users.noreply.github.com>
|
||||
klosax <131523366+klosax@users.noreply.github.com>
|
||||
@@ -1136,6 +1149,7 @@ leejet <leejet714@gmail.com>
|
||||
Leng Yue <lengyue@lengyue.me>
|
||||
Lennart Austenfeld <53152202+l-austenfeld@users.noreply.github.com>
|
||||
leo-pony <nengjunma@outlook.com>
|
||||
Leon <118652405+LeON-Nie-code@users.noreply.github.com>
|
||||
Leon Knauer <git@leonknauer.com>
|
||||
Leonard Mosescu <tlemo@users.noreply.github.com>
|
||||
leonardHONG <2695316095@qq.com>
|
||||
@@ -1146,8 +1160,10 @@ lexasub <lexakopp2212@gmail.com>
|
||||
lgai-exaone <exaonemodels@lgresearch.ai>
|
||||
lhez <lih@qti.qualcomm.com>
|
||||
lhez <quic_lih@quicinc.com>
|
||||
Li Chuyang <1418587903@qq.com>
|
||||
Li Pengzhan <151381994+Lpzhan931@users.noreply.github.com>
|
||||
Li Tan <tanliboy@gmail.com>
|
||||
li-lizhe <82501526+li-lizhe@users.noreply.github.com>
|
||||
liangliangchang <lichang@amd.com>
|
||||
liminfei-amd <91481003+liminfei-amd@users.noreply.github.com>
|
||||
limitedAtonement <limitedAtonement@users.noreply.github.com>
|
||||
@@ -1166,6 +1182,7 @@ LoganDark <github@logandark.mozmail.com>
|
||||
Loïc Carrère <loic.carrere@gmail.com>
|
||||
lon <114724657+longregen@users.noreply.github.com>
|
||||
loonerin <132926317+loonerin@users.noreply.github.com>
|
||||
Lorenzo Bona <lorenzobona@tuta.com>
|
||||
losewayy <1134285612@qq.com>
|
||||
LostRuins <39025047+LostRuins@users.noreply.github.com>
|
||||
LostRuins Concedo <39025047+LostRuins@users.noreply.github.com>
|
||||
@@ -1253,6 +1270,7 @@ Masaya, Kato <62578291+msy-kato@users.noreply.github.com>
|
||||
mashdragon <122402293+mashdragon@users.noreply.github.com>
|
||||
Mason Milburn <masonmilby@gmail.com>
|
||||
MasterYi1024 <39848311+MasterYi1024@users.noreply.github.com>
|
||||
Maternion <98753158+maternion@users.noreply.github.com>
|
||||
Mateusz Charytoniuk <mateusz.charytoniuk@protonmail.com>
|
||||
Matheus C. França <matheus-catarino@hotmail.com>
|
||||
Matheus Gabriel Alves Silva <matheusgasource@gmail.com>
|
||||
@@ -1350,6 +1368,7 @@ Miwa / Ensan <63481257+ensan-hcl@users.noreply.github.com>
|
||||
miyan <1138989048@qq.com>
|
||||
mj-shifu <77107165+mj-shifu@users.noreply.github.com>
|
||||
mkoker <132301062+mkoker@users.noreply.github.com>
|
||||
mmalpe-nv <mmalpe@nvidia.com>
|
||||
mmyjona <jonathan.gonse@gmail.com>
|
||||
mnehete32 <33429707+mnehete32@users.noreply.github.com>
|
||||
Mohamed Elashri <git@elashri.com>
|
||||
@@ -1368,6 +1387,7 @@ mtmcp <141645996+mtmcp@users.noreply.github.com>
|
||||
muggle-stack <promuggle@qq.com>
|
||||
Muhammad Saad <saadydev@gmail.com>
|
||||
Muhammad Salem <salem.ebo@gmail.com>
|
||||
MuoDoo <36472129+MuoDoo@users.noreply.github.com>
|
||||
Murilo Santana <mvrilo@gmail.com>
|
||||
Musab Gultekin <musabgultekin@users.noreply.github.com>
|
||||
musoles <135031143+musoles@users.noreply.github.com>
|
||||
@@ -1416,10 +1436,12 @@ Nicolas Budyn <16596345+nbud@users.noreply.github.com>
|
||||
Nicolas Mowen <nickmowen213@gmail.com>
|
||||
Nicolás Pérez <nicolas_perez@brown.edu>
|
||||
Nicolò Scipione <nicolo.scipione@codeplay.com>
|
||||
Nidhi <nidhisharma16635@gmail.com>
|
||||
Nigel Bosch <pnigelb@gmail.com>
|
||||
Nigel Jones <nigel.l.jones+git@gmail.com>
|
||||
Nik Bogatyrev <50734723+notforu777@users.noreply.github.com>
|
||||
Nikhil Jain <nikhil.jain0987@gmail.com>
|
||||
Nikhil Sharma <150424968+nikhilfujitsu@users.noreply.github.com>
|
||||
Nikita Gordeev <iamfobey@gmail.com>
|
||||
Nikita Sarychev <42014488+sARY77@users.noreply.github.com>
|
||||
Niklas Korz <niklas@niklaskorz.de>
|
||||
@@ -1592,6 +1614,7 @@ Raman Shinde <raman.shinde15@gmail.com>
|
||||
Rand Xie <randxiexyy29@gmail.com>
|
||||
Randall Fitzgerald <randall@dasaku.net>
|
||||
Random Fly <renfei8@live.cn>
|
||||
randomized <286843573@qq.com>
|
||||
rankaiyx <rankaiyx@foxmail.com>
|
||||
rankaiyx <rankaiyx@rankaiyx.com>
|
||||
RapidMark <32768622+RapidMark@users.noreply.github.com>
|
||||
@@ -2009,6 +2032,7 @@ Tungsten842 <quantmint@protonmail.com>
|
||||
Tushar <ditsuke@protonmail.com>
|
||||
tv1wnd <55383215+tv1wnd@users.noreply.github.com>
|
||||
tyronecai <tyronecai@163.com>
|
||||
Uber <20715993+YagUber@users.noreply.github.com>
|
||||
ubergarm <leimgrub@gmail.com>
|
||||
ubik2 <ubik2@users.noreply.github.com>
|
||||
UEXTM.com <84163508+uextm@users.noreply.github.com>
|
||||
@@ -2242,4 +2266,5 @@ Zijun Yu <zijun.yu@intel.com>
|
||||
zql <37731799+zqlcode@users.noreply.github.com>
|
||||
zrm <trustiosity.zrm@gmail.com>
|
||||
Zsapi <martin1.zsapka@gmail.com>
|
||||
zyang-dev <267119621+zyang-dev@users.noreply.github.com>
|
||||
zzzzwc <tiddar@foxmail.com>
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ include(CheckIncludeFileCXX)
|
||||
|
||||
### llama.cpp version
|
||||
set(LLAMA_VERSION_MAJOR 0)
|
||||
set(LLAMA_VERSION_MINOR 8)
|
||||
set(LLAMA_VERSION_MINOR 9)
|
||||
set(LLAMA_VERSION_PATCH 0)
|
||||
set(LLAMA_VERSION_BASE "${LLAMA_VERSION_MAJOR}.${LLAMA_VERSION_MINOR}.${LLAMA_VERSION_PATCH}")
|
||||
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
/src/llama-graph.* @CISC
|
||||
/src/llama-model.* @CISC
|
||||
/src/llama-vocab.* @CISC
|
||||
/src/llama-moe-cache.* @am17an
|
||||
/src/models/ @ggml-org/llama-models
|
||||
/tests/ @ggerganov
|
||||
/tests/test-chat.* @pwilkin
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
[](https://github.com/ggml-org/llama.cpp/actions/workflows/docker.yml)
|
||||
[](https://github.com/ggml-org/llama.cpp/actions/workflows/winget.yml)
|
||||
|
||||
[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%3Asanmai%20OR%20author%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%3Ajhen0409%20OR%20author%3Abartowski1182%20OR%20author%3Anikwen%20OR%20author%3Ahipudding%20OR%20author%3Aravi9%20OR%20author%3AServeurpersoCom%20OR%20author%3Athelittlefireman%20OR%20author%3Apwilkin%20OR%20author%3Areeselevine%20OR%20author%3Angxson%20OR%20author%3Ajeffbolznv%20OR%20author%3Amarty1885%20OR%20author%3A0cc4m%20OR%20author%3ATitaniumtown%20OR%20author%3Aangt%20OR%20author%3AIMbackK%20OR%20author%3Aarthw%20OR%20author%3AJohannesGaessler%20OR%20author%3AORippler%20OR%20author%3Aruixiang63%20OR%20author%3Axctan%20OR%20author%3AmasterFoad%20OR%20author%3Aallozaur%20OR%20author%3AAndreas-Krebbel%20OR%20author%3Ayomaytk%20OR%20author%3Aaendk%20OR%20author%3Awine99%20OR%20author%3Agaugarg-nv%20OR%20author%3Ataronaeo%20OR%20author%3Aforforever73%20OR%20author%3Achaxu01%20OR%20author%3Alhez%20OR%20author%3AAlekseiNikiforovIBM%20OR%20author%3Anetrunnereve%20OR%20author%3Afairydreaming%20OR%20author%3Aynankani)%20sort%3Aupdated-desc) / [dev stats](https://github.com/ggml-org/llama.cpp-dev) / [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)
|
||||
[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/pulls?q=is%3Apr%20is%3Aopen%20draft%3AFalse%20(author%3Asanmai%20OR%20author%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%3Ajhen0409%20OR%20author%3Abartowski1182%20OR%20author%3Anikwen%20OR%20author%3Ahipudding%20OR%20author%3Aravi9%20OR%20author%3AServeurpersoCom%20OR%20author%3Athelittlefireman%20OR%20author%3Apwilkin%20OR%20author%3Areeselevine%20OR%20author%3Angxson%20OR%20author%3Ajeffbolznv%20OR%20author%3Amarty1885%20OR%20author%3A0cc4m%20OR%20author%3ATitaniumtown%20OR%20author%3Aangt%20OR%20author%3AIMbackK%20OR%20author%3Aarthw%20OR%20author%3AJohannesGaessler%20OR%20author%3AORippler%20OR%20author%3Aruixiang63%20OR%20author%3Axctan%20OR%20author%3AmasterFoad%20OR%20author%3Aallozaur%20OR%20author%3AAndreas-Krebbel%20OR%20author%3Ayomaytk%20OR%20author%3Aaendk%20OR%20author%3Awine99%20OR%20author%3Agaugarg-nv%20OR%20author%3Ataronaeo%20OR%20author%3Aforforever73%20OR%20author%3Achaxu01%20OR%20author%3Alhez%20OR%20author%3AAlekseiNikiforovIBM%20OR%20author%3Anetrunnereve%20OR%20author%3Afairydreaming%20OR%20author%3Aynankani)%20sort%3Aupdated-desc) / [dev stats](https://github.com/ggml-org/llama.cpp-dev) / [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>
|
||||
|
||||
|
||||
@@ -296,25 +296,6 @@ function gg_run_test_llama_archs_tensor_split {
|
||||
set +e
|
||||
}
|
||||
|
||||
# test_llama_archs_models
|
||||
|
||||
function gg_run_test_llama_archs_models {
|
||||
cd ${SRC}
|
||||
|
||||
set -e
|
||||
|
||||
# TODO: fix and re-enable `test-llama-archs` on OpenVINO
|
||||
# TODO: the `test-llama-archs` currently does not build on Windows, so we check if the binary exists
|
||||
if [ -z ${GG_BUILD_OPENVINO} ] && [ -f ./build-ci-release/bin/test-llama-archs ]; then
|
||||
rm -rf build-ci-models && mkdir -p build-ci-models
|
||||
|
||||
# generate the dummy models used by the model-dependent tests
|
||||
./build-ci-release/bin/test-llama-archs -o build-ci-models 2>&1
|
||||
fi
|
||||
|
||||
set +e
|
||||
}
|
||||
|
||||
# test_scripts
|
||||
|
||||
function gg_run_test_scripts {
|
||||
@@ -456,12 +437,8 @@ function gg_run_qwen3_0_6b {
|
||||
|
||||
(time ./bin/llama-imatrix --model ${model_f16} -f ${wiki_test} -ngl 99 -c 1024 -b 512 --chunks 2 ) 2>&1 | tee -a $OUT/${ci}-imatrix.log
|
||||
|
||||
# TODO: these tests are extremely slow on WebGPU - re-enable when fixed
|
||||
# https://github.com/ggml-org/llama.cpp/actions/runs/39639985732
|
||||
if [ -z ${GG_BUILD_WEBGPU} ]; then
|
||||
(time ./bin/test-llama-context --model ${model_q4_0} -ngl 10 -c 1024 -fa off --no-op-offload) 2>&1 | tee -a $OUT/${ci}-test-llama-context.log
|
||||
(time ./bin/test-llama-context --model ${model_q4_0} -ngl 99 -c 1024 -fa off ) 2>&1 | tee -a $OUT/${ci}-test-llama-context.log
|
||||
fi
|
||||
(time ./bin/test-llama-context --model ${model_q4_0} -ngl 10 -c 1024 -fa off --no-op-offload) 2>&1 | tee -a $OUT/${ci}-test-llama-context.log
|
||||
(time ./bin/test-llama-context --model ${model_q4_0} -ngl 99 -c 1024 -fa off ) 2>&1 | tee -a $OUT/${ci}-test-llama-context.log
|
||||
(time ./bin/test-llama-context --model ${model_q4_0} -ngl 10 -c 1024 -fa on --no-op-offload) 2>&1 | tee -a $OUT/${ci}-test-llama-context.log
|
||||
(time ./bin/test-llama-context --model ${model_q4_0} -ngl 99 -c 1024 -fa on ) 2>&1 | tee -a $OUT/${ci}-test-llama-context.log
|
||||
|
||||
@@ -701,7 +678,6 @@ test $ret -eq 0 && gg_run ctest_release
|
||||
|
||||
test $ret -eq 0 && gg_run test_backend_ops
|
||||
|
||||
test $ret -eq 0 && gg_run test_llama_archs_models
|
||||
test $ret -eq 0 && gg_run test_llama_archs_tensor_split
|
||||
|
||||
if [ -z ${GG_BUILD_LOW_PERF} ]; then
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ if(WIN32)
|
||||
endif()
|
||||
enable_language(RC)
|
||||
set(LLAMA_WIN_APP_MANIFEST_RC "${CMAKE_CURRENT_BINARY_DIR}/win-app-manifest.rc")
|
||||
configure_file("${CMAKE_CURRENT_LIST_DIR}/win-app.rc.in" "${LLAMA_WIN_APP_MANIFEST_RC}" @ONLY)
|
||||
file(CONFIGURE OUTPUT "${LLAMA_WIN_APP_MANIFEST_RC}" CONTENT "1 24 \"@LLAMA_WIN_APP_MANIFEST@\"\n" @ONLY)
|
||||
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${LLAMA_WIN_APP_MANIFEST}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
// generated from cmake/win-app.rc.in - do not edit
|
||||
// RT_MANIFEST (24), ID 1: the application manifest shared by all llama.cpp executables
|
||||
1 24 "@LLAMA_WIN_APP_MANIFEST@"
|
||||
+34
-3
@@ -4,6 +4,7 @@
|
||||
#include "chat.h"
|
||||
#include "common.h"
|
||||
#include "download.h"
|
||||
#include "http.h"
|
||||
#include "json-schema-to-grammar.h"
|
||||
#include "json.h"
|
||||
#include "llama.h"
|
||||
@@ -399,7 +400,26 @@ bool common_models_handler_is_preset_repo(const common_models_handler & handler)
|
||||
return !handler.plan.preset.url.empty();
|
||||
}
|
||||
|
||||
static common_download_opts download_opts_for_url(const common_download_opts & opts, const std::string & url) {
|
||||
common_download_opts result = opts;
|
||||
try {
|
||||
const auto hf = common_http_parse_url(common_get_model_endpoint());
|
||||
const auto parts = common_http_parse_url(url);
|
||||
|
||||
if (parts.scheme == hf.scheme &&
|
||||
parts.host == hf.host &&
|
||||
parts.port == hf.port &&
|
||||
string_starts_with(result.bearer_token, "hf_")) {
|
||||
return result;
|
||||
}
|
||||
} catch (const std::exception &) {
|
||||
}
|
||||
result.bearer_token.clear();
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::vector<common_download_task> build_url_tasks(const common_params_model & model, common_download_opts opts) {
|
||||
opts = download_opts_for_url(opts, model.url);
|
||||
auto parts = common_download_get_all_parts(model.url);
|
||||
std::vector<common_download_task> tasks;
|
||||
|
||||
@@ -488,7 +508,7 @@ void common_models_handler_apply(common_models_handler & handler, common_params
|
||||
common_download_task task;
|
||||
task.url = params.mmproj.url;
|
||||
task.local_path = params.mmproj.path;
|
||||
task.opts = opts;
|
||||
task.opts = download_opts_for_url(opts, task.url);
|
||||
tasks.push_back(task);
|
||||
}
|
||||
bool had_spec_url = false;
|
||||
@@ -496,7 +516,7 @@ void common_models_handler_apply(common_models_handler & handler, common_params
|
||||
common_download_task task;
|
||||
task.url = params.speculative.draft.mparams.url;
|
||||
task.local_path = params.speculative.draft.mparams.path;
|
||||
task.opts = opts;
|
||||
task.opts = download_opts_for_url(opts, task.url);
|
||||
tasks.push_back(task);
|
||||
had_spec_url = true;
|
||||
}
|
||||
@@ -710,7 +730,7 @@ static void common_params_apply_system_config(common_params & params, llama_exam
|
||||
std::vector<std::filesystem::path> paths;
|
||||
|
||||
#if defined(_WIN32)
|
||||
const std::filesystem::path program_data = common_get_path_from_env("PROGRAMDATA");
|
||||
const std::filesystem::path program_data = common_get_env("PROGRAMDATA");
|
||||
if (!program_data.empty()) {
|
||||
paths.push_back(program_data / "llama.cpp" / "config.ini");
|
||||
}
|
||||
@@ -2734,6 +2754,17 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
|
||||
params.moe_cache_size = (size_t) value*1024*1024;
|
||||
}
|
||||
).set_env("LLAMA_ARG_MOE_CACHE_MIB"));
|
||||
add_opt(common_arg(
|
||||
{"--moe-cache-cpu-share"}, "F",
|
||||
string_format("share of the MoE cache misses that the CPU computes from the host experts instead of uploading them to the GPU once the cache is full, from 0 to 1 (default: %.2f)", (double) params.moe_cache_cpu_share),
|
||||
[](common_params & params, const std::string & value) {
|
||||
const float share = std::stof(value);
|
||||
if (share < 0.0f || share > 1.0f) {
|
||||
throw std::invalid_argument("invalid value");
|
||||
}
|
||||
params.moe_cache_cpu_share = share;
|
||||
}
|
||||
).set_env("LLAMA_ARG_MOE_CACHE_CPU_SHARE"));
|
||||
add_opt(common_arg(
|
||||
{"-ncffn", "--n-cpu-ffn"}, "N",
|
||||
"keep the dense FFN weights of the first N layers in the CPU\n"
|
||||
|
||||
@@ -348,7 +348,8 @@ void common_chat_peg_mapper::map(const common_peg_ast_node & node) {
|
||||
}
|
||||
|
||||
if (is_tool_id && current_tool) {
|
||||
auto text = trim_trailing_space(node.text);
|
||||
auto sanitized = node.sanitized_text();
|
||||
auto text = trim_trailing_space(sanitized);
|
||||
if (text.size() >= 2 && text.front() == '"' && text.back() == '"') {
|
||||
text = text.substr(1, text.size() - 2);
|
||||
}
|
||||
@@ -401,7 +402,7 @@ void common_chat_peg_mapper::map(const common_peg_ast_node & node) {
|
||||
}
|
||||
|
||||
if ((is_arg_value || is_arg_string_value) && current_tool) {
|
||||
std::string value_content = std::string(node.text);
|
||||
std::string value_content = node.sanitized_text();
|
||||
|
||||
std::string value_to_add;
|
||||
if (value_content.empty() && is_arg_string_value) {
|
||||
@@ -978,7 +979,7 @@ static std::string gemma4_to_json(const common_peg_ast_arena & arena, common_peg
|
||||
}
|
||||
|
||||
if (node.rule == "gemma4-string-content") {
|
||||
return escape_json_string_inner(std::string(node.text));
|
||||
return escape_json_string_inner(node.sanitized_text());
|
||||
}
|
||||
|
||||
if (node.rule == "gemma4-string") {
|
||||
@@ -1195,7 +1196,7 @@ static std::string minimax_m3_value_to_json(const common_peg_ast_arena & arena,
|
||||
}
|
||||
|
||||
if (node.tag == common_chat_peg_builder::TOOL_ARG_STRING_VALUE) {
|
||||
return "\"" + escape_json_string_inner(std::string(node.text)) + (closed ? "\"" : "");
|
||||
return "\"" + escape_json_string_inner(node.sanitized_text()) + (closed ? "\"" : "");
|
||||
}
|
||||
|
||||
// Numbers and booleans are written verbatim by the template
|
||||
|
||||
+31
-39
@@ -895,27 +895,7 @@ bool fs_validate_filename(const std::string & filename, bool allow_subdirs) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
std::wstring utf8_to_wstring(const std::string & str) {
|
||||
if (str.empty()) {
|
||||
return std::wstring();
|
||||
}
|
||||
|
||||
int size = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int)str.size(), NULL, 0);
|
||||
|
||||
if (size <= 0) {
|
||||
return std::wstring();
|
||||
}
|
||||
|
||||
std::wstring wstr(size, 0);
|
||||
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int)str.size(), &wstr[0], size);
|
||||
|
||||
return wstr;
|
||||
}
|
||||
|
||||
std::string wstring_to_utf8(const std::wstring & str) {
|
||||
if (str.empty()) {
|
||||
return std::string();
|
||||
@@ -983,20 +963,9 @@ void common_set_env(const std::string & name, const std::string & value) {
|
||||
#endif
|
||||
}
|
||||
|
||||
std::filesystem::path common_get_path_from_env(const std::string & name) {
|
||||
#if defined(_WIN32)
|
||||
const std::wstring wname = utf8_to_wstring(name);
|
||||
const wchar_t * wvalue = _wgetenv(wname.c_str());
|
||||
return wvalue ? std::filesystem::path(wvalue) : std::filesystem::path();
|
||||
#else
|
||||
const char * value = std::getenv(name.c_str());
|
||||
return value ? std::filesystem::path(value) : std::filesystem::path();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined(_WIN32)
|
||||
static std::filesystem::path get_home_directory() {
|
||||
std::filesystem::path home = common_get_path_from_env("HOME");
|
||||
std::filesystem::path home = common_get_env("HOME");
|
||||
if (!home.empty()) {
|
||||
return home;
|
||||
}
|
||||
@@ -1009,19 +978,19 @@ static std::filesystem::path get_home_directory() {
|
||||
#endif
|
||||
|
||||
std::filesystem::path fs_get_cache_directory() {
|
||||
std::filesystem::path cache_directory = common_get_path_from_env("LLAMA_CACHE");
|
||||
std::filesystem::path cache_directory = common_get_env("LLAMA_CACHE");
|
||||
if (!cache_directory.empty()) {
|
||||
return cache_directory;
|
||||
}
|
||||
#if defined(_WIN32)
|
||||
cache_directory = common_get_path_from_env("LOCALAPPDATA");
|
||||
cache_directory = common_get_env("LOCALAPPDATA");
|
||||
if (cache_directory.empty()) {
|
||||
throw std::runtime_error("Failed to find %LOCALAPPDATA% directory");
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
cache_directory = get_home_directory() / "Library/Caches";
|
||||
#else
|
||||
cache_directory = common_get_path_from_env("XDG_CACHE_HOME");
|
||||
cache_directory = common_get_env("XDG_CACHE_HOME");
|
||||
if (cache_directory.empty()) {
|
||||
cache_directory = get_home_directory() / ".cache";
|
||||
}
|
||||
@@ -1032,12 +1001,12 @@ std::filesystem::path fs_get_cache_directory() {
|
||||
std::filesystem::path fs_get_config_directory() {
|
||||
std::filesystem::path config_directory;
|
||||
#if defined(_WIN32)
|
||||
config_directory = common_get_path_from_env("APPDATA");
|
||||
config_directory = common_get_env("APPDATA");
|
||||
if (config_directory.empty()) {
|
||||
throw std::runtime_error("Failed to find %APPDATA% directory");
|
||||
}
|
||||
#else
|
||||
config_directory = common_get_path_from_env("XDG_CONFIG_HOME");
|
||||
config_directory = common_get_env("XDG_CONFIG_HOME");
|
||||
if (config_directory.empty()) {
|
||||
config_directory = get_home_directory() / ".config";
|
||||
}
|
||||
@@ -1053,7 +1022,7 @@ std::filesystem::path fs_get_cache_file(const std::string & filename) {
|
||||
if (ec) {
|
||||
throw std::runtime_error("failed to create cache directory: " + cache_directory.string());
|
||||
}
|
||||
return cache_directory / std::filesystem::u8path(filename);
|
||||
return cache_directory / filename;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -1344,6 +1313,12 @@ common_init_result::common_init_result(common_params & params, bool model_only)
|
||||
LOG_INF("%s", "decision model reads the embeddings output, enabling embedding mode\n");
|
||||
}
|
||||
|
||||
if (llama_model_classifier_free_guidance(model)) {
|
||||
params.kv_unified = true;
|
||||
cparams.kv_unified = true;
|
||||
cparams.n_seq_max *= 2;
|
||||
}
|
||||
|
||||
// embeddings need the whole batch in one ubatch, so n_batch must not be larger than n_ubatch
|
||||
// (server.cpp does this check for --embedding, but before the model is loaded)
|
||||
if (cparams.embeddings && cparams.n_batch > cparams.n_ubatch) {
|
||||
@@ -1783,7 +1758,8 @@ struct llama_context_params common_context_params_to_llama(const common_params &
|
||||
cparams.type_k = params.cache_type_k;
|
||||
cparams.type_v = params.cache_type_v;
|
||||
|
||||
cparams.moe_cache_size = params.moe_cache_size;
|
||||
cparams.moe_cache_size = params.moe_cache_size;
|
||||
cparams.moe_cache_cpu_share = params.moe_cache_cpu_share;
|
||||
|
||||
return cparams;
|
||||
}
|
||||
@@ -2275,6 +2251,16 @@ int32_t common_batch::add_embd(llama_embd embd, const llama_pos * pos, llama_seq
|
||||
return size() - 1;
|
||||
}
|
||||
|
||||
int32_t common_batch::add_embd_row(int32_t row, const llama_pos * pos, llama_seq_id seq_id, bool output) {
|
||||
token t = { LLAMA_TOKEN_NULL, { 0, 0, 0, 0 }, seq_id, output, { nullptr, 0, 0 }, { nullptr, 0, 0 }, {} };
|
||||
t.embd_row = row;
|
||||
for (int32_t j = 0; j < n_pos; ++j) {
|
||||
t.pos[j] = pos[j];
|
||||
}
|
||||
tokens.push_back(t);
|
||||
return size() - 1;
|
||||
}
|
||||
|
||||
llama_batch_ext * common_batch::get_sub_batch(int32_t off, int32_t n) {
|
||||
GGML_ASSERT(batch && "common_batch was not initialized with a context");
|
||||
GGML_ASSERT(off >= 0 && n >= 0 && off + n <= size());
|
||||
@@ -2295,6 +2281,12 @@ llama_batch_ext * common_batch::get_sub_batch(int32_t off, int32_t n) {
|
||||
if (t.embd.data && !llama_batch_ext_set_embd_token(res, idx, t.embd)) {
|
||||
GGML_ABORT("%s: failed to set the embedding of token %d at index %d\n", __func__, t.id, i);
|
||||
}
|
||||
} else if (t.embd_row >= 0) {
|
||||
idx = llama_batch_ext_add_embd_row(res, t.seq_id, t.embd_row);
|
||||
if (idx < 0) {
|
||||
GGML_ABORT("%s: failed to add embd row %d at index %d (error %d, n = %d)\n", __func__, t.embd_row, i, idx, n);
|
||||
}
|
||||
llama_batch_ext_set_pos(res, idx, t.pos.data());
|
||||
} else {
|
||||
idx = llama_batch_ext_add_embd(res, t.seq_id, t.embd);
|
||||
if (idx < 0) {
|
||||
|
||||
+24
-8
@@ -597,7 +597,8 @@ struct common_params {
|
||||
ggml_type cache_type_k = GGML_TYPE_F16; // KV cache data type for the K
|
||||
ggml_type cache_type_v = GGML_TYPE_F16; // KV cache data type for the V
|
||||
|
||||
size_t moe_cache_size = 0; // GPU cache size in bytes for the MoE experts kept in the CPU, split among the GPUs like the layers
|
||||
size_t moe_cache_size = 0; // GPU cache size in bytes for the MoE experts kept in the CPU, split among the GPUs like the layers
|
||||
float moe_cache_cpu_share = 0.0f; // share of the MoE cache misses computed on the CPU instead of uploaded
|
||||
|
||||
common_conversation_mode conversation_mode = COMMON_CONVERSATION_MODE_AUTO;
|
||||
|
||||
@@ -906,8 +907,7 @@ bool glob_match(const std::string & pattern, const std::string & str);
|
||||
//
|
||||
|
||||
#ifdef _WIN32
|
||||
std::wstring utf8_to_wstring(const std::string & str);
|
||||
std::string wstring_to_utf8(const std::wstring & str);
|
||||
std::string wstring_to_utf8(const std::wstring & str);
|
||||
#endif
|
||||
|
||||
//
|
||||
@@ -919,9 +919,6 @@ std::string wstring_to_utf8(const std::wstring & str);
|
||||
std::string common_get_env(const std::string & name);
|
||||
void common_set_env(const std::string & name, const std::string & value);
|
||||
|
||||
// reads a path from the environment, an unset variable gives an empty path
|
||||
std::filesystem::path common_get_path_from_env(const std::string & name);
|
||||
|
||||
//
|
||||
// Filesystem utils
|
||||
//
|
||||
@@ -1096,6 +1093,7 @@ struct common_batch {
|
||||
llama_embd state; // non-owning view of the data passed to set_embd_state(), data == NULL if none
|
||||
std::vector<llama_seq_id> seq_ids_extra; // see add_seq()
|
||||
int32_t decision_order = 0; // see llama_batch_ext_set_decision_order()
|
||||
int32_t embd_row = -1; // see add_embd_row(), -1 if none
|
||||
};
|
||||
|
||||
std::vector<token> tokens; // mirror of the entries, tokens[i] describes batch index i
|
||||
@@ -1138,6 +1136,10 @@ struct common_batch {
|
||||
// pos points to n_pos positions
|
||||
int32_t add_embd(llama_embd embd, const llama_pos * pos, llama_seq_id seq_id, bool output);
|
||||
|
||||
// add an entry whose embedding is row `row` of the layer input device buffer of the context's ctx_other
|
||||
// pos points to n_pos positions
|
||||
int32_t add_embd_row(int32_t row, const llama_pos * pos, llama_seq_id seq_id, bool output);
|
||||
|
||||
int32_t size() const { return (int32_t) tokens.size(); }
|
||||
};
|
||||
|
||||
@@ -1288,6 +1290,20 @@ enum ggml_opt_optimizer_type common_opt_get_optimizer(const char *);
|
||||
// prompt utils
|
||||
//
|
||||
|
||||
// leave default-inserted elements uninitialized; callers must fill them before use
|
||||
template <typename T>
|
||||
struct common_no_init_allocator : std::allocator<T> {
|
||||
template <typename U> struct rebind { using other = common_no_init_allocator<U>; };
|
||||
|
||||
common_no_init_allocator() = default;
|
||||
template <typename U> common_no_init_allocator(const common_no_init_allocator<U> &) {}
|
||||
|
||||
template <typename U> void construct(U * p) { ::new ((void *) p) U; }
|
||||
};
|
||||
|
||||
// sequence state data, filled by llama_state_seq_get_data_ext()
|
||||
using common_state_data = std::vector<uint8_t, common_no_init_allocator<uint8_t>>;
|
||||
|
||||
struct common_prompt_checkpoint {
|
||||
int64_t n_tokens;
|
||||
|
||||
@@ -1297,8 +1313,8 @@ struct common_prompt_checkpoint {
|
||||
llama_pos pos_min;
|
||||
llama_pos pos_max;
|
||||
|
||||
std::vector<uint8_t> data_tgt;
|
||||
std::vector<uint8_t> data_dft;
|
||||
common_state_data data_tgt;
|
||||
common_state_data data_dft;
|
||||
|
||||
// (optional) speculative-decoding implementation state stashed with the checkpoint
|
||||
// (e.g. eagle3's deferred-boundary g_embd row)
|
||||
|
||||
+6
-6
@@ -45,7 +45,7 @@ static const std::string PARTIAL_SUFFIX = ".downloadInProgress";
|
||||
|
||||
static void write_etag(const std::string & path, const std::string & etag) {
|
||||
const std::string etag_path = path + ".etag";
|
||||
fs_write_atomic(std::filesystem::u8path(etag_path), etag);
|
||||
fs_write_atomic(etag_path, etag);
|
||||
LOG_DBG("%s: file etag saved: %s\n", __func__, etag_path.c_str());
|
||||
}
|
||||
|
||||
@@ -293,8 +293,7 @@ static int common_download_file_single_online(const std::string & url,
|
||||
|
||||
// alt_path is the HF snapshot: the blob may have been moved there when symlinks are unavailable
|
||||
auto cache_hit = [&] {
|
||||
return std::filesystem::exists(std::filesystem::u8path(path)) ||
|
||||
(!alt_path.empty() && std::filesystem::exists(std::filesystem::u8path(alt_path)));
|
||||
return std::filesystem::exists(path) || (!alt_path.empty() && std::filesystem::exists(alt_path));
|
||||
};
|
||||
|
||||
if (skip_etag && cache_hit()) {
|
||||
@@ -511,7 +510,7 @@ int common_download_file_single(const std::string & url,
|
||||
return common_download_file_single_online(url, path, online_opts, skip_etag, lock_path, alt_path);
|
||||
}
|
||||
|
||||
if (!std::filesystem::exists(std::filesystem::u8path(path))) {
|
||||
if (!std::filesystem::exists(path)) {
|
||||
LOG_ERR("%s: required file is not available in cache (offline mode): %s\n", __func__, path.c_str());
|
||||
return -1;
|
||||
}
|
||||
@@ -748,7 +747,8 @@ static hf_cache::hf_file find_best_model(const hf_cache::hf_files & files,
|
||||
}
|
||||
|
||||
for (const auto & t : tags) {
|
||||
std::regex pattern(t + "[.-]", std::regex::icase);
|
||||
// match the tag as a full token, so ":F16" does not match a BF16 file
|
||||
std::regex pattern("(^|[-./])" + t + "[.-]", std::regex::icase);
|
||||
for (const auto & f : files) {
|
||||
if (gguf_filename_is_model(f.path) &&
|
||||
std::regex_search(f.path, pattern)) {
|
||||
@@ -1211,7 +1211,7 @@ bool common_download_remove_sidecars(const std::string & hf_repo_with_tag, const
|
||||
for (const auto & s : sidecars) {
|
||||
const auto & f = plan.*s.file;
|
||||
if (!f.local_path.empty()) {
|
||||
to_remove.emplace_back(std::filesystem::u8path(f.local_path));
|
||||
to_remove.emplace_back(f.local_path);
|
||||
}
|
||||
}
|
||||
if (to_remove.empty()) {
|
||||
|
||||
+29
-8
@@ -61,6 +61,7 @@ static std::vector<llama_device_memory_data> common_get_device_memory_data_impl(
|
||||
const llama_context_params * cparams,
|
||||
std::vector<ggml_backend_dev_t> & devs,
|
||||
uint32_t & hp_ngl,
|
||||
uint32_t & hp_ngl_skip,
|
||||
uint32_t & hp_n_ctx_train,
|
||||
uint32_t & hp_n_expert,
|
||||
ggml_log_level log_level) {
|
||||
@@ -152,6 +153,8 @@ static std::vector<llama_device_memory_data> common_get_device_memory_data_impl(
|
||||
if (mparams->load_mtp) {
|
||||
hp_ngl += llama_model_n_layer_nextn(model);
|
||||
}
|
||||
// without MTP the NextN layers hold no weights but the model loader still counts them for n_gpu_layers
|
||||
hp_ngl_skip = mparams->load_mtp ? 0 : llama_model_n_layer_nextn(model);
|
||||
hp_n_ctx_train = llama_model_n_ctx_train(model);
|
||||
hp_n_expert = llama_model_n_expert(model);
|
||||
|
||||
@@ -240,11 +243,12 @@ common_device_memory_data_vec common_get_device_memory_data(
|
||||
const llama_context_params * cparams,
|
||||
std::vector<ggml_backend_dev_t> & devs,
|
||||
uint32_t & hp_ngl,
|
||||
uint32_t & hp_ngl_skip,
|
||||
uint32_t & hp_n_ctx_train,
|
||||
uint32_t & hp_n_expert,
|
||||
ggml_log_level log_level) {
|
||||
std::vector<llama_device_memory_data> impl = common_get_device_memory_data_impl(
|
||||
path_model, mparams, cparams, devs, hp_ngl, hp_n_ctx_train, hp_n_expert, log_level);
|
||||
path_model, mparams, cparams, devs, hp_ngl, hp_ngl_skip, hp_n_ctx_train, hp_n_expert, log_level);
|
||||
|
||||
common_device_memory_data_vec ret(impl.size());
|
||||
for (size_t i = 0; i < impl.size(); i++) {
|
||||
@@ -270,6 +274,7 @@ static void common_params_fit_impl(
|
||||
|
||||
std::vector<ggml_backend_dev_t> devs;
|
||||
uint32_t hp_ngl = 0; // hparams.n_gpu_layers
|
||||
uint32_t hp_nsk = 0; // number of skipped NextN layers, counted by the model loader but not by hp_ngl
|
||||
uint32_t hp_nct = 0; // hparams.n_ctx_train
|
||||
uint32_t hp_nex = 0; // hparams.n_expert
|
||||
|
||||
@@ -291,6 +296,7 @@ static void common_params_fit_impl(
|
||||
if (dmds_extra.empty() || n_ctx_extra != cparams->n_ctx) {
|
||||
std::vector<ggml_backend_dev_t> devs_extra;
|
||||
uint32_t ngl_extra = 0;
|
||||
uint32_t nsk_extra = 0;
|
||||
uint32_t nct_extra = 0;
|
||||
uint32_t nex_extra = 0;
|
||||
|
||||
@@ -302,7 +308,7 @@ static void common_params_fit_impl(
|
||||
dmds_t measured;
|
||||
try {
|
||||
measured = common_get_device_memory_data_impl(
|
||||
extra->path_model, extra->mparams, extra->cparams, devs_extra, ngl_extra, nct_extra, nex_extra, log_level);
|
||||
extra->path_model, extra->mparams, extra->cparams, devs_extra, ngl_extra, nsk_extra, nct_extra, nex_extra, log_level);
|
||||
} catch (const std::runtime_error & e) {
|
||||
// the extra model is optional, fit the main model alone rather than giving up
|
||||
LOG_WRN("%s: failed to measure the memory of the extra model, fitting without it: %s\n", __func__, e.what());
|
||||
@@ -342,7 +348,7 @@ static void common_params_fit_impl(
|
||||
// step 1: get data for default parameters and check whether any changes are necessary in the first place
|
||||
|
||||
LOG_TRC("%s: getting device memory data for initial parameters:\n", __func__);
|
||||
dmds_t dmds_full = common_get_device_memory_data_impl(path_model, mparams, cparams, devs, hp_ngl, hp_nct, hp_nex, log_level);
|
||||
dmds_t dmds_full = common_get_device_memory_data_impl(path_model, mparams, cparams, devs, hp_ngl, hp_nsk, hp_nct, hp_nex, log_level);
|
||||
|
||||
// saturate instead of overflowing, this also preserves the UINT32_MAX sentinel of n_ctx_min:
|
||||
const uint32_t n_ctx_max = (uint32_t) std::min<uint64_t>(uint64_t(hp_nct) * n_streams, UINT32_MAX);
|
||||
@@ -354,7 +360,7 @@ static void common_params_fit_impl(
|
||||
if (n_streams > 1) {
|
||||
LOG_TRC("%s: context size unset and KV cache not unified -> using %" PRIu32 " for %" PRIu32 " sequences:\n",
|
||||
__func__, n_ctx_max, n_streams);
|
||||
dmds_full = common_get_device_memory_data_impl(path_model, mparams, cparams, devs, hp_ngl, hp_nct, hp_nex, log_level);
|
||||
dmds_full = common_get_device_memory_data_impl(path_model, mparams, cparams, devs, hp_ngl, hp_nsk, hp_nct, hp_nex, log_level);
|
||||
}
|
||||
}
|
||||
add_extra_memory(dmds_full);
|
||||
@@ -493,7 +499,7 @@ static void common_params_fit_impl(
|
||||
|
||||
int64_t sum_projected_used_min_ctx = 0;
|
||||
cparams->n_ctx = n_ctx_min_total;
|
||||
dmds_t dmds_min_ctx = common_get_device_memory_data_impl(path_model, mparams, cparams, devs, hp_ngl, hp_nct, hp_nex, log_level);
|
||||
dmds_t dmds_min_ctx = common_get_device_memory_data_impl(path_model, mparams, cparams, devs, hp_ngl, hp_nsk, hp_nct, hp_nex, log_level);
|
||||
add_extra_memory(dmds_min_ctx);
|
||||
if (nd == 0) {
|
||||
sum_projected_used_min_ctx = dmds_min_ctx.back().mb.total();
|
||||
@@ -640,6 +646,20 @@ static void common_params_fit_impl(
|
||||
assert(uint32_t(mparams.n_gpu_layers) <= hp_ngl + 1);
|
||||
uint32_t il0 = hp_ngl + 1 - mparams.n_gpu_layers; // start index for tensor buft overrides
|
||||
|
||||
// the skipped NextN layers come right before the output layer, put them on the same device as the output layer
|
||||
// so that the layers assigned by the model loader match the layers above
|
||||
if (hp_nsk > 0 && mparams.n_gpu_layers > 0) {
|
||||
mparams.n_gpu_layers += hp_nsk;
|
||||
if (nd > 1) {
|
||||
// the last devices have no layers if not even the output layer fits
|
||||
size_t id_last = nd - 1;
|
||||
while (ngl_per_device[id_last].n_layer == 0) {
|
||||
id_last--;
|
||||
}
|
||||
tensor_split[id_last] += hp_nsk;
|
||||
}
|
||||
}
|
||||
|
||||
mparams.tensor_split = tensor_split;
|
||||
|
||||
size_t itbo = 0;
|
||||
@@ -675,7 +695,7 @@ static void common_params_fit_impl(
|
||||
set_ngl_tensor_split_tbo(ngl_per_device, overflow_bufts, mparams_copy);
|
||||
|
||||
dmds_t dmd_nl = common_get_device_memory_data_impl(
|
||||
path_model, &mparams_copy, cparams, devs, hp_ngl, hp_nct, hp_nex, log_level);
|
||||
path_model, &mparams_copy, cparams, devs, hp_ngl, hp_nsk, hp_nct, hp_nex, log_level);
|
||||
add_extra_memory(dmd_nl);
|
||||
|
||||
LOG_TRC("%s: memory for test allocation by device:\n", func_name);
|
||||
@@ -704,7 +724,7 @@ static void common_params_fit_impl(
|
||||
|
||||
LOG_TRC("%s: getting device memory data with all MoE tensors moved to system memory:\n", __func__);
|
||||
dmds_t dmds_cpu_moe = common_get_device_memory_data_impl(
|
||||
path_model, mparams, cparams, devs, hp_ngl, hp_nct, hp_nex, log_level);
|
||||
path_model, mparams, cparams, devs, hp_ngl, hp_nsk, hp_nct, hp_nex, log_level);
|
||||
add_extra_memory(dmds_cpu_moe);
|
||||
|
||||
for (size_t id = 0; id < nd; id++) {
|
||||
@@ -1185,10 +1205,11 @@ void common_fit_print(
|
||||
llama_context_params * cparams) {
|
||||
std::vector<ggml_backend_dev_t> devs;
|
||||
uint32_t hp_ngl = 0; // hparams.n_gpu_layers
|
||||
uint32_t hp_nsk = 0; // number of skipped NextN layers, counted by the model loader but not by hp_ngl
|
||||
uint32_t hp_nct = 0; // hparams.n_ctx_train
|
||||
uint32_t hp_nex = 0; // hparams.n_expert
|
||||
|
||||
auto dmd = common_get_device_memory_data_impl(path_model, mparams, cparams, devs, hp_ngl, hp_nct, hp_nex, GGML_LOG_LEVEL_ERROR);
|
||||
auto dmd = common_get_device_memory_data_impl(path_model, mparams, cparams, devs, hp_ngl, hp_nsk, hp_nct, hp_nex, GGML_LOG_LEVEL_ERROR);
|
||||
GGML_ASSERT(dmd.size() == devs.size() + 1);
|
||||
|
||||
for (size_t id = 0; id < devs.size(); id++) {
|
||||
|
||||
@@ -104,6 +104,7 @@ common_device_memory_data_vec common_get_device_memory_data(
|
||||
const llama_context_params * cparams,
|
||||
std::vector<ggml_backend_dev_t> & devs,
|
||||
uint32_t & hp_ngl,
|
||||
uint32_t & hp_ngl_skip,
|
||||
uint32_t & hp_n_ctx_train,
|
||||
uint32_t & hp_n_expert,
|
||||
ggml_log_level log_level);
|
||||
|
||||
+6
-7
@@ -45,7 +45,7 @@ static fs::path get_cache_directory() {
|
||||
{HOME_DIR, fs::path(".cache") / "huggingface" / "hub"}
|
||||
};
|
||||
for (const auto & entry : entries) {
|
||||
if (fs::path base = common_get_path_from_env(entry.var); !base.empty()) {
|
||||
if (fs::path base = common_get_env(entry.var); !base.empty()) {
|
||||
return entry.path.empty() ? base : base / entry.path;
|
||||
}
|
||||
}
|
||||
@@ -242,7 +242,7 @@ static std::string get_repo_commit(const std::string & repo_id,
|
||||
LOG_WRN("%s: skip invalid commit: %s\n", __func__, _commit.c_str());
|
||||
continue;
|
||||
}
|
||||
const fs::path candidate = fs::u8path(_name);
|
||||
const fs::path candidate = _name;
|
||||
|
||||
if (!is_valid_subpath(refs_path, candidate)) {
|
||||
LOG_WRN("%s: skip invalid branch: %s\n", __func__, _name.c_str());
|
||||
@@ -317,7 +317,7 @@ hf_files get_repo_files(const std::string & repo_id,
|
||||
file.repo_id = repo_id;
|
||||
file.path = item["path"].get<std::string>();
|
||||
|
||||
const fs::path subpath = fs::u8path(file.path);
|
||||
const fs::path subpath = file.path;
|
||||
|
||||
if (!is_valid_subpath(commit_path, subpath)) {
|
||||
LOG_WRN("%s: skip invalid path: %s\n", __func__, file.path.c_str());
|
||||
@@ -434,8 +434,7 @@ hf_files get_cached_files(const std::string & repo_id) {
|
||||
if (!path.empty()) {
|
||||
hf_file file;
|
||||
file.repo_id = _repo_id;
|
||||
const auto generic_path = path.generic_u8string();
|
||||
file.path = std::string(generic_path.begin(), generic_path.end());
|
||||
file.path = path.generic_string();
|
||||
file.local_path = entry.path().string();
|
||||
file.final_path = file.local_path;
|
||||
files.push_back(std::move(file));
|
||||
@@ -450,8 +449,8 @@ std::string finalize_file(const hf_file & file, const std::function<bool()> & ke
|
||||
static std::atomic<bool> symlinks_disabled{false};
|
||||
|
||||
std::error_code ec;
|
||||
fs::path local_path = fs::u8path(file.local_path);
|
||||
fs::path final_path = fs::u8path(file.final_path);
|
||||
fs::path local_path = file.local_path;
|
||||
fs::path final_path = file.final_path;
|
||||
|
||||
if (local_path == final_path || fs::exists(final_path, ec)) {
|
||||
return file.final_path;
|
||||
|
||||
@@ -71,6 +71,7 @@ common_chat_params common_chat_params_init_gpt_oss(const common_chat_template &
|
||||
auto content = p.rule("message-content", p.until("<|end|>"));
|
||||
auto channel = p.literal("<|channel|>") + (p.literal("commentary") | p.literal("analysis"));
|
||||
auto constrain_type = p.chars("[A-Za-z0-9_-]", 1, -1);
|
||||
auto constraint = p.optional(p.space() + p.optional(p.literal("<|constrain|>")) + constrain_type);
|
||||
|
||||
// Occasionally, gpt-oss-20b will prefix channels with this commentary
|
||||
auto stray_commentary = p.optional(p.literal("<|channel|>commentary") + p.optional(p.literal(" to=assistant")));
|
||||
@@ -84,7 +85,7 @@ common_chat_params common_chat_params_init_gpt_oss(const common_chat_template &
|
||||
|
||||
auto analysis = p.ref("analysis");
|
||||
auto preamble = p.rule("preamble", p.literal("<|channel|>commentary<|message|>") + p.content(content) + end);
|
||||
auto final_msg = p.rule("final", stray_commentary + p.literal("<|channel|>final<|message|>") + p.content(content));
|
||||
auto final_msg = p.rule("final", stray_commentary + p.literal("<|channel|>final") + constraint + p.literal("<|message|>") + p.content(content));
|
||||
|
||||
// Consume any unsolicited tool calls, e.g. builtin functions
|
||||
auto unsolicited = p.rule("unsolicited", p.atomic(p.optional(channel) + p.literal(" to=") + content + end));
|
||||
@@ -92,7 +93,6 @@ common_chat_params common_chat_params_init_gpt_oss(const common_chat_template &
|
||||
auto any = p.rule("any", preamble | analysis);
|
||||
|
||||
if (has_response_format) {
|
||||
auto constraint = p.optional(p.space() + p.optional(p.literal("<|constrain|>")) + constrain_type);
|
||||
auto response_format = p.rule("response-format",
|
||||
p.literal("<|channel|>final") + constraint + p.literal("<|message|>") +
|
||||
p.content(p.schema(p.json(), "response-format-schema", inputs.json_schema)));
|
||||
@@ -109,7 +109,6 @@ common_chat_params common_chat_params_init_gpt_oss(const common_chat_template &
|
||||
const auto params = common_chat_tool_parameters(function);
|
||||
|
||||
auto func_name = p.literal(" to=functions.") + p.tool_name(p.literal(name));
|
||||
auto constraint = p.optional(p.space() + p.optional(p.literal("<|constrain|>")) + constrain_type);
|
||||
auto args = p.tool_args(p.schema(p.json(), "tool-" + std::to_string(tool_index) + "-schema", params));
|
||||
|
||||
// recipient in role header
|
||||
|
||||
+1
-1
@@ -385,7 +385,7 @@ static bool is_draft_file(const std::string & fname) {
|
||||
}
|
||||
|
||||
common_presets common_preset_context::load_from_models_dir(const std::string & models_dir) const {
|
||||
const std::filesystem::path dir = std::filesystem::u8path(models_dir);
|
||||
const std::filesystem::path dir = models_dir;
|
||||
if (!std::filesystem::exists(dir) || !std::filesystem::is_directory(dir)) {
|
||||
throw std::runtime_error(string_format("error: '%s' does not exist or is not a directory\n", models_dir.c_str()));
|
||||
}
|
||||
|
||||
+82
-8
@@ -1027,6 +1027,9 @@ struct common_speculative_impl_draft_dflash : public common_speculative_impl {
|
||||
const int32_t * target_layer_ids = nullptr; // model_dft's extract layer indices
|
||||
uint32_t target_layer_ids_n = 0;
|
||||
|
||||
// inject target features from the target's device buffer instead of host copies (env LLAMA_DFLASH_DEV=0 disables)
|
||||
bool use_dev_features = false;
|
||||
|
||||
common_speculative_impl_draft_dflash(const common_params_speculative & params, uint32_t n_seq,
|
||||
common_speculative_type type = COMMON_SPECULATIVE_TYPE_DRAFT_DFLASH)
|
||||
: common_speculative_impl(type, n_seq, params.draft.n_max)
|
||||
@@ -1141,6 +1144,23 @@ struct common_speculative_impl_draft_dflash : public common_speculative_impl {
|
||||
llama_set_embeddings_layer_inp(ctx_tgt, (uint32_t) target_layer_ids[k], true);
|
||||
}
|
||||
|
||||
// the device buffer keeps layers in ascending id order, the fc input expects target_layer_ids order
|
||||
{
|
||||
const char * env = getenv("LLAMA_DFLASH_DEV");
|
||||
const bool ascending = std::adjacent_find(target_layer_ids, target_layer_ids + target_layer_ids_n,
|
||||
[](int32_t a, int32_t b) { return a >= b; }) == target_layer_ids + target_layer_ids_n;
|
||||
|
||||
use_dev_features = !is_lilicorr && ascending && (env == nullptr || atoi(env) != 0);
|
||||
if (use_dev_features) {
|
||||
llama_set_embeddings_layer_inp_dev(ctx_tgt, true);
|
||||
use_dev_features = llama_supports_embd_row(ctx_dft);
|
||||
if (!use_dev_features) {
|
||||
llama_set_embeddings_layer_inp_dev(ctx_tgt, false);
|
||||
}
|
||||
}
|
||||
LOG_INF("%s: DFlash target features via %s\n", __func__, use_dev_features ? "device buffer" : "host copies");
|
||||
}
|
||||
|
||||
// DFlash2 reads its selector lattice from h_nextn and never consumes raw logits.
|
||||
llama_set_embeddings_nextn(ctx_dft, true, /*masked*/ !is_dflash2 && !is_lilicorr);
|
||||
llama_set_causal_attn(ctx_dft, causal_attn); // DFlash needs non-causal attention unless the model says otherwise
|
||||
@@ -1233,6 +1253,25 @@ struct common_speculative_impl_draft_dflash : public common_speculative_impl {
|
||||
for (int32_t offset = 0; offset < n_rows; offset += n_ubatch) {
|
||||
const int32_t n_chunk = std::min(n_ubatch, n_rows - offset);
|
||||
|
||||
if (use_dev_features) {
|
||||
// the features are the target batch rows in the target's device buffer
|
||||
batch_inject.clear();
|
||||
for (int32_t i = 0; i < n_chunk; ++i) {
|
||||
const int32_t row = i_batch_beg[seq_id] + offset + i;
|
||||
const llama_pos p = batch_in.tokens[row].pos[0];
|
||||
const llama_pos pos_arr[4] = { p, p, p, 0 };
|
||||
batch_inject.add_embd_row(row, pos_arr, seq_id, false);
|
||||
}
|
||||
|
||||
const int32_t rc = llama_process(ctx_dft, LLAMA_PROCESS_TYPE_DECODE, batch_inject.get());
|
||||
if (rc != 0) {
|
||||
LOG_ERR("%s: llama_process(ctx_dft) failed rc=%d (n_tokens=%d, offset=%d)\n",
|
||||
__func__, rc, (int) n_chunk, (int) offset);
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// gather target features per extract layer; the fused decode encodes and
|
||||
// injects them into the K/V cache at the target positions
|
||||
features_buf.resize((size_t) n_chunk * n_embd_enc);
|
||||
@@ -1574,12 +1613,12 @@ struct common_speculative_impl_draft_mtp : public common_speculative_impl {
|
||||
}
|
||||
}
|
||||
|
||||
llama_set_embeddings_nextn(ctx_tgt, true, /*masked*/ false);
|
||||
llama_set_embeddings_nextn(ctx_dft, true, /*masked*/ true);
|
||||
|
||||
is_mem_shared = llama_get_ctx_other(ctx_dft) == ctx_tgt;
|
||||
chain_heads = n_mtp_layers > 1 && !is_mem_shared;
|
||||
|
||||
llama_set_embeddings_nextn(ctx_tgt, true, /*masked*/ is_mem_shared);
|
||||
llama_set_embeddings_nextn(ctx_dft, true, /*masked*/ true);
|
||||
|
||||
if (chain_heads) {
|
||||
this->params.n_max = std::min(this->params.n_max, n_mtp_layers);
|
||||
|
||||
@@ -1733,16 +1772,28 @@ struct common_speculative_impl_draft_mtp : public common_speculative_impl {
|
||||
}
|
||||
|
||||
const int32_t n_rows = i_batch_end[seq_id] - i_batch_beg[seq_id] + 1;
|
||||
verify_h_rows[seq_id] = n_rows;
|
||||
verify_h[seq_id].resize((size_t) n_rows * n_embd);
|
||||
if (is_mem_shared && !batch_in.tokens[i_batch_end[seq_id]].output) {
|
||||
verify_h_rows[seq_id] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < n_rows; ++i) {
|
||||
const float * h = llama_get_embeddings_nextn_ith(ctx_tgt, i_batch_beg[seq_id] + i);
|
||||
const bool all_rows_output = std::all_of(
|
||||
batch_in.tokens.begin() + i_batch_beg[seq_id],
|
||||
batch_in.tokens.begin() + i_batch_end[seq_id] + 1,
|
||||
[](const common_batch::token & token) { return token.output; });
|
||||
const int32_t h_rows = is_mem_shared && !all_rows_output ? 1 : n_rows;
|
||||
const int32_t h_offset = is_mem_shared && !all_rows_output ? i_batch_end[seq_id] : i_batch_beg[seq_id];
|
||||
|
||||
verify_h_rows[seq_id] = h_rows;
|
||||
verify_h[seq_id].resize((size_t) h_rows * n_embd);
|
||||
|
||||
for (int32_t i = 0; i < h_rows; ++i) {
|
||||
const float * h = llama_get_embeddings_nextn_ith(ctx_tgt, h_offset + i);
|
||||
std::memcpy(verify_h[seq_id].data() + (size_t) i * n_embd, h, row_bytes);
|
||||
}
|
||||
|
||||
std::memcpy(pending_h[seq_id].data(),
|
||||
verify_h[seq_id].data() + (size_t) (n_rows - 1) * n_embd, row_bytes);
|
||||
verify_h[seq_id].data() + (size_t) (h_rows - 1) * n_embd, row_bytes);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -1928,6 +1979,29 @@ struct common_speculative_impl_draft_mtp : public common_speculative_impl {
|
||||
const size_t row_bytes = (size_t) n_embd * sizeof(float);
|
||||
std::memcpy(pending_h[seq_id].data(), verify_h[seq_id].data() + (size_t) i_h * n_embd, row_bytes);
|
||||
}
|
||||
|
||||
bool get_state(llama_seq_id seq_id, std::vector<uint8_t> & data) const override {
|
||||
if (seq_id < 0 || seq_id >= (llama_seq_id) n_seq) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t row_bytes = (size_t) n_embd * sizeof(float);
|
||||
data.resize(row_bytes);
|
||||
std::memcpy(data.data(), pending_h[seq_id].data(), row_bytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
void set_state(llama_seq_id seq_id, const std::vector<uint8_t> & data) override {
|
||||
if (seq_id < 0 || seq_id >= (llama_seq_id) n_seq) {
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t row_bytes = (size_t) n_embd * sizeof(float);
|
||||
if (data.size() != row_bytes) {
|
||||
return;
|
||||
}
|
||||
std::memcpy(pending_h[seq_id].data(), data.data(), row_bytes);
|
||||
}
|
||||
};
|
||||
|
||||
// state of self-speculation (simple implementation, not ngram-map)
|
||||
|
||||
@@ -20,6 +20,7 @@ TEXT_MODEL_MAP: dict[str, str] = {
|
||||
"NEOChatModel": "sensenova_u1",
|
||||
"AfmoeForCausalLM": "afmoe",
|
||||
"LagunaForCausalLM": "laguna",
|
||||
"RicursiveForCausalLM": "ricursive",
|
||||
"FlintForCausalLM": "flint",
|
||||
"ApertusForCausalLM": "llama",
|
||||
"ArceeForCausalLM": "llama",
|
||||
@@ -45,7 +46,9 @@ TEXT_MODEL_MAP: dict[str, str] = {
|
||||
"ChameleonForConditionalGeneration": "chameleon",
|
||||
"ChatGLMForConditionalGeneration": "chatglm",
|
||||
"ChatGLMModel": "chatglm",
|
||||
"ChatterboxModel": "chatterbox",
|
||||
"ClefModel": "clef",
|
||||
"CloverMoeModelLM": "clover",
|
||||
"CodeShellForCausalLM": "codeshell",
|
||||
"CogVLMForCausalLM": "cogvlm",
|
||||
"Cohere2MoeForCausalLM": "command_r",
|
||||
@@ -60,6 +63,7 @@ TEXT_MODEL_MAP: dict[str, str] = {
|
||||
"DeepseekV2ForCausalLM": "deepseek",
|
||||
"DeepseekV3ForCausalLM": "deepseek",
|
||||
"DeepseekV32ForCausalLM": "deepseek",
|
||||
"Xing4_0ForCausalLM": "xing",
|
||||
"DFlashDraftModel": "qwen",
|
||||
"DFlash2DraftModel": "qwen",
|
||||
"LiLiCorrDraftModel": "nemotron",
|
||||
@@ -93,6 +97,7 @@ TEXT_MODEL_MAP: dict[str, str] = {
|
||||
"FalconForCausalLM": "falcon",
|
||||
"FalconH1ForCausalLM": "falcon_h1",
|
||||
"FalconMambaForCausalLM": "mamba",
|
||||
"FishOmniModel": "drama3",
|
||||
"GPT2LMHeadModel": "gpt2",
|
||||
"GPTBigCodeForCausalLM": "starcoder",
|
||||
"GPTNeoXForCausalLM": "gptneox",
|
||||
@@ -153,6 +158,7 @@ TEXT_MODEL_MAP: dict[str, str] = {
|
||||
"KORMoForCausalLM": "qwen",
|
||||
"KimiK25ForConditionalGeneration": "deepseek",
|
||||
"KimiK3ForConditionalGeneration": "kimi_k3",
|
||||
"KimiK31ForConditionalGeneration": "kimi_k3",
|
||||
"KimiLinearForCausalLM": "kimi_linear",
|
||||
"KimiLinearModel": "kimi_linear",
|
||||
"KimiVLForConditionalGeneration": "deepseek",
|
||||
@@ -187,6 +193,7 @@ TEXT_MODEL_MAP: dict[str, str] = {
|
||||
"Eagle3LlamaForCausalLM": "llama",
|
||||
"LlamaForCausalLMEagle3": "llama",
|
||||
"LlavaForConditionalGeneration": "llama",
|
||||
"LlavaOnevision2ForConditionalGeneration": "qwen",
|
||||
"LlavaStableLMEpochForCausalLM": "stablelm",
|
||||
"MPTForCausalLM": "mpt",
|
||||
"MT5ForConditionalGeneration": "t5",
|
||||
@@ -196,6 +203,7 @@ TEXT_MODEL_MAP: dict[str, str] = {
|
||||
"MambaLMHeadModel": "mamba",
|
||||
"MapleForCausalLM": "maple",
|
||||
"MellumForCausalLM": "mellum",
|
||||
"Metis16ForCausalLM": "metis",
|
||||
"MiMoV2FlashForCausalLM": "mimo",
|
||||
"MiMoV2ForCausalLM": "mimo",
|
||||
"MiniCPM3ForCausalLM": "minicpm",
|
||||
@@ -222,6 +230,7 @@ TEXT_MODEL_MAP: dict[str, str] = {
|
||||
"ModernBertForSequenceClassification": "bert",
|
||||
"ModernBertModel": "bert",
|
||||
"NanbeigeForCausalLM": "nanbeige",
|
||||
"Nemotron3_5TranscribeForConditionalGeneration": "nemotron",
|
||||
"NemotronForCausalLM": "nemotron",
|
||||
"NemotronHForCausalLM": "nemotron",
|
||||
"NemotronHPuzzleForCausalLM": "nemotron",
|
||||
@@ -327,6 +336,7 @@ TEXT_MODEL_MAP: dict[str, str] = {
|
||||
|
||||
MMPROJ_MODEL_MAP: dict[str, str] = {
|
||||
"AudioFlamingo3ForConditionalGeneration": "ultravox",
|
||||
"ChatterboxModel": "chatterbox",
|
||||
"ClefModel": "clef",
|
||||
"CogVLMForCausalLM": "cogvlm",
|
||||
"Cohere2VisionForConditionalGeneration": "command_r",
|
||||
@@ -341,6 +351,7 @@ MMPROJ_MODEL_MAP: dict[str, str] = {
|
||||
"DotsOCRForCausalLM": "dotsocr",
|
||||
"EmbeddingGemma2Model": "gemma",
|
||||
"Exaone4_5_ForConditionalGeneration": "exaone",
|
||||
"FishOmniModel": "drama3",
|
||||
"Gemma3ForConditionalGeneration": "gemma",
|
||||
"Gemma3nForConditionalGeneration": "gemma",
|
||||
"Gemma4ForConditionalGeneration": "gemma",
|
||||
@@ -370,6 +381,7 @@ MMPROJ_MODEL_MAP: dict[str, str] = {
|
||||
"LightOnOCRForConditionalGeneration": "lighton_ocr",
|
||||
"Llama4ForConditionalGeneration": "llama4",
|
||||
"LlavaForConditionalGeneration": "llava",
|
||||
"LlavaOnevision2ForConditionalGeneration": "magevl",
|
||||
"MERaLiON2ForConditionalGeneration": "ultravox",
|
||||
"MiMoV2ForCausalLM": "mimo",
|
||||
"MiniMaxM3SparseForConditionalGeneration": "minimax",
|
||||
@@ -379,6 +391,7 @@ MMPROJ_MODEL_MAP: dict[str, str] = {
|
||||
"MiniCPMOcrForConditionalGeneration": "minicpm",
|
||||
"Mistral3ForConditionalGeneration": "llava",
|
||||
"Mistral3Model": "llava",
|
||||
"Nemotron3_5TranscribeForConditionalGeneration": "nemotron",
|
||||
"NemotronH_Omni_Reasoning_V3": "nemotron",
|
||||
"NemotronH_Nano_VL_V2": "nemotron",
|
||||
"MuseGlimmerForConditionalGeneration": "muse_glimmer",
|
||||
|
||||
+47
-24
@@ -167,6 +167,8 @@ class ModelBase:
|
||||
self._fusable_qkv_weight_layers: set[int] = set()
|
||||
self._fusable_qkv_bias_layers: set[int] = set()
|
||||
self.hparams = ModelBase.load_hparams(self.dir_model, self.is_mistral_format) if hparams is None else hparams
|
||||
# source tensor name to filtered tensor name mapping.
|
||||
self._source_tensor_names: dict[str, str | None] = {}
|
||||
self.model_tensors = self.index_tensors(remote_hf_model_id=remote_hf_model_id)
|
||||
self.metadata_override = metadata_override
|
||||
self.model_name = model_name
|
||||
@@ -225,21 +227,25 @@ class ModelBase:
|
||||
tensors: dict[str, Callable[[], Tensor]] = {}
|
||||
|
||||
if remote_hf_model_id is not None:
|
||||
is_safetensors = True
|
||||
|
||||
logger.info(f"Using remote model with HuggingFace id: {remote_hf_model_id}")
|
||||
remote_tensors = gguf.utility.SafetensorRemote.get_list_tensors_hf_model(remote_hf_model_id)
|
||||
for name, remote_tensor in remote_tensors.items():
|
||||
data_gen = lambda r=remote_tensor: LazyTorchTensor.from_remote_tensor(r) # noqa: E731
|
||||
if titem := self.filter_tensors((name, data_gen)):
|
||||
titem = self.filter_tensors((name, data_gen))
|
||||
self._source_tensor_names[name] = titem[0] if titem else None
|
||||
if titem:
|
||||
tname, tgen = titem
|
||||
tensors[tname] = tgen
|
||||
|
||||
return tensors
|
||||
|
||||
prefix = "model" if not self.is_mistral_format else "consolidated"
|
||||
return self.index_local_tensors("model" if not self.is_mistral_format else "consolidated")
|
||||
|
||||
# index the local "<prefix>*.safetensors" files (or pytorch_model*.bin), through filter_tensors
|
||||
def index_local_tensors(self, prefix: str) -> dict[str, Callable[[], Tensor]]:
|
||||
tensors: dict[str, Callable[[], Tensor]] = {}
|
||||
part_names: list[str] = ModelBase.get_model_part_names(self.dir_model, prefix, ".safetensors")
|
||||
is_safetensors: bool = len(part_names) > 0 or (not self.is_mistral_format and (self.dir_model / "model.safetensors.index.json").is_file())
|
||||
is_safetensors: bool = len(part_names) > 0 or (not self.is_mistral_format and (self.dir_model / f"{prefix}.safetensors.index.json").is_file())
|
||||
if not is_safetensors:
|
||||
part_names = ModelBase.get_model_part_names(self.dir_model, "pytorch_model", ".bin")
|
||||
|
||||
@@ -247,7 +253,7 @@ class ModelBase:
|
||||
tensor_names_from_parts: set[str] = set()
|
||||
|
||||
if not self.is_mistral_format:
|
||||
index_name = "model.safetensors" if is_safetensors else "pytorch_model.bin"
|
||||
index_name = f"{prefix}.safetensors" if is_safetensors else "pytorch_model.bin"
|
||||
index_name += ".index.json"
|
||||
index_file = self.dir_model / index_name
|
||||
|
||||
@@ -292,7 +298,9 @@ class ModelBase:
|
||||
data_gen = lambda data=data_torch: LazyTorchTensor.from_eager(data) # noqa: E731
|
||||
else:
|
||||
data_gen = lambda data=data_torch: data # noqa: E731
|
||||
if titem := self.filter_tensors((name, data_gen)):
|
||||
titem = self.filter_tensors((name, data_gen))
|
||||
self._source_tensor_names[name] = titem[0] if titem else None
|
||||
if titem:
|
||||
tname, tgen = titem
|
||||
tensors[tname] = tgen
|
||||
|
||||
@@ -492,7 +500,7 @@ class ModelBase:
|
||||
s = self.model_tensors[name]
|
||||
self.model_tensors[weight_name] = lambda w=w, s=s: dequant_bitnet(w(), s())
|
||||
tensors_to_remove.append(name)
|
||||
elif quant_method == "fp8":
|
||||
elif quant_method in ("fp8", "bsgemm-moe"): # bsgemm-moe: drama-3, same block layout
|
||||
block_size = quant_config.get("weight_block_size")
|
||||
for name in self.model_tensors.keys():
|
||||
if name.endswith("_scale_inv"):
|
||||
@@ -1277,6 +1285,7 @@ class ModelBase:
|
||||
expert_scales: dict[tuple[int, str], list[tuple[int, float]]] = {}
|
||||
expert_input_scales: dict[tuple[int, str], list[tuple[int, float]]] = {}
|
||||
expert_shapes: dict[tuple[int, str], list[int]] = {}
|
||||
expert_names: dict[tuple[int, str], str] = {}
|
||||
n_experts = self.find_hparam(["num_local_experts", "num_experts", "n_routed_experts"], optional=True) or 0
|
||||
consumed: list[str] = []
|
||||
|
||||
@@ -1325,6 +1334,7 @@ class ModelBase:
|
||||
expert_scales[key] = []
|
||||
expert_input_scales[key] = []
|
||||
expert_shapes[key] = shape
|
||||
expert_names[key] = name
|
||||
expert_blocks[key].append((expert_id, raw.copy()))
|
||||
# Collect per-expert scale2 (scalar per expert)
|
||||
expert_scales[key].append((expert_id, float(scale2.float().sum())))
|
||||
@@ -1333,13 +1343,13 @@ class ModelBase:
|
||||
|
||||
# Flush when all experts for this (layer, proj) are collected
|
||||
if n_experts > 0 and len(expert_blocks[key]) >= n_experts:
|
||||
self._flush_nvfp4_experts(key, expert_blocks, expert_scales, expert_input_scales, expert_shapes, bid, proj_type)
|
||||
self._flush_nvfp4_experts(key, expert_blocks, expert_scales, expert_input_scales, expert_shapes, expert_names, bid, proj_type)
|
||||
else:
|
||||
self._repack_nvfp4(name, weight, scale, scale2, input_scale)
|
||||
|
||||
# Flush any remaining experts (fallback if n_experts was unknown)
|
||||
for bid, proj_type in list(expert_blocks.keys()):
|
||||
self._flush_nvfp4_experts((bid, proj_type), expert_blocks, expert_scales, expert_input_scales, expert_shapes, bid, proj_type)
|
||||
self._flush_nvfp4_experts((bid, proj_type), expert_blocks, expert_scales, expert_input_scales, expert_shapes, expert_names, bid, proj_type)
|
||||
|
||||
# Remove consumed tensors so get_tensors/modify_tensors won't see them
|
||||
for name in consumed:
|
||||
@@ -1350,7 +1360,7 @@ class ModelBase:
|
||||
if name.endswith((".k_scale", ".v_scale")):
|
||||
del self.model_tensors[name]
|
||||
|
||||
def _flush_nvfp4_experts(self, key, expert_blocks, expert_scales, expert_input_scales, expert_shapes, bid, proj_type):
|
||||
def _flush_nvfp4_experts(self, key, expert_blocks, expert_scales, expert_input_scales, expert_shapes, expert_names, bid, proj_type):
|
||||
experts = expert_blocks.pop(key)
|
||||
scales = expert_scales.pop(key)
|
||||
input_scales = expert_input_scales.pop(key)
|
||||
@@ -1362,7 +1372,7 @@ class ModelBase:
|
||||
new_name = self.map_tensor_name(merged_name)
|
||||
logger.info(f"Repacked {new_name} with shape [{len(experts)}, {shape[0]}, {shape[1]}] and quantization NVFP4")
|
||||
self.gguf_writer.add_tensor(new_name, merged, raw_dtype=gguf.GGMLQuantizationType.NVFP4)
|
||||
self._tag_prec_a4(merged_name, new_name)
|
||||
self._tag_prec_a4(expert_names.pop(key), new_name)
|
||||
|
||||
scales.sort(key=lambda x: x[0])
|
||||
self._write_scales_tensor(new_name.replace(".weight", ".scale"), [s[1] for s in scales])
|
||||
@@ -1413,18 +1423,25 @@ class ModelBase:
|
||||
# Per-tensor NVFP4 precision.
|
||||
self._nvfp4_layer_algo = {}
|
||||
if quant_layers:
|
||||
# store all possible module paths and assert if a quantized layer is not in the model
|
||||
modules: set[str] = set()
|
||||
for name in self.model_tensors:
|
||||
while name := name.rpartition(".")[0]:
|
||||
modules.add(name)
|
||||
|
||||
for layer_name, entry in quant_layers.items():
|
||||
if not isinstance(entry, dict):
|
||||
# quantized_layers keys are module paths in the source checkpoint, not tensor names
|
||||
# resolve each source tensor to the closest quantized_layers parent and record the algo under its filtered name for _tag_prec_a4
|
||||
layer_algo = {k: v.get("quant_algo") for k, v in quant_layers.items() if isinstance(v, dict)}
|
||||
matched: set[str] = set()
|
||||
for src_name, filtered_name in self._source_tensor_names.items():
|
||||
module = src_name
|
||||
while module := module.rpartition(".")[0]:
|
||||
if module in layer_algo:
|
||||
break
|
||||
if not module:
|
||||
continue
|
||||
if titem := self.filter_tensors((layer_name, lambda: torch.empty(0))):
|
||||
assert titem[0] in modules, f"quantized_layers entry {layer_name!r} is not in the model tensors"
|
||||
self._nvfp4_layer_algo[titem[0]] = entry.get("quant_algo")
|
||||
|
||||
matched.add(module)
|
||||
# filter_tensors may drop a tensors so we need to check for that here.
|
||||
if filtered_name is not None:
|
||||
self._nvfp4_layer_algo[filtered_name.removesuffix(".weight").removesuffix(".bias")] = layer_algo[module]
|
||||
|
||||
unmatched = layer_algo.keys() - matched
|
||||
assert not unmatched, f"quantized_layers entries not in the model tensors: {sorted(unmatched)}"
|
||||
|
||||
# NVFP4 weights are repacked and written directly to gguf_writer.
|
||||
# This must run before dequant_model so NVFP4 tensors are removed
|
||||
@@ -2114,6 +2131,9 @@ class TextModel(ModelBase):
|
||||
if chkhsh == "0fe1cf6eda062318a1af7270f3331a85c539a01778ff948e24388e949c5282f4":
|
||||
# ref: https://huggingface.co/evilfreelancer/ruGPT3XL
|
||||
res = "gpt-2"
|
||||
if chkhsh == "df1bc34a6366466bcb36a9a1b1cc0afdb08cfe21c9250602c930f159085390a9":
|
||||
# ref: https://huggingface.co/Lernex/Metis-1.6-Logos
|
||||
res = "gpt-2"
|
||||
if chkhsh == "9e454714343b69b99b71795c1d27a68c2a1d15dab111f4d353109f966af29da7":
|
||||
# ref: https://huggingface.co/LiquidAI/LFM2.5-8B-A1B
|
||||
res = "lfm2"
|
||||
@@ -3384,7 +3404,7 @@ def get_model_architecture(hparams: dict[str, Any], model_type: ModelType) -> st
|
||||
# Kimi-K3's text_config reports "KimiLinearForCausalLM", which is the older
|
||||
# Kimi-Linear-48B architecture and cannot load K3 (no attention residuals,
|
||||
# latent MoE, situ, ...). Route on the top-level architecture instead.
|
||||
if model_type == ModelType.TEXT and arch in ("NEOChatModel", "StepVLForConditionalGeneration", "Sarashina2VisionForCausalLM", "Exaone4_5_ForConditionalGeneration", "Step3p7ForConditionalGeneration", "KimiK3ForConditionalGeneration"):
|
||||
if model_type == ModelType.TEXT and arch in ("NEOChatModel", "StepVLForConditionalGeneration", "Sarashina2VisionForCausalLM", "Exaone4_5_ForConditionalGeneration", "Step3p7ForConditionalGeneration", "KimiK3ForConditionalGeneration", "KimiK31ForConditionalGeneration", "Nemotron3_5TranscribeForConditionalGeneration"):
|
||||
return arch
|
||||
|
||||
# if "architectures" is found in the sub-config, use that instead
|
||||
@@ -3392,6 +3412,9 @@ def get_model_architecture(hparams: dict[str, Any], model_type: ModelType) -> st
|
||||
arch = text_config["architectures"][0]
|
||||
elif model_type == ModelType.MMPROJ and vision_config.get("architectures") is not None:
|
||||
arch = vision_config["architectures"][0]
|
||||
# some models (llava_onevision2) only declare the architecture inside text_config
|
||||
if arch is None and text_config.get("architectures") is not None:
|
||||
arch = text_config["architectures"][0]
|
||||
if arch is None:
|
||||
raise ValueError("Failed to detect model architecture")
|
||||
return arch
|
||||
|
||||
@@ -0,0 +1,473 @@
|
||||
# Chatterbox (ResembleAI) turbo and multilingual v3, from the raw checkpoints of the official repos
|
||||
# the checkpoints ship no config.json, the variant is detected from the talker file and the hparams come from the reference code
|
||||
# talker: text_emb and speech_emb are fused into one [text | speech] vocab, speech token i is <|speech_i|>
|
||||
# mmproj: the s3gen sidecar, the voice and conditioning encoders, the position and speech tables, and the conds.pt voice
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import math
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Any, Callable, Iterable
|
||||
|
||||
import torch
|
||||
import torch.nn.functional as F
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from torch import Tensor
|
||||
|
||||
from .base import ModelBase, TextModel, MmprojModel, LazyTorchTensor, gguf, logger
|
||||
from .llama import LlamaModel
|
||||
|
||||
# checkpoint file prefixes, the files are "<prefix>.safetensors"
|
||||
TURBO_TALKER = "t3_turbo_v1"
|
||||
MTL_TALKER = "t3_mtl23ls_v3"
|
||||
TURBO_S3GEN = "s3gen_meanflow"
|
||||
MTL_S3GEN = "s3gen_v3"
|
||||
VE = "ve"
|
||||
|
||||
# relative speech ids shared by both variants (start/stop_speech_token in the reference)
|
||||
SPEECH_BOS = 6561
|
||||
SPEECH_EOS = 6562
|
||||
|
||||
# sampling defaults of the reference, samplers it does not use are disabled so the common defaults do not apply
|
||||
TURBO_TOP_K = 1000
|
||||
MTL_TOP_K = 0
|
||||
TURBO_SAMPLING = {"min_p": 0.0, "top_p": 0.95, "temp": 0.8, "penalty_repeat": 1.2}
|
||||
MTL_SAMPLING = {"min_p": 0.05, "top_p": 1.0, "temp": 0.8, "penalty_repeat": 1.2}
|
||||
# the reference repetition penalty covers the whole generated history
|
||||
PENALTY_LAST_N = -1
|
||||
|
||||
|
||||
def _has_file(dir_model: Path, prefix: str) -> bool:
|
||||
return (dir_model / f"{prefix}.safetensors").is_file()
|
||||
|
||||
|
||||
def _is_turbo(dir_model: Path) -> bool:
|
||||
if _has_file(dir_model, TURBO_TALKER):
|
||||
return True
|
||||
if _has_file(dir_model, MTL_TALKER):
|
||||
return False
|
||||
raise FileNotFoundError(f"no chatterbox talker checkpoint in {dir_model}")
|
||||
|
||||
|
||||
# talker hparams of the reference (GPT2_MEDIUM_CONFIG / LLAMA_520M_CONFIG_DICT, T3Config)
|
||||
TURBO_TEXT_CONFIG = {
|
||||
"n_layer": 24, "n_embd": 1024, "n_inner": 4096, "n_head": 16, "n_ctx": 8196, "layer_norm_epsilon": 1e-05,
|
||||
"vocab_size": 50276, "speech_vocab_size": 6563,
|
||||
}
|
||||
MTL_TEXT_CONFIG = {
|
||||
"num_hidden_layers": 30, "hidden_size": 1024, "intermediate_size": 4096, "num_attention_heads": 16,
|
||||
"num_key_value_heads": 16, "head_dim": 64, "max_position_embeddings": 131072, "rms_norm_eps": 1e-05,
|
||||
"rope_theta": 500000.0,
|
||||
"rope_scaling": {"factor": 8.0, "high_freq_factor": 4.0, "low_freq_factor": 1.0, "original_max_position_embeddings": 8192},
|
||||
"vocab_size": 2454, "speech_vocab_size": 8194,
|
||||
}
|
||||
|
||||
|
||||
def _is_chatterbox_checkpoint(dir_model: Path) -> bool:
|
||||
return _has_file(dir_model, VE) and (_has_file(dir_model, TURBO_TALKER) or _has_file(dir_model, MTL_TALKER))
|
||||
|
||||
|
||||
@ModelBase.register_hparams_loader(_is_chatterbox_checkpoint)
|
||||
def _load_chatterbox_hparams(dir_model: Path) -> dict[str, Any]:
|
||||
turbo = _is_turbo(dir_model)
|
||||
logger.info(f"gguf: detected Chatterbox {'turbo' if turbo else 'multilingual v3'} checkpoint")
|
||||
text_config = dict(TURBO_TEXT_CONFIG if turbo else MTL_TEXT_CONFIG)
|
||||
# the mmproj tensors are named explicitly, they do not go through the block tensor map
|
||||
return {"architectures": ["ChatterboxModel"], "text_config": text_config, "audio_config": {"num_hidden_layers": 0}}
|
||||
|
||||
|
||||
@ModelBase.register("ChatterboxModel")
|
||||
class ChatterboxTalkerModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.LLAMA # multilingual; the turbo constructor switches to GPT2
|
||||
|
||||
def __init__(self, dir_model: Path, *args, **kwargs):
|
||||
self.is_turbo = _is_turbo(dir_model)
|
||||
if self.is_turbo:
|
||||
self.model_arch = gguf.MODEL_ARCH.GPT2
|
||||
super().__init__(dir_model, *args, **kwargs)
|
||||
self._text_embd: Tensor | None = None
|
||||
self._speech_embd: Tensor | None = None
|
||||
self._text_head: Tensor | None = None
|
||||
self._speech_head: Tensor | None = None
|
||||
|
||||
def index_tensors(self, remote_hf_model_id: str | None = None) -> dict[str, Callable[[], Tensor]]:
|
||||
return self.index_local_tensors(TURBO_TALKER if self.is_turbo else MTL_TALKER)
|
||||
|
||||
@classmethod
|
||||
def filter_tensors(cls, item: tuple[str, Callable[[], Tensor]]) -> tuple[str, Callable[[], Tensor]] | None:
|
||||
name, _ = item
|
||||
# the reference feeds inputs_embeds, the transformer input embeddings are unused
|
||||
if name in ("tfmr.wte.weight", "tfmr.embed_tokens.weight"):
|
||||
return None
|
||||
if name.startswith(("cond_enc.", "text_pos_emb.", "speech_pos_emb.")):
|
||||
return None
|
||||
return super().filter_tensors(item)
|
||||
|
||||
def set_vocab(self):
|
||||
if self.is_turbo:
|
||||
self._set_vocab_turbo()
|
||||
else:
|
||||
self._set_vocab_mtl()
|
||||
|
||||
def _speech_token_names(self, n_speech: int) -> list[str]:
|
||||
return [f"<|speech_{i}|>" for i in range(n_speech)]
|
||||
|
||||
def _set_vocab_turbo(self):
|
||||
# stock GPT-2 BPE from the checkpoint dir, extended with the speech tokens
|
||||
tokens, toktypes, tokpre = self.get_vocab_base()
|
||||
n_text = len(tokens)
|
||||
n_speech = self.hparams["speech_vocab_size"]
|
||||
speech = self._speech_token_names(n_speech)
|
||||
tokens += speech
|
||||
toktypes += [gguf.TokenType.CONTROL] * n_speech
|
||||
|
||||
with open(self.dir_model / "merges.txt", "r", encoding="utf-8") as f:
|
||||
merges = [line.rstrip("\n") for line in f if line.strip() and not line.startswith("#version")]
|
||||
|
||||
self._write_vocab(tokens, toktypes, merges, tokpre, n_text)
|
||||
|
||||
def _write_vocab(self, tokens: list[str], toktypes: list[int], merges: list[str], tokpre: str, n_text: int):
|
||||
self.gguf_writer.add_tokenizer_model("gpt2")
|
||||
self.gguf_writer.add_tokenizer_pre(tokpre)
|
||||
self.gguf_writer.add_token_list(tokens)
|
||||
self.gguf_writer.add_token_types(toktypes)
|
||||
self.gguf_writer.add_token_merges(merges)
|
||||
|
||||
self.gguf_writer.add_bos_token_id(n_text + SPEECH_BOS)
|
||||
self.gguf_writer.add_eos_token_id(n_text + SPEECH_EOS)
|
||||
self.gguf_writer.add_add_bos_token(False)
|
||||
self.gguf_writer.add_add_eos_token(False)
|
||||
|
||||
# the reference samples the speech head only
|
||||
self.gguf_writer.add_suppress_tokens(list(range(n_text)))
|
||||
|
||||
def _set_vocab_mtl(self):
|
||||
# the reference BPE is char-level, it is re-encoded to byte-level with extra merges that rebuild each multi-byte char
|
||||
# its lowercasing is folded into the embedding table, so the prompt needs no text preprocessing
|
||||
with open(self.dir_model / "mtl_tokenizer.json", "r", encoding="utf-8") as f:
|
||||
tok = json.load(f)
|
||||
|
||||
byte_map = gguf.vocab.bytes_to_unicode()
|
||||
|
||||
def enc(s: str) -> str:
|
||||
return "".join(byte_map[b] for b in s.encode("utf-8"))
|
||||
|
||||
n_text = self.hparams["vocab_size"]
|
||||
tokens: list[str] = [f"[unused_{i}]" for i in range(n_text)]
|
||||
toktypes = [int(gguf.TokenType.UNUSED)] * n_text
|
||||
char_merges: list[str] = []
|
||||
for t, i in tok["model"]["vocab"].items():
|
||||
if t == " ":
|
||||
# the reference substitutes [SPACE] before encoding, the raw space token is never used
|
||||
continue
|
||||
tokens[i] = enc(t)
|
||||
toktypes[i] = int(gguf.TokenType.NORMAL)
|
||||
if len(t) == 1 and len(t.encode("utf-8")) > 1:
|
||||
parts = [byte_map[b] for b in t.encode("utf-8")]
|
||||
for k in range(1, len(parts)):
|
||||
char_merges.append("".join(parts[:k]) + " " + parts[k])
|
||||
for entry in tok.get("added_tokens", []):
|
||||
tokens[entry["id"]] = entry["content"]
|
||||
toktypes[entry["id"]] = int(gguf.TokenType.CONTROL)
|
||||
|
||||
# raw spaces tokenize to [SPACE] directly
|
||||
space_id = tok["model"]["vocab"]["[SPACE]"]
|
||||
tokens[space_id] = enc(" ")
|
||||
toktypes[space_id] = int(gguf.TokenType.NORMAL)
|
||||
|
||||
n_speech = self.hparams["speech_vocab_size"]
|
||||
tokens += self._speech_token_names(n_speech)
|
||||
toktypes += [int(gguf.TokenType.CONTROL)] * n_speech
|
||||
|
||||
# chars are atomic in the reference, they must form before any of its merges
|
||||
merges = char_merges
|
||||
for m in tok["model"].get("merges", []):
|
||||
a, b = m if isinstance(m, list) else m.split(" ")
|
||||
merges.append(enc(a) + " " + enc(b))
|
||||
|
||||
self._write_vocab(tokens, toktypes, merges, "default", n_text)
|
||||
|
||||
def _mtl_case_fold_pairs(self) -> list[tuple[int, int]]:
|
||||
# (upper_id, lower_id) of the single-char vocab entries, for every script in the vocab
|
||||
with open(self.dir_model / "mtl_tokenizer.json", "r", encoding="utf-8") as f:
|
||||
vocab = json.load(f)["model"]["vocab"]
|
||||
pairs: list[tuple[int, int]] = []
|
||||
for t, i in vocab.items():
|
||||
if len(t) != 1:
|
||||
continue
|
||||
low = t.lower()
|
||||
if low != t and len(low) == 1 and low in vocab:
|
||||
pairs.append((i, vocab[low]))
|
||||
return pairs
|
||||
|
||||
def set_gguf_parameters(self):
|
||||
super().set_gguf_parameters()
|
||||
|
||||
sampling = TURBO_SAMPLING if self.is_turbo else MTL_SAMPLING
|
||||
self.gguf_writer.add_sampling_top_k(TURBO_TOP_K if self.is_turbo else MTL_TOP_K)
|
||||
self.gguf_writer.add_sampling_min_p(sampling["min_p"])
|
||||
self.gguf_writer.add_sampling_top_p(sampling["top_p"])
|
||||
self.gguf_writer.add_sampling_temp(sampling["temp"])
|
||||
self.gguf_writer.add_sampling_penalty_repeat(sampling["penalty_repeat"])
|
||||
self.gguf_writer.add_sampling_penalty_last_n(PENALTY_LAST_N)
|
||||
if not self.is_turbo:
|
||||
self.gguf_writer.add_classifier_free_guidance(True)
|
||||
|
||||
def generate_extra_tensors(self) -> Iterable[tuple[str, Tensor]]:
|
||||
if self.is_turbo:
|
||||
return
|
||||
# llama3 rope scaling baked into the rope_freqs factors tensor
|
||||
rp = self.hparams["rope_scaling"]
|
||||
dim = self.hparams["head_dim"]
|
||||
base = self.hparams["rope_theta"]
|
||||
freqs = 1.0 / (base ** (torch.arange(0, dim, 2, dtype=torch.float32) / dim))
|
||||
factor = rp["factor"]
|
||||
low_freq_wavelen = rp["original_max_position_embeddings"] / rp["low_freq_factor"]
|
||||
high_freq_wavelen = rp["original_max_position_embeddings"] / rp["high_freq_factor"]
|
||||
rope_factors = []
|
||||
for freq in freqs:
|
||||
wavelen = 2 * math.pi / freq
|
||||
if wavelen < high_freq_wavelen:
|
||||
rope_factors.append(1)
|
||||
elif wavelen > low_freq_wavelen:
|
||||
rope_factors.append(factor)
|
||||
else:
|
||||
smooth = (rp["original_max_position_embeddings"] / wavelen - rp["low_freq_factor"]) / (rp["high_freq_factor"] - rp["low_freq_factor"])
|
||||
rope_factors.append(1 / ((1 - smooth) / factor + smooth))
|
||||
yield (self.format_tensor_name(gguf.MODEL_TENSOR.ROPE_FREQS), torch.tensor(rope_factors, dtype=torch.float32))
|
||||
|
||||
def _maybe_emit_fused(self) -> Iterable[tuple[str, Tensor]]:
|
||||
if self._text_embd is not None and self._speech_embd is not None:
|
||||
yield (self.format_tensor_name(gguf.MODEL_TENSOR.TOKEN_EMBD),
|
||||
torch.cat([self._text_embd, self._speech_embd], dim=0))
|
||||
self._text_embd = None
|
||||
self._speech_embd = None
|
||||
if self._text_head is not None and self._speech_head is not None:
|
||||
yield (self.format_tensor_name(gguf.MODEL_TENSOR.OUTPUT),
|
||||
torch.cat([self._text_head, self._speech_head], dim=0))
|
||||
self._text_head = None
|
||||
self._speech_head = None
|
||||
|
||||
def modify_tensors(self, data_torch: Tensor, name: str, bid: int | None) -> Iterable[tuple[str, Tensor]]:
|
||||
# generate_extra_tensors output comes back through here with its final name
|
||||
if name.startswith("rope_freqs"):
|
||||
yield (name, data_torch)
|
||||
return
|
||||
# fused [text | speech] vocab: embeddings and output head
|
||||
if name == "text_emb.weight":
|
||||
if not self.is_turbo:
|
||||
# the reference lowercases its input, the uppercase rows take the lowercase ones
|
||||
fold = list(range(data_torch.shape[0]))
|
||||
for upper, lower in self._mtl_case_fold_pairs():
|
||||
fold[upper] = lower
|
||||
data_torch = data_torch[torch.tensor(fold)]
|
||||
self._text_embd = data_torch
|
||||
yield from self._maybe_emit_fused()
|
||||
return
|
||||
if name == "speech_emb.weight":
|
||||
self._speech_embd = data_torch
|
||||
yield from self._maybe_emit_fused()
|
||||
return
|
||||
if name == "text_head.weight":
|
||||
self._text_head = data_torch
|
||||
yield from self._maybe_emit_fused()
|
||||
return
|
||||
if name == "speech_head.weight":
|
||||
self._speech_head = data_torch
|
||||
yield from self._maybe_emit_fused()
|
||||
return
|
||||
if name == "speech_head.bias":
|
||||
# the text head has no bias, its zone is suppressed at sampling anyway
|
||||
yield (self.format_tensor_name(gguf.MODEL_TENSOR.OUTPUT, suffix=".bias"), F.pad(data_torch, (self.hparams["vocab_size"], 0)))
|
||||
return
|
||||
|
||||
assert name.startswith("tfmr.")
|
||||
name = name[len("tfmr."):]
|
||||
|
||||
if self.is_turbo:
|
||||
# HF GPT-2 layout: Conv1D style weights are stored transposed
|
||||
if name.endswith((".c_attn.weight", ".c_proj.weight", ".c_fc.weight")):
|
||||
data_torch = data_torch.transpose(1, 0)
|
||||
yield (self.map_tensor_name(name), data_torch)
|
||||
return
|
||||
|
||||
if name.endswith("q_proj.weight"):
|
||||
data_torch = LlamaModel.permute(data_torch, self.hparams["num_attention_heads"], None)
|
||||
if name.endswith("k_proj.weight"):
|
||||
data_torch = LlamaModel.permute(data_torch, self.hparams["num_attention_heads"], self.hparams["num_key_value_heads"])
|
||||
yield (self.map_tensor_name("model." + name), data_torch)
|
||||
|
||||
|
||||
@ModelBase.register("ChatterboxModel")
|
||||
class ChatterboxMmprojModel(MmprojModel):
|
||||
has_vision_encoder = False
|
||||
has_audio_encoder = True
|
||||
|
||||
def __init__(self, dir_model: Path, *args, **kwargs):
|
||||
self.is_turbo = _is_turbo(dir_model)
|
||||
super().__init__(dir_model, *args, **kwargs)
|
||||
self._wnorm_g: dict[str, Tensor] = {}
|
||||
self._wnorm_v: dict[str, Tensor] = {}
|
||||
|
||||
def get_audio_config(self) -> dict[str, Any] | None:
|
||||
return self.global_config.get("audio_config")
|
||||
|
||||
def index_tensors(self, remote_hf_model_id: str | None = None) -> dict[str, Callable[[], Tensor]]:
|
||||
tensors: dict[str, Callable[[], Tensor]] = {}
|
||||
for prefix in (TURBO_S3GEN if self.is_turbo else MTL_S3GEN, VE, TURBO_TALKER if self.is_turbo else MTL_TALKER):
|
||||
tensors.update(self.index_local_tensors(prefix))
|
||||
return tensors
|
||||
|
||||
@classmethod
|
||||
def filter_tensors(cls, item: tuple[str, Callable[[], Tensor]]) -> tuple[str, Callable[[], Tensor]] | None:
|
||||
# the s3gen, ve and talker checkpoints have disjoint top-level names
|
||||
name, gen = item
|
||||
new_name: str | None = None
|
||||
# batchnorm bookkeeping (over the gguf name length cap) and the tokenizer dsp buffers are unused
|
||||
if name.endswith("num_batches_tracked") or name in ("tokenizer.window", "tokenizer._mel_filters"):
|
||||
return None
|
||||
for src, dst in (
|
||||
("flow.encoder.", "a.gen.fenc."),
|
||||
("flow.decoder.estimator.", "a.gen.est."),
|
||||
("mel2wav.", "a.gen.hift."),
|
||||
("speaker_encoder.", "a.spk."),
|
||||
("tokenizer.", "a.s3tok."),
|
||||
("flow.", "a.gen.flow."), # input_embedding, encoder_proj, spk_embed_affine_layer
|
||||
("lstm.", "a.ve.lstm."),
|
||||
("proj.", "a.ve.proj."),
|
||||
("cond_enc.", "a.cenc."),
|
||||
):
|
||||
if name.startswith(src):
|
||||
new_name = dst + name[len(src):]
|
||||
break
|
||||
if name == "text_pos_emb.emb.weight":
|
||||
new_name = "a.gen.t3.text_pos_emb"
|
||||
elif name == "speech_pos_emb.emb.weight":
|
||||
new_name = "a.gen.t3.speech_pos_emb"
|
||||
elif name == "speech_emb.weight":
|
||||
new_name = gguf.TENSOR_NAMES[gguf.MODEL_TENSOR.A_GEN_CODE_OUT_EMBD] + ".weight"
|
||||
if new_name is None:
|
||||
return None
|
||||
return super().filter_tensors((new_name, gen))
|
||||
|
||||
def set_gguf_parameters(self):
|
||||
self.gguf_writer.add_file_type(self.ftype)
|
||||
|
||||
# speaker encoder, the front-end hparams are hard-coded in tools/mtmd
|
||||
self.gguf_writer.add_clip_has_audio_encoder(True)
|
||||
self.gguf_writer.add_clip_audio_projector_type(gguf.VisionProjectorType.CHATTERBOX_SPKENC)
|
||||
self.gguf_writer.add_audio_projection_dim(80)
|
||||
self.gguf_writer.add_audio_num_mel_bins(80)
|
||||
self.gguf_writer.add_audio_block_count(0)
|
||||
self.gguf_writer.add_audio_embedding_length(192)
|
||||
self.gguf_writer.add_audio_head_count(1)
|
||||
self.gguf_writer.add_audio_feed_forward_length(192)
|
||||
self.gguf_writer.add_audio_attention_layernorm_eps(1e-5)
|
||||
|
||||
# audio generator (s3gen, chatterbox projector); the flow encoder shape
|
||||
self.gguf_writer.add_clip_has_gen_audio_encoder(True)
|
||||
self.gguf_writer.add_clip_gen_audio_projector_type(gguf.VisionProjectorType.CHATTERBOX)
|
||||
self.gguf_writer.add_gen_audio_projection_dim(80)
|
||||
self.gguf_writer.add_gen_audio_embedding_length(512)
|
||||
self.gguf_writer.add_gen_audio_feed_forward_length(2048)
|
||||
self.gguf_writer.add_gen_audio_block_count(6)
|
||||
self.gguf_writer.add_gen_audio_head_count(8)
|
||||
self.gguf_writer.add_gen_audio_attention_layernorm_eps(1e-5)
|
||||
|
||||
def _fuse_weight_norm(self, name: str, data_torch: Tensor) -> tuple[str, Tensor] | None:
|
||||
# torch weight_norm parametrization: weight = g * v / |v| over dims 1..n
|
||||
base = name.split(".parametrizations.weight.original")[0]
|
||||
if name.endswith("original0"):
|
||||
self._wnorm_g[base] = data_torch
|
||||
else:
|
||||
self._wnorm_v[base] = data_torch
|
||||
if base in self._wnorm_g and base in self._wnorm_v:
|
||||
g = self._wnorm_g.pop(base)
|
||||
v = self._wnorm_v.pop(base)
|
||||
norm = v.float().norm(dim=tuple(range(1, v.dim())), keepdim=True)
|
||||
return (base + ".weight", g.float() * v.float() / norm)
|
||||
return None
|
||||
|
||||
def modify_tensors(self, data_torch: Tensor, name: str, bid: int | None) -> Iterable[tuple[str, Tensor]]:
|
||||
if ".parametrizations.weight.original" in name:
|
||||
fused = self._fuse_weight_norm(name, data_torch)
|
||||
if fused is not None:
|
||||
yield fused
|
||||
return
|
||||
yield (name, data_torch)
|
||||
|
||||
def tensor_force_quant(self, name, new_name, bid, n_dims):
|
||||
del name, bid
|
||||
# tensors read on the host stay F32
|
||||
if new_name.startswith(("a.ve.", "a.cenc.", "voice.", "a.gen.t3.", "a.gen.hift.m_source.")):
|
||||
return gguf.GGMLQuantizationType.F32
|
||||
# the conv ops have no BF16 kernels
|
||||
if n_dims >= 2 and new_name.endswith((".weight", ".weight_v")):
|
||||
return gguf.GGMLQuantizationType.F16
|
||||
return gguf.GGMLQuantizationType.F32
|
||||
|
||||
def generate_extra_tensors(self) -> Iterable[tuple[str, Tensor]]:
|
||||
conds = torch.load(self.dir_model / "conds.pt", map_location="cpu", weights_only=True)
|
||||
t3c = conds["t3"] if isinstance(conds, dict) else conds.t3
|
||||
genc = conds["gen"] if isinstance(conds, dict) else conds.gen
|
||||
t3c = vars(t3c) if not isinstance(t3c, dict) else t3c
|
||||
genc = vars(genc) if not isinstance(genc, dict) else genc
|
||||
|
||||
def talker_tensor(name: str) -> Tensor:
|
||||
return LazyTorchTensor.to_eager(self.model_tensors[name]())
|
||||
|
||||
# the conds.pt voice: voice.default holds the talker conditioning rows, voice.default.ref_* the flow decoder reference
|
||||
# 1D tensors are written as F32, the speech ids stay exact
|
||||
yield ("voice.default.ref_tokens", genc["prompt_token"][0].float())
|
||||
yield ("voice.default.ref_feat", genc["prompt_feat"][0].float())
|
||||
yield ("voice.default.ref_spk", genc["embedding"][0].float())
|
||||
|
||||
spkr_w = talker_tensor("a.cenc.spkr_enc.weight").float()
|
||||
spkr_b = talker_tensor("a.cenc.spkr_enc.bias").float()
|
||||
spkr_row = spkr_w @ t3c["speaker_emb"][0].float() + spkr_b
|
||||
speech_emb = talker_tensor(self.format_tensor_name(gguf.MODEL_TENSOR.A_GEN_CODE_OUT_EMBD)).float()
|
||||
cond_tokens = t3c["cond_prompt_speech_tokens"][0]
|
||||
|
||||
if self.is_turbo:
|
||||
# turbo talker conditioning: [spkr, speech rows of the cond tokens]
|
||||
yield ("voice.default", torch.cat([spkr_row[None], speech_emb[cond_tokens]], dim=0))
|
||||
return
|
||||
|
||||
# multilingual talker conditioning [spkr, perceiver x32, emotion], from the reference perceiver over the cond speech tokens
|
||||
with torch.no_grad():
|
||||
speech_pos = talker_tensor("a.gen.t3.speech_pos_emb").float()
|
||||
pse = speech_emb[cond_tokens] + speech_pos[: cond_tokens.shape[0]]
|
||||
|
||||
ln_w = talker_tensor("a.cenc.perceiver.attn.norm.weight").float()
|
||||
ln_b = talker_tensor("a.cenc.perceiver.attn.norm.bias").float()
|
||||
wq = talker_tensor("a.cenc.perceiver.attn.to_q.weight").float()
|
||||
bq = talker_tensor("a.cenc.perceiver.attn.to_q.bias").float()
|
||||
wk = talker_tensor("a.cenc.perceiver.attn.to_k.weight").float()
|
||||
bk = talker_tensor("a.cenc.perceiver.attn.to_k.bias").float()
|
||||
wv = talker_tensor("a.cenc.perceiver.attn.to_v.weight").float()
|
||||
bv = talker_tensor("a.cenc.perceiver.attn.to_v.bias").float()
|
||||
wo = talker_tensor("a.cenc.perceiver.attn.proj_out.weight").float()
|
||||
bo = talker_tensor("a.cenc.perceiver.attn.proj_out.bias").float()
|
||||
query = talker_tensor("a.cenc.perceiver.pre_attention_query")[0].float()
|
||||
|
||||
n_head = 4
|
||||
n_e = query.shape[1]
|
||||
|
||||
def attn_block(x1: Tensor, x2: Tensor) -> Tensor:
|
||||
nx1 = F.layer_norm(x1, (n_e,), ln_w, ln_b)
|
||||
nx2 = F.layer_norm(x2, (n_e,), ln_w, ln_b)
|
||||
q = (nx1 @ wq.T + bq).view(-1, n_head, n_e // n_head).transpose(0, 1)
|
||||
k = (nx2 @ wk.T + bk).view(-1, n_head, n_e // n_head).transpose(0, 1)
|
||||
v = (nx2 @ wv.T + bv).view(-1, n_head, n_e // n_head).transpose(0, 1)
|
||||
ctx = F.scaled_dot_product_attention(q, k, v)
|
||||
ctx = ctx.transpose(0, 1).reshape(-1, n_e)
|
||||
return ctx @ wo.T + bo + x1
|
||||
|
||||
pre = attn_block(query, pse)
|
||||
p32 = attn_block(pre, pre)
|
||||
|
||||
emo = talker_tensor("a.cenc.emotion_adv_fc.weight").float()
|
||||
emo_row = emo[:, 0] * t3c["emotion_adv"].reshape(-1)[0]
|
||||
yield ("voice.default", torch.cat([spkr_row[None], p32, emo_row[None]], dim=0))
|
||||
@@ -0,0 +1,41 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Callable, Iterable, TYPE_CHECKING
|
||||
|
||||
from .base import ModelBase, gguf
|
||||
from .qwen import _LinearAttentionVReorderBase
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from torch import Tensor
|
||||
|
||||
|
||||
@ModelBase.register("CloverMoeModelLM")
|
||||
@ModelBase.example("Diffuspace/Clover-35B-A3B-Preview")
|
||||
class CloverMoeModel(_LinearAttentionVReorderBase):
|
||||
model_arch = gguf.MODEL_ARCH.CLOVER_MOE
|
||||
supports_mtp_export = False
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.no_mtp = True
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def set_vocab(self):
|
||||
self._set_vocab_gpt2()
|
||||
|
||||
def set_gguf_parameters(self):
|
||||
super().set_gguf_parameters()
|
||||
self.gguf_writer.add_expert_shared_count(self.hparams.get("num_shared_experts", 1))
|
||||
|
||||
@classmethod
|
||||
def filter_tensors(cls, item: tuple[str, Callable[[], Tensor]]) -> tuple[str, Callable[[], Tensor]] | None:
|
||||
name, _ = item
|
||||
if name.endswith((".conv_right_weight", ".bd_softmax_logit_scale", ".bd_softmax_history_bias", ".bd_softmax_history_c")):
|
||||
return None
|
||||
|
||||
return super().filter_tensors(item)
|
||||
|
||||
def modify_tensors(self, data_torch: Tensor, name: str, bid: int | None) -> Iterable[tuple[str, Tensor]]:
|
||||
if name.endswith(".A_log") or (name.endswith("norm.weight") and not name.endswith("linear_attn.norm.weight")):
|
||||
data_torch = data_torch.float()
|
||||
|
||||
yield from super().modify_tensors(data_torch, name, bid)
|
||||
@@ -1078,7 +1078,7 @@ class DeepseekV4FlashVisionModel(MmprojModel):
|
||||
self.gguf_writer.add_vision_use_silu(True) # SwiGLU MLP
|
||||
self.gguf_writer.add_vision_projector_scale_factor(self.hparams_vision["downsample_ratio"])
|
||||
self.gguf_writer.add_vision_min_pixels(self.hparams_vision["min_pixels"])
|
||||
# hardcoded on the C++ side (see PROJECTOR_TYPE_DEEPSEEK4V in clip.cpp)
|
||||
# hardcoded on the C++ side (see PROJECTOR_TYPE_DEEPSEEK4V in tools/mtmd)
|
||||
# if future models use different values, add GGUF keys for those
|
||||
assert self.global_config["vision_max_n_token"] == 384
|
||||
assert self.global_config["vision_max_wh_ratio"] == 8
|
||||
|
||||
@@ -458,7 +458,7 @@ class DeepseekV41VisionModel(DeepseekV4FlashVisionModel):
|
||||
self.gguf_writer.add_vision_use_silu(True)
|
||||
self.gguf_writer.add_vision_projector_scale_factor(self.hparams_vision["downsample_ratio"])
|
||||
self.gguf_writer.add_vision_min_pixels(self.hparams_vision["min_pixels"])
|
||||
# hardcoded in clip.cpp (PROJECTOR_TYPE_DEEPSEEK41V); add GGUF keys if a later model differs
|
||||
# hardcoded in tools/mtmd (PROJECTOR_TYPE_DEEPSEEK41V); add GGUF keys if a later model differs
|
||||
assert self.hparams_vision["max_image_tokens"] == 1024, self.hparams_vision["max_image_tokens"]
|
||||
assert self.hparams_vision["max_wh_ratio"] is None, self.hparams_vision["max_wh_ratio"]
|
||||
assert self.hparams_vision["rope_theta"] == 10000, self.hparams_vision["rope_theta"]
|
||||
|
||||
@@ -0,0 +1,251 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, Callable, Iterable, TYPE_CHECKING
|
||||
|
||||
import torch
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from torch import Tensor
|
||||
|
||||
from .base import ModelBase, MmprojModel, gguf
|
||||
from .qwen import Qwen3_5MoeTextModel
|
||||
|
||||
# Fish Audio Drama 3 (FishOmniModel)
|
||||
# text model: Qwen3.5-MoE backbone, samples the main token of each frame
|
||||
# mmproj: codebook tower and Fish DAC decoder (codec.pth)
|
||||
|
||||
_TOWER_SHARED = "audio_decoder_mtp_shared.layers."
|
||||
_TOWER_RESIDUAL = "audio_decoder_mtp.layers."
|
||||
|
||||
|
||||
@ModelBase.register("FishOmniModel")
|
||||
@ModelBase.example("fishaudio/drama-3")
|
||||
class Drama3TextModel(Qwen3_5MoeTextModel):
|
||||
model_arch = gguf.MODEL_ARCH.QWEN35MOE
|
||||
no_mtp = True # the checkpoint has no MTP head
|
||||
|
||||
@classmethod
|
||||
def filter_tensors(cls, item: tuple[str, Callable[[], Tensor]]) -> tuple[str, Callable[[], Tensor]] | None:
|
||||
if item[0].startswith("audio_decoder"):
|
||||
return None
|
||||
return super().filter_tensors(item)
|
||||
|
||||
|
||||
@ModelBase.register("FishOmniModel")
|
||||
@ModelBase.example("fishaudio/drama-3")
|
||||
class Drama3MmprojModel(MmprojModel):
|
||||
has_vision_encoder = False
|
||||
has_audio_encoder = False
|
||||
|
||||
_LAYER_MAP = {
|
||||
"enorm.weight": (gguf.MODEL_TENSOR.A_GEN_CODE_ENORM, True),
|
||||
"hnorm.weight": (gguf.MODEL_TENSOR.A_GEN_CODE_HNORM, True),
|
||||
"eh_proj.weight": (gguf.MODEL_TENSOR.A_GEN_CODE_EH_PROJ, False),
|
||||
"semantic_embedding.weight": (gguf.MODEL_TENSOR.A_GEN_CODE_BLK_EMBD, False),
|
||||
"codebook_embedding.weight": (gguf.MODEL_TENSOR.A_GEN_CODE_BLK_EMBD, False),
|
||||
"final_layernorm.weight": (gguf.MODEL_TENSOR.A_GEN_CODE_BLK_OUT_NORM, True),
|
||||
"transformer_layer.attention_norm.weight": (gguf.MODEL_TENSOR.A_GEN_CODE_ATTN_NORM, True),
|
||||
"transformer_layer.ffn_norm.weight": (gguf.MODEL_TENSOR.A_GEN_CODE_FFN_NORM, True),
|
||||
"transformer_layer.attention.q_norm.weight": (gguf.MODEL_TENSOR.A_GEN_CODE_ATTN_Q_NORM, True),
|
||||
"transformer_layer.attention.k_norm.weight": (gguf.MODEL_TENSOR.A_GEN_CODE_ATTN_K_NORM, True),
|
||||
"transformer_layer.attention.wo.weight": (gguf.MODEL_TENSOR.A_GEN_CODE_ATTN_OUT, False),
|
||||
"transformer_layer.feed_forward.w1.weight": (gguf.MODEL_TENSOR.A_GEN_CODE_FFN_GATE, False),
|
||||
"transformer_layer.feed_forward.w3.weight": (gguf.MODEL_TENSOR.A_GEN_CODE_FFN_UP, False),
|
||||
"transformer_layer.feed_forward.w2.weight": (gguf.MODEL_TENSOR.A_GEN_CODE_FFN_DOWN, False),
|
||||
}
|
||||
|
||||
_heads: dict[int, Tensor]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self._heads = {}
|
||||
|
||||
def get_audio_config(self) -> dict[str, Any] | None:
|
||||
cfg = dict(self.global_config["audio_decoder_config"])
|
||||
cfg["num_hidden_layers"] = cfg["shared_enrichment_layers"] + cfg["num_codebooks"] - 1
|
||||
return cfg
|
||||
|
||||
def set_gguf_parameters(self):
|
||||
cfg = self.hparams
|
||||
self.gguf_writer.add_file_type(self.ftype)
|
||||
self.gguf_writer.add_clip_has_gen_audio_encoder(True)
|
||||
self.gguf_writer.add_clip_gen_audio_projector_type(gguf.VisionProjectorType.DRAMA3_GEN)
|
||||
self.gguf_writer.add_gen_audio_projection_dim(self.n_embd_text)
|
||||
self.gguf_writer.add_gen_audio_embedding_length(cfg["dim"])
|
||||
self.gguf_writer.add_gen_audio_feed_forward_length(cfg["intermediate_size"])
|
||||
self.gguf_writer.add_gen_audio_block_count(cfg["num_hidden_layers"])
|
||||
self.gguf_writer.add_gen_audio_head_count(cfg["n_head"])
|
||||
self.gguf_writer.add_gen_audio_head_count_kv(cfg["n_local_heads"])
|
||||
self.gguf_writer.add_gen_audio_attention_layernorm_eps(cfg["norm_eps"])
|
||||
# other tower and codec hparams are hardcoded in tools/mtmd
|
||||
|
||||
@classmethod
|
||||
def filter_tensors(cls, item: tuple[str, Callable[[], Tensor]]) -> tuple[str, Callable[[], Tensor]] | None:
|
||||
name = item[0]
|
||||
if name.startswith("audio_decoder") or name == "model.language_model.embed_tokens.weight":
|
||||
return item
|
||||
return None
|
||||
|
||||
def tensor_force_quant(self, name, new_name, bid, n_dims):
|
||||
# conv1d/conv1d_dw kernels must be F16, ggml_conv_1d(_dw) has no BF16 path
|
||||
if new_name.endswith(".weight") and (
|
||||
new_name in ("a.gen.wav.dac.entry.weight", "a.gen.wav.dac.post_conv.weight")
|
||||
or (".up.blk." in new_name and new_name.endswith(".dwconv.weight"))
|
||||
or (".dac.blk." in new_name and (new_name.endswith(".conv1.weight") or new_name.endswith(".conv2.weight")))
|
||||
):
|
||||
return gguf.GGMLQuantizationType.F16
|
||||
# keep ConvTranspose1d kernels and folded codebook tables in F32
|
||||
if new_name.endswith(".conv.weight") and (".up.blk." in new_name or ".dac.blk." in new_name):
|
||||
return gguf.GGMLQuantizationType.F32
|
||||
if new_name.startswith("a.gen.wav.quant."):
|
||||
return gguf.GGMLQuantizationType.F32
|
||||
return super().tensor_force_quant(name, new_name, bid, n_dims)
|
||||
|
||||
def modify_tensors(self, data_torch: Tensor, name: str, bid: int | None) -> Iterable[tuple[str, Tensor]]:
|
||||
T = gguf.MODEL_TENSOR
|
||||
cfg = self.hparams
|
||||
|
||||
if name.startswith("a.gen.wav."):
|
||||
yield (name, data_torch)
|
||||
return
|
||||
|
||||
if name == "model.language_model.embed_tokens.weight":
|
||||
# semantic band of the backbone embeddings
|
||||
begin = self.global_config["semantic_start_token_id"]
|
||||
yield (self.format_tensor_name(T.A_GEN_CODE_OUT_EMBD), data_torch[begin:begin + cfg["vocab_size"]])
|
||||
return
|
||||
|
||||
if name == "audio_decoder.codebook_embeddings.weight":
|
||||
n_cb = cfg["num_codebooks"]
|
||||
yield (self.format_tensor_name(T.A_GEN_CODE_EMBD), data_torch.reshape(n_cb, -1, data_torch.shape[-1]))
|
||||
return
|
||||
|
||||
if name.startswith("audio_decoder_mtp.heads."):
|
||||
n_heads = cfg["num_codebooks"] - 1
|
||||
self._heads[int(name.split(".")[2])] = data_torch
|
||||
if len(self._heads) < n_heads:
|
||||
return
|
||||
yield (self.format_tensor_name(T.A_GEN_CODE_HEAD), torch.stack([self._heads.pop(i) for i in range(n_heads)]))
|
||||
return
|
||||
|
||||
for prefix, offset in ((_TOWER_SHARED, 0), (_TOWER_RESIDUAL, cfg["shared_enrichment_layers"])):
|
||||
if not name.startswith(prefix):
|
||||
continue
|
||||
idx, key = name[len(prefix):].split(".", 1)
|
||||
il = int(idx) + offset
|
||||
if key == "transformer_layer.attention.wqkv.weight":
|
||||
# rows are [query | gate | key | value]
|
||||
n_q = cfg["n_head"] * cfg["head_dim"]
|
||||
n_kv = cfg["n_local_heads"] * cfg["head_dim"]
|
||||
q, gate, k, v = data_torch.split([n_q, n_q, n_kv, n_kv], dim=0)
|
||||
yield (self.format_tensor_name(T.A_GEN_CODE_ATTN_Q, il), q)
|
||||
yield (self.format_tensor_name(T.A_GEN_CODE_ATTN_GATE, il), gate)
|
||||
yield (self.format_tensor_name(T.A_GEN_CODE_ATTN_K, il), k)
|
||||
yield (self.format_tensor_name(T.A_GEN_CODE_ATTN_V, il), v)
|
||||
return
|
||||
tensor, zero_centered = self._LAYER_MAP[key]
|
||||
if zero_centered:
|
||||
data_torch = data_torch.float() + 1
|
||||
yield (self.format_tensor_name(tensor, il), data_torch)
|
||||
return
|
||||
|
||||
raise ValueError(f"unexpected tensor {name}")
|
||||
|
||||
def generate_extra_tensors(self) -> Iterable[tuple[str, Tensor]]:
|
||||
# only the DAC decoder, the encoder is for voice cloning (not supported yet)
|
||||
sd = torch.load(self.dir_model / "codec.pth", map_location="cpu", mmap=True, weights_only=True)
|
||||
sd = sd.get("state_dict", sd)
|
||||
T = gguf.MODEL_TENSOR
|
||||
|
||||
def get(name: str) -> Tensor:
|
||||
return sd[name].float()
|
||||
|
||||
def conv(prefix: str) -> Tensor:
|
||||
# fold weight norm
|
||||
if prefix + ".conv.weight" in sd:
|
||||
return get(prefix + ".conv.weight")
|
||||
g = get(prefix + ".conv.parametrizations.weight.original0")
|
||||
v = get(prefix + ".conv.parametrizations.weight.original1")
|
||||
return g * v / v.norm(dim=(1, 2), keepdim=True)
|
||||
|
||||
def quant_table(prefix: str) -> Tensor:
|
||||
# fold out_proj into the codebook, so decoding is a row lookup
|
||||
g = get(prefix + ".out_proj.weight_g")
|
||||
v = get(prefix + ".out_proj.weight_v")
|
||||
w = (g * v / v.norm(dim=(1, 2), keepdim=True)).squeeze(-1)
|
||||
return get(prefix + ".codebook.weight") @ w.T + get(prefix + ".out_proj.bias")
|
||||
|
||||
def snake(alpha: Tensor) -> tuple[Tensor, Tensor]:
|
||||
alpha = alpha.flatten()
|
||||
return alpha, 1.0 / (alpha + 1e-9)
|
||||
|
||||
q = "quantizer."
|
||||
yield (self.format_tensor_name(T.A_GEN_WAV_QUANT_FIRST_CB), quant_table(q + "semantic_quantizer.quantizers.0"))
|
||||
n_rest = sum(1 for k in sd if k.startswith(q + "quantizer.quantizers.") and k.endswith(".codebook.weight"))
|
||||
yield (self.format_tensor_name(T.A_GEN_WAV_QUANT_REST_CB),
|
||||
torch.stack([quant_table(f"{q}quantizer.quantizers.{i}") for i in range(n_rest)]))
|
||||
|
||||
# post_module uses interleaved RoPE, permute q/k rows so NEOX RoPE gives the same result
|
||||
tfm = q + "post_module."
|
||||
n_head, d_head = 16, 64
|
||||
order = torch.cat([torch.arange(0, d_head, 2), torch.arange(1, d_head, 2)])
|
||||
|
||||
def neox_rows(w: Tensor) -> Tensor:
|
||||
return w.reshape(n_head, d_head, -1)[:, order].reshape(w.shape)
|
||||
|
||||
n_tfm = sum(1 for k in sd if k.startswith(tfm + "layers.") and k.endswith(".ffn_norm.weight"))
|
||||
for il in range(n_tfm):
|
||||
p = f"{tfm}layers.{il}."
|
||||
wq, wk, wv = get(p + "attention.wqkv.weight").chunk(3, dim=0)
|
||||
yield (self.format_tensor_name(T.A_GEN_WAV_TFM_ATTN_Q, il), neox_rows(wq))
|
||||
yield (self.format_tensor_name(T.A_GEN_WAV_TFM_ATTN_K, il), neox_rows(wk))
|
||||
yield (self.format_tensor_name(T.A_GEN_WAV_TFM_ATTN_V, il), wv)
|
||||
yield (self.format_tensor_name(T.A_GEN_WAV_TFM_ATTN_OUT, il), get(p + "attention.wo.weight"))
|
||||
yield (self.format_tensor_name(T.A_GEN_WAV_TFM_ATTN_NORM, il), get(p + "attention_norm.weight"))
|
||||
yield (self.format_tensor_name(T.A_GEN_WAV_TFM_ATTN_SCALE, il), get(p + "attention_layer_scale.gamma"))
|
||||
yield (self.format_tensor_name(T.A_GEN_WAV_TFM_FFN_NORM, il), get(p + "ffn_norm.weight"))
|
||||
yield (self.format_tensor_name(T.A_GEN_WAV_TFM_FFN_GATE, il), get(p + "feed_forward.w1.weight"))
|
||||
yield (self.format_tensor_name(T.A_GEN_WAV_TFM_FFN_UP, il), get(p + "feed_forward.w3.weight"))
|
||||
yield (self.format_tensor_name(T.A_GEN_WAV_TFM_FFN_DOWN, il), get(p + "feed_forward.w2.weight"))
|
||||
yield (self.format_tensor_name(T.A_GEN_WAV_TFM_FFN_SCALE, il), get(p + "ffn_layer_scale.gamma"))
|
||||
yield (self.format_tensor_name(T.A_GEN_WAV_TFM_OUTPUT_NORM), get(tfm + "norm.weight"))
|
||||
|
||||
# upsample: 2x (ConvTranspose1d + ConvNeXt)
|
||||
for il in range(2):
|
||||
p = f"{q}upsample.{il}."
|
||||
yield (self.format_tensor_name(T.A_GEN_WAV_UP_CONV, il, suffix=".weight"), conv(p + "0"))
|
||||
yield (self.format_tensor_name(T.A_GEN_WAV_UP_CONV, il, suffix=".bias"), get(p + "0.conv.bias"))
|
||||
yield (self.format_tensor_name(T.A_GEN_WAV_UP_DWCONV, il, suffix=".weight"), conv(p + "1.dwconv"))
|
||||
yield (self.format_tensor_name(T.A_GEN_WAV_UP_DWCONV, il, suffix=".bias"), get(p + "1.dwconv.conv.bias"))
|
||||
for key, tensor in (("norm", T.A_GEN_WAV_UP_NORM), ("pwconv1", T.A_GEN_WAV_UP_PW1), ("pwconv2", T.A_GEN_WAV_UP_PW2)):
|
||||
yield (self.format_tensor_name(tensor, il, suffix=".weight"), get(f"{p}1.{key}.weight"))
|
||||
yield (self.format_tensor_name(tensor, il, suffix=".bias"), get(f"{p}1.{key}.bias"))
|
||||
yield (self.format_tensor_name(T.A_GEN_WAV_UP_GAMMA, il, suffix=""), get(p + "1.gamma"))
|
||||
|
||||
# DAC: entry conv, 4x (Snake, ConvTranspose1d, 3 residual units), Snake, post conv
|
||||
d = "decoder.model."
|
||||
yield (self.format_tensor_name(T.A_GEN_WAV_DAC_ENTRY, suffix=".weight"), conv(d + "0"))
|
||||
yield (self.format_tensor_name(T.A_GEN_WAV_DAC_ENTRY, suffix=".bias"), get(d + "0.conv.bias"))
|
||||
for bid in range(4):
|
||||
p = f"{d}{bid + 1}.block."
|
||||
a, b = snake(get(p + "0.alpha"))
|
||||
yield (self.format_tensor_name(T.A_GEN_WAV_DAC_UP_SNAKE, bid, suffix=".alpha"), a)
|
||||
yield (self.format_tensor_name(T.A_GEN_WAV_DAC_UP_SNAKE, bid, suffix=".beta"), b)
|
||||
yield (self.format_tensor_name(T.A_GEN_WAV_DAC_UP_CONV, bid, suffix=".weight"), conv(p + "1"))
|
||||
yield (self.format_tensor_name(T.A_GEN_WAV_DAC_UP_CONV, bid, suffix=".bias"), get(p + "1.conv.bias"))
|
||||
for xid in range(3):
|
||||
r = f"{p}{xid + 2}.block."
|
||||
for act, tensor in (("0", T.A_GEN_WAV_DAC_RES_ACT1), ("2", T.A_GEN_WAV_DAC_RES_ACT2)):
|
||||
a, b = snake(get(r + act + ".alpha"))
|
||||
name = gguf.TENSOR_NAMES[tensor].format(bid=bid, xid=xid)
|
||||
yield (name + ".alpha", a)
|
||||
yield (name + ".beta", b)
|
||||
for cv, tensor in (("1", T.A_GEN_WAV_DAC_RES_CONV1), ("3", T.A_GEN_WAV_DAC_RES_CONV2)):
|
||||
name = gguf.TENSOR_NAMES[tensor].format(bid=bid, xid=xid)
|
||||
yield (name + ".weight", conv(r + cv))
|
||||
yield (name + ".bias", get(r + cv + ".conv.bias"))
|
||||
a, b = snake(get(d + "5.alpha"))
|
||||
yield (self.format_tensor_name(T.A_GEN_WAV_DAC_POST_SNAKE, suffix=".alpha"), a)
|
||||
yield (self.format_tensor_name(T.A_GEN_WAV_DAC_POST_SNAKE, suffix=".beta"), b)
|
||||
yield (self.format_tensor_name(T.A_GEN_WAV_DAC_POST_CONV, suffix=".weight"), conv(d + "6"))
|
||||
yield (self.format_tensor_name(T.A_GEN_WAV_DAC_POST_CONV, suffix=".bias"), get(d + "6.conv.bias"))
|
||||
@@ -343,3 +343,33 @@ class KimiK3Model(TextModel):
|
||||
return
|
||||
|
||||
yield from super().modify_tensors(data_torch, name, bid)
|
||||
|
||||
|
||||
@ModelBase.register("KimiK31ForConditionalGeneration")
|
||||
@ModelBase.example("moonshotai/Kimi-K3.1-Pro")
|
||||
class KimiK31Model(KimiK3Model):
|
||||
"""
|
||||
Kimi-K3.1: K3 with the full-attention MLA layers replaced by gated DSA.
|
||||
|
||||
The tensor set is K3's plus a lightning indexer per full-attention layer,
|
||||
and `dsa_config` adds the attention.indexer.* metadata.
|
||||
"""
|
||||
|
||||
model_arch = gguf.MODEL_ARCH.KIMI_K31
|
||||
|
||||
def set_gguf_parameters(self):
|
||||
super().set_gguf_parameters()
|
||||
|
||||
# --- DSA indexer ---
|
||||
dsa = self.hparams["dsa_config"]
|
||||
dsa_layers = dsa["dsa_layers"]
|
||||
# the layer lists are 1-indexed, like linear_attn_config's
|
||||
assert sorted(dsa_layers) == sorted(self.hparams["linear_attn_config"]["full_attn_layers"]), \
|
||||
"every full-attention layer is expected to own a DSA indexer"
|
||||
self.gguf_writer.add_indexer_head_count(dsa["index_num_heads"])
|
||||
self.gguf_writer.add_indexer_key_length(dsa["index_head_dim"])
|
||||
self.gguf_writer.add_indexer_top_k(dsa["index_topk"])
|
||||
self.gguf_writer.add_indexer_types([(il + 1) in dsa_layers
|
||||
for il in range(self.hparams["num_hidden_layers"])])
|
||||
# eps of the indexer key LayerNorm; the config declares no separate value
|
||||
self.gguf_writer.add_layer_norm_eps(dsa.get("index_norm_eps", self.hparams["rms_norm_eps"]))
|
||||
|
||||
+5
-5
@@ -181,11 +181,11 @@ class LFM3VLVisionMixin(MmprojModel):
|
||||
|
||||
def _set_lfm3vl_gguf_parameters(self):
|
||||
assert self.hparams_vision is not None
|
||||
# clip.cpp hardcodes the GELU projector and its input norm eps
|
||||
# mtmd hardcodes the GELU projector and its input norm eps
|
||||
if (self.global_config["projector_hidden_act"] != "gelu" or not self.global_config["projector_bias"]
|
||||
or self.global_config["projector_layer_norm_eps"] != 1e-6):
|
||||
raise ValueError("unsupported projector_hidden_act / projector_bias / projector_layer_norm_eps")
|
||||
# clip.cpp hardcodes the vision rope base, the RGB patchifier and the 3x3 spatial conv
|
||||
# mtmd hardcodes the vision rope base, the RGB patchifier and the 3x3 spatial conv
|
||||
if (self.hparams_vision["rope_parameters"]["rope_theta"] != 1e6 or self.hparams_vision["in_channels"] != 3
|
||||
or self.hparams_vision["conv_kernel_size"] != 3):
|
||||
raise ValueError("unsupported vision rope_theta / in_channels / conv_kernel_size")
|
||||
@@ -347,7 +347,7 @@ class LFM3AudioMmprojModel(MmprojModel):
|
||||
"feed_forward.w3": gguf.MODEL_TENSOR.A_GEN_WAV_TFM_FFN_UP,
|
||||
"feed_forward.w2": gguf.MODEL_TENSOR.A_GEN_WAV_TFM_FFN_DOWN,
|
||||
}
|
||||
# the codec graph in clip.cpp hardcodes the liquid-codec FSQ front end and decoder shape, conversion fails on a mismatch
|
||||
# the codec graph in mtmd hardcodes the liquid-codec FSQ front end and decoder shape, conversion fails on a mismatch
|
||||
_codec = {
|
||||
"model_type": "liquid_codec", "fsq_levels": [8, 7, 6, 6], "n_q": 12, "quantizer_dim": 256,
|
||||
"encoder_dim": 512, "stft_n_fft": 1280, "stft_hop_length": 320, "stft_win_length": 1280, "stft_frame_stack": 6,
|
||||
@@ -405,7 +405,7 @@ class LFM3AudioMmprojModel(MmprojModel):
|
||||
if fe[k] != v:
|
||||
raise ValueError(f"unsupported feature_extractor.{k}={fe[k]!r}, expected {v!r}")
|
||||
|
||||
# clip.cpp hardcodes the encoder rope base
|
||||
# mtmd hardcodes the encoder rope base
|
||||
if self.hparams_audio["rope_parameters"]["rope_theta"] != 1e6:
|
||||
raise ValueError("unsupported audio encoder rope_theta")
|
||||
|
||||
@@ -420,7 +420,7 @@ class LFM3AudioMmprojModel(MmprojModel):
|
||||
if not self._audio_output:
|
||||
return
|
||||
|
||||
# audio generation: depthformer hparams, the codec ones are constant and live in clip.cpp
|
||||
# audio generation: depthformer hparams, the codec ones are constant and live in mtmd
|
||||
gen = self.get_generation_config()
|
||||
for k, v in self._generation.items():
|
||||
if gen[k] != v:
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Callable, Iterable, TYPE_CHECKING
|
||||
|
||||
import torch
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from torch import Tensor
|
||||
|
||||
from .base import MmprojModel, ModelBase, gguf
|
||||
|
||||
|
||||
@ModelBase.register("LlavaOnevision2ForConditionalGeneration")
|
||||
@ModelBase.example("microsoft/Mage-VL-Cowork")
|
||||
class MageVLVisionModel(MmprojModel):
|
||||
# a rope pair uses 2 different angles: the graph runs 2 ropes on heads permuted to [evens | odds]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
assert self.hparams_vision is not None
|
||||
|
||||
self.n_embd = self.find_vparam(["hidden_size"])
|
||||
self.n_head = self.find_vparam(["num_attention_heads"])
|
||||
self.d_head = self.n_embd // self.n_head
|
||||
|
||||
d_half = self.d_head // 2
|
||||
assert d_half % 16 == 0, "the 4:6:6 split of the rope requires d_head to be a multiple of 32"
|
||||
|
||||
# 4:6:6 split for t:h:w
|
||||
n_t = 4 * (d_half // 16)
|
||||
n_s = 6 * (d_half // 16)
|
||||
theta = float(self.find_vparam(["rope_theta"]))
|
||||
freq_t = 1.0 / theta ** (torch.arange(n_t, dtype=torch.float64) / n_t)
|
||||
freq_s = 1.0 / theta ** (torch.arange(n_s, dtype=torch.float64) / n_s)
|
||||
freq = torch.cat([freq_t, freq_s, freq_s])
|
||||
self.rope_freq = torch.cat([freq, freq])
|
||||
|
||||
def pair_axis(i: int) -> int:
|
||||
dim = (2 * i) % d_half
|
||||
return 0 if dim < n_t else 1 if dim < n_t + n_s else 2
|
||||
|
||||
self.rope_pairs = sorted(range(d_half), key=pair_axis)
|
||||
|
||||
def set_gguf_parameters(self):
|
||||
super().set_gguf_parameters()
|
||||
self.gguf_writer.add_clip_projector_type(gguf.VisionProjectorType.MAGEVL)
|
||||
self.gguf_writer.add_vision_attention_layernorm_eps(self.find_vparam(["layer_norm_eps"]))
|
||||
self.gguf_writer.add_vision_spatial_merge_size(self.find_vparam(["spatial_merge_size"]))
|
||||
self.gguf_writer.add_vision_min_pixels(int(self.preprocessor_config["min_pixels"]))
|
||||
self.gguf_writer.add_vision_max_pixels(int(self.preprocessor_config["max_pixels"]))
|
||||
|
||||
@classmethod
|
||||
def filter_tensors(cls, item: tuple[str, Callable[[], Tensor]]) -> tuple[str, Callable[[], Tensor]] | None:
|
||||
name, _ = item
|
||||
|
||||
if not name.startswith("visual."):
|
||||
return None
|
||||
|
||||
return super().filter_tensors(item)
|
||||
|
||||
def generate_extra_tensors(self) -> Iterable[tuple[str, Tensor]]:
|
||||
# ggml uses theta = pos / rope_freqs
|
||||
pairs = torch.tensor(self.rope_pairs)
|
||||
freq_a = self.rope_freq[2 * pairs]
|
||||
freq_b = self.rope_freq[2 * pairs + 1]
|
||||
yield ("visual.rope_freqs.weight", (1.0 / torch.cat([freq_a, freq_b])).to(torch.float32))
|
||||
|
||||
def permute_qk(self, data_torch: Tensor) -> Tensor:
|
||||
rows = [2 * i for i in self.rope_pairs] + [2 * i + 1 for i in self.rope_pairs]
|
||||
return data_torch.reshape(self.n_head, self.d_head, -1)[:, rows].reshape(data_torch.shape)
|
||||
|
||||
def modify_tensors(self, data_torch: Tensor, name: str, bid: int | None) -> Iterable[tuple[str, Tensor]]:
|
||||
if ".self_attn.qkv." in name:
|
||||
q, k, v = data_torch.split(self.n_embd, dim=0)
|
||||
data_torch = torch.cat([self.permute_qk(q), self.permute_qk(k), v], dim=0)
|
||||
|
||||
yield from super().modify_tensors(data_torch, name, bid)
|
||||
@@ -0,0 +1,204 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
from typing import Callable, Iterable, TYPE_CHECKING
|
||||
|
||||
import torch
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from torch import Tensor
|
||||
|
||||
from .base import LazyTorchTensor, ModelBase, TextModel, gguf
|
||||
|
||||
|
||||
@ModelBase.register("Metis16ForCausalLM")
|
||||
class Metis16Model(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.METIS16
|
||||
|
||||
# read by generate_extra_tensors() or not used at inference: dropped in modify_tensors()
|
||||
_folded = {
|
||||
"pass_embeddings", "lm_head.weight", "depth_budget.multiplier",
|
||||
"depth_memory.pass_embeddings", "depth_memory.anchor_embeddings",
|
||||
"depth_memory.state_write.bias", "depth_memory.metadata_write.bias",
|
||||
}
|
||||
_folded_layer = {
|
||||
"mixer_connection.controller.weight", "mixer_connection.controller.bias", "mixer_connection.mix_logits",
|
||||
"mixer_connection.read_logits", "mixer_connection.write_logits",
|
||||
"moe_connection.controller.weight", "moe_connection.controller.bias", "moe_connection.mix_logits",
|
||||
"moe_connection.read_logits", "moe_connection.write_logits",
|
||||
"moe.k_router.weight", "moe.k_router.bias", "moe.k_budget.multiplier",
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
hp = self.hparams
|
||||
self.n_pass = hp["num_passes"]
|
||||
self.attn_layers = list(hp["attention_layer_indices"])
|
||||
self._generated: set[str] = set()
|
||||
# one cache slot per pass and layer, while the tensors exist once per physical layer
|
||||
self.block_count = self.n_pass * hp["num_hidden_layers"]
|
||||
|
||||
def set_vocab(self):
|
||||
self._set_vocab_gpt2()
|
||||
# turns end on the first eos id, so llama.cpp must stop on it too
|
||||
eos = self.hparams.get("eos_token_id")
|
||||
if isinstance(eos, list) and eos:
|
||||
self.gguf_writer.add_eot_token_id(eos[0])
|
||||
|
||||
def set_gguf_parameters(self):
|
||||
hp = self.hparams
|
||||
super().set_gguf_parameters()
|
||||
|
||||
n_layer = hp["num_hidden_layers"]
|
||||
self.gguf_writer.add_head_count_kv([hp["num_key_value_heads"] if il % n_layer in self.attn_layers else 0 for il in range(self.block_count)])
|
||||
|
||||
self.gguf_writer.add_expert_feed_forward_length(hp["expert_intermediate_size"])
|
||||
self.gguf_writer.add_expert_shared_feed_forward_length(hp["shared_expert_intermediate_size"])
|
||||
self.gguf_writer.add_expert_shared_count(1)
|
||||
self.gguf_writer.add_moe_latent_size(hp["latent_dim"])
|
||||
|
||||
d_inner = hp["mamba_expand"] * hp["hidden_size"]
|
||||
self.gguf_writer.add_ssm_conv_kernel(hp["mamba_d_conv"])
|
||||
self.gguf_writer.add_ssm_inner_size(d_inner)
|
||||
self.gguf_writer.add_ssm_state_size(hp["mamba_d_state"])
|
||||
self.gguf_writer.add_ssm_time_step_rank(d_inner // hp["mamba_head_dim"])
|
||||
self.gguf_writer.add_ssm_group_count(hp["mamba_n_groups"])
|
||||
self.gguf_writer.add_ssm_norm_epsilon(hp["mamba_norm_eps"])
|
||||
|
||||
self.gguf_writer.add_hyper_connection_count(hp["n_streams"])
|
||||
self.gguf_writer.add_metis_pass_count(self.n_pass)
|
||||
self.gguf_writer.add_metis_memory_length(hp["memory_dim"])
|
||||
self.gguf_writer.add_metis_route_length(hp["route_feature_dim"])
|
||||
self.gguf_writer.add_metis_continuation_logit_limit(hp["continuation_logit_limit"])
|
||||
self.gguf_writer.add_attention_pass_lora_rank(hp["attention_pass_lora_rank"])
|
||||
|
||||
@classmethod
|
||||
def filter_tensors(cls, item: tuple[str, Callable[[], Tensor]]) -> tuple[str, Callable[[], Tensor]] | None:
|
||||
name, gen = item
|
||||
# the checkpoint leaves these names suffix-less; add the suffix of the GGUF tensor so the mapper keeps it
|
||||
if name.endswith((".mixer.impl.mixer.dt_bias", ".moe.selection_bias")):
|
||||
name += ".bias"
|
||||
elif (name.endswith((".moe.expert_embeddings", ".mixer.pass_gates"))
|
||||
or name in ("depth_memory.stream_gate", "stream_embeddings")):
|
||||
name += ".weight"
|
||||
elif name == "depth_memory.stream_gate_bias":
|
||||
name = "depth_memory.stream_gate.bias"
|
||||
return super().filter_tensors((name, gen))
|
||||
|
||||
def _load(self, name: str) -> Tensor:
|
||||
return LazyTorchTensor.to_eager(self.model_tensors[name]())
|
||||
|
||||
def _emit(self, name: str, data: Tensor) -> tuple[str, Tensor]:
|
||||
self._generated.add(name)
|
||||
return name, data
|
||||
|
||||
def generate_extra_tensors(self) -> Iterable[tuple[str, Tensor]]:
|
||||
hp = self.hparams
|
||||
r = hp["route_feature_dim"]
|
||||
n_stream = hp["n_streams"]
|
||||
T = gguf.MODEL_TENSOR
|
||||
passes = self._load("pass_embeddings")[: self.n_pass]
|
||||
|
||||
# the mixes depend only on the weights and the pass, so Sinkhorn runs once here
|
||||
# the controller runs in the checkpoint dtype, as the reference does
|
||||
for il in range(hp["num_hidden_layers"]):
|
||||
for src, (mix, read, write) in (
|
||||
("mixer_connection", (T.HC_ATTN_MIX, T.HC_ATTN_READ, T.HC_ATTN_WRITE)),
|
||||
("moe_connection", (T.HC_FFN_MIX, T.HC_FFN_READ, T.HC_FFN_WRITE)),
|
||||
):
|
||||
prefix = f"layers.{il}.{src}."
|
||||
ctrl_w, ctrl_b = self._load(prefix + "controller.weight"), self._load(prefix + "controller.bias")
|
||||
mixes, reads, writes = [], [], []
|
||||
for p in range(self.n_pass):
|
||||
delta = torch.nn.functional.linear(passes[p].to(ctrl_w.dtype), ctrl_w, ctrl_b).float()
|
||||
m_delta, r_delta, w_delta = torch.split(delta, [n_stream * n_stream, n_stream, n_stream])
|
||||
log_m = self._load(prefix + "mix_logits").float() + m_delta.view(n_stream, n_stream)
|
||||
for _ in range(hp["mhc_sinkhorn_iterations"]):
|
||||
log_m = log_m - torch.logsumexp(log_m, dim=-1, keepdim=True)
|
||||
log_m = log_m - torch.logsumexp(log_m, dim=-2, keepdim=True)
|
||||
mixes.append(log_m.exp())
|
||||
reads.append(torch.softmax(self._load(prefix + "read_logits").float() + r_delta, dim=-1))
|
||||
writes.append(torch.softmax(self._load(prefix + "write_logits").float() + w_delta, dim=-1))
|
||||
act = ctrl_w.dtype
|
||||
yield self._emit(self.format_tensor_name(mix, il), torch.stack(mixes).to(act).float())
|
||||
yield self._emit(self.format_tensor_name(read, il), torch.stack(reads).to(act).float())
|
||||
yield self._emit(self.format_tensor_name(write, il), torch.stack(writes).to(act).float())
|
||||
|
||||
# one bias per memory entry: write biases, pass and anchor embeddings, and the constant routed width
|
||||
meta_w = self._load("depth_memory.metadata_write.weight").float()
|
||||
mean_k = hp["num_experts_per_tok"] / hp["max_routed_k"]
|
||||
base = (self._load("depth_memory.state_write.bias").float() + self._load("depth_memory.metadata_write.bias").float()
|
||||
+ mean_k * meta_w[:, r])
|
||||
pass_e = self._load("depth_memory.pass_embeddings").float()
|
||||
anchor_e = self._load("depth_memory.anchor_embeddings").float()
|
||||
n_anchor = len(self.attn_layers) + 1
|
||||
entry_bias = torch.stack([base + pass_e[p] + anchor_e[a] for p in range(self.n_pass) for a in range(n_anchor)])
|
||||
yield self._emit(self.format_tensor_name(T.DEPTH_MEM_ENTRY_BIAS), entry_bias)
|
||||
|
||||
def _split_features(self, data_torch: Tensor, template: str, parts: tuple[str, ...], d: int, bid: int | None) -> Iterable[tuple[str, Tensor]]:
|
||||
# the graph reads the concatenated features one block at a time; each block is its own tensor
|
||||
for i, part in enumerate(parts):
|
||||
piece = data_torch[:, i * d:(i + 1) * d] if i < 3 else data_torch[:, 3 * d:]
|
||||
yield from super().modify_tensors(piece, template.format(part), bid)
|
||||
|
||||
def modify_tensors(self, data_torch: Tensor, name: str, bid: int | None) -> Iterable[tuple[str, Tensor]]:
|
||||
if name in self._generated:
|
||||
yield name, data_torch
|
||||
return
|
||||
if name in self._folded:
|
||||
return
|
||||
hp = self.hparams
|
||||
d = hp["hidden_size"]
|
||||
|
||||
if bid is None:
|
||||
if name == "stream_embeddings.weight":
|
||||
# the graph keeps the streams innermost: [n_stream, n_embd, n_tokens]
|
||||
yield from super().modify_tensors(data_torch.T.contiguous(), name, bid)
|
||||
return
|
||||
if name == "depth_memory.metadata_write.weight":
|
||||
# metadata input becomes [summary, entropy, confidence, continuation]; entropy arrives unnormalized
|
||||
r = hp["route_feature_dim"]
|
||||
meta_w = data_torch.float()
|
||||
entropy_col = meta_w[:, r + 1:r + 2] / math.log(hp["n_routed_experts"])
|
||||
data_torch = torch.cat((meta_w[:, :r], entropy_col, meta_w[:, r + 2:]), dim=1)
|
||||
elif name == "depth_memory.stream_gate.weight":
|
||||
data_torch = data_torch.float() / math.sqrt(d)
|
||||
elif name == "depth_memory.route_projection.weight":
|
||||
yield from self._split_features(data_torch, "depth_memory.route_{}.weight", ("state", "retr", "diff", "hist"), d, bid)
|
||||
return
|
||||
elif name == "continuation.hidden.weight":
|
||||
yield from self._split_features(data_torch, "continuation.hidden_{}.weight", ("state", "retr", "diff", "route"), d, bid)
|
||||
return
|
||||
yield from super().modify_tensors(data_torch, name, bid)
|
||||
return
|
||||
|
||||
local = name.removeprefix(f"layers.{bid}.")
|
||||
if local in self._folded_layer:
|
||||
return
|
||||
|
||||
if local == "mixer.impl.mixer.A_log":
|
||||
data_torch = -torch.exp(data_torch).unsqueeze(-1)
|
||||
elif local == "mixer.impl.mixer.D":
|
||||
data_torch = data_torch.unsqueeze(-1)
|
||||
elif local == "mixer.impl.mixer.conv1d.weight":
|
||||
data_torch = data_torch.squeeze(1)
|
||||
elif local == "mixer.impl.mixer.norm.weight":
|
||||
data_torch = data_torch.reshape(hp["mamba_n_groups"], -1)
|
||||
elif local == "mixer.pass_gates.weight":
|
||||
# the reference applies tanh(gate) in the checkpoint dtype
|
||||
data_torch = torch.tanh(data_torch[: self.n_pass]).to(torch.bfloat16).float()
|
||||
elif local == "moe.shared_expert.gate_up.weight":
|
||||
gate, up = data_torch.chunk(2, dim=0)
|
||||
yield from super().modify_tensors(gate, name.replace("gate_up", "gate"), bid)
|
||||
yield from super().modify_tensors(up, name.replace("gate_up", "up"), bid)
|
||||
return
|
||||
|
||||
yield from super().modify_tensors(data_torch, name, bid)
|
||||
|
||||
def tensor_force_quant(self, name: str, new_name: str, bid: int | None, n_dims: int) -> gguf.GGMLQuantizationType | bool:
|
||||
# FP32 in the checkpoint, tiny and read as rows, or computed here at full precision: keep FP32
|
||||
if (new_name.startswith(("cont_", "depth_mem_entry_bias", "depth_mem_stream_gate"))
|
||||
or new_name.endswith(("ffn_exp_embd.weight", "ffn_gate_inp.weight", "hc_attn_mix.weight", "hc_attn_read.weight",
|
||||
"hc_attn_write.weight", "hc_ffn_mix.weight", "hc_ffn_read.weight", "hc_ffn_write.weight"))):
|
||||
return gguf.GGMLQuantizationType.F32
|
||||
return super().tensor_force_quant(name, new_name, bid, n_dims)
|
||||
@@ -161,7 +161,7 @@ class MiniCPMV4_6VisionModel(MmprojModel):
|
||||
# In MiniCPM-V 4.6 `vision_config.image_size` (980) describes the SigLIP
|
||||
# positional embedding bucket grid (70 x 70), while the per-slice processing
|
||||
# resolution is the preprocessor's `scale_resolution` (typically 448).
|
||||
# The CLIP loader in tools/mtmd/clip.cpp consumes `clip.vision.image_size`
|
||||
# The mmproj loader in tools/mtmd/mtmd-model.cpp consumes `clip.vision.image_size`
|
||||
# as the slice size and warmup resolution, so report `scale_resolution` there
|
||||
# to match the upstream MiniCPMV4_6ImageProcessorPil slicing rules.
|
||||
scale_resolution = self.preprocessor_config.get(
|
||||
@@ -173,7 +173,7 @@ class MiniCPMV4_6VisionModel(MmprojModel):
|
||||
super().set_gguf_parameters()
|
||||
assert self.hparams_vision is not None
|
||||
|
||||
# projector type string is consumed by clip_projector_type_from_string() in clip.cpp
|
||||
# projector type string is consumed by projector_type_from_string() in tools/mtmd/mtmd-impl.h
|
||||
self.gguf_writer.add_clip_projector_type(self.projector_type)
|
||||
|
||||
self.gguf_writer.add_vision_projector_scale_factor(
|
||||
@@ -243,7 +243,7 @@ class MiniCPMV4_7VisionModel(MiniCPMV4_6VisionModel):
|
||||
projector_type = gguf.VisionProjectorType.MINICPMV4_7
|
||||
# MiniCPMV4_7ImageProcessorPil default
|
||||
default_scale_resolution = 448
|
||||
# rows of v.tok_embd_sep, the order must match clip_suffix_rows() in clip-impl.h
|
||||
# rows of v.tok_embd_sep, the order must match mtmd_suffix_rows() in tools/mtmd/mtmd-impl.h
|
||||
tok_embd_sep = ["</image>", "<slice>", "</slice>", "\n"]
|
||||
|
||||
def get_downsample_mode(self) -> str:
|
||||
|
||||
+148
-3
@@ -208,7 +208,7 @@ class NemotronNanoV2VLModel(MmprojModel):
|
||||
return name, gen
|
||||
|
||||
def modify_tensors(self, data_torch: Tensor, name: str, bid: int | None) -> Iterable[tuple[str, Tensor]]:
|
||||
# RADIO's pos_embed doesn't have .weight suffix, but clip.cpp expects it
|
||||
# RADIO's pos_embed doesn't have .weight suffix, but mtmd expects it
|
||||
if "patch_generator.pos_embed" in name:
|
||||
# Downsample position embeddings for fixed 512x512 image size
|
||||
import torch.nn.functional as F
|
||||
@@ -428,6 +428,9 @@ class NemotronHModel(GraniteHybridModel):
|
||||
is_moe: bool = False
|
||||
supports_mtp_export = True
|
||||
_experts: list[dict[str, Tensor]] | None = None
|
||||
# tokens past the embedding rows (left out of the vocab), and special tokens that are printed as text
|
||||
_vocab_skip: tuple[str, ...] = ()
|
||||
_user_defined_tokens: re.Pattern[str] | None = None
|
||||
|
||||
_SSM_LAYER_TYPES = {"mamba", "linear_attention"}
|
||||
_ATTN_LAYER_TYPES = {"attention", "full_attention"}
|
||||
@@ -616,7 +619,11 @@ class NemotronHModel(GraniteHybridModel):
|
||||
vocab_size = -(vocab_size // -pad_vocab) * pad_vocab
|
||||
self.hparams["vocab_size"] = vocab_size
|
||||
|
||||
assert max(tokenizer.vocab.values()) < vocab_size # ty: ignore[unresolved-attribute]
|
||||
# draft-model converters (DFlash, LiLiCorr) call this with their own instance, which has neither hook
|
||||
vocab_skip = getattr(self, "_vocab_skip", ())
|
||||
user_defined_tokens = getattr(self, "_user_defined_tokens", None)
|
||||
|
||||
assert max(id_ for tok, id_ in tokenizer.vocab.items() if tok not in vocab_skip) < vocab_size # ty: ignore[unresolved-attribute]
|
||||
|
||||
tokpre = self.get_vocab_base_pre(tokenizer)
|
||||
|
||||
@@ -638,7 +645,8 @@ class NemotronHModel(GraniteHybridModel):
|
||||
if previous_token != token:
|
||||
logger.info(f"{repr(previous_token)} is encoded and decoded back to {repr(token)} using AutoTokenizer")
|
||||
|
||||
if added_tokens_decoder[i].special or self.does_token_look_special(token):
|
||||
printed = user_defined_tokens is not None and user_defined_tokens.fullmatch(token)
|
||||
if (added_tokens_decoder[i].special or self.does_token_look_special(token)) and not printed:
|
||||
toktypes.append(gguf.TokenType.CONTROL)
|
||||
else:
|
||||
token = token.replace(b"\xe2\x96\x81".decode("utf-8"), " ") # pre-normalize user-defined spaces
|
||||
@@ -834,3 +842,140 @@ class NemotronHPuzzleModel(NemotronHModel):
|
||||
if item[0].startswith("mtp."):
|
||||
return None
|
||||
return super().filter_tensors(item)
|
||||
|
||||
|
||||
# NeMo speechlm2 SALM checkpoint: a Nemotron-H decoder under llm.*, the speech encoder under perception.*
|
||||
@ModelBase.register("Nemotron3_5TranscribeForConditionalGeneration")
|
||||
@ModelBase.example("nvidia/NVIDIA-Nemotron-3.5-Transcribe-30B-A4B")
|
||||
class NemotronTranscribeModel(NemotronHModel):
|
||||
model_arch = gguf.MODEL_ARCH.NEMOTRON_H
|
||||
# the audio placeholder (id vocab_size) has no embedding row; speaker, event and style tags print with the transcript
|
||||
_vocab_skip = ("<|audio|>",)
|
||||
_user_defined_tokens = re.compile(r"<spk:\d+>|<ev:[a-z_]+>|<sty:(?:stt|end):[a-z_]+>")
|
||||
_renames = {
|
||||
"llm.model.embed_tokens.weight": "backbone.embeddings.weight",
|
||||
"llm.model.norm.weight": "backbone.norm_f.weight",
|
||||
"llm.lm_head.weight": "lm_head.weight",
|
||||
}
|
||||
# grouped experts: [n_expert, n_in, n_out] -> [n_expert, n_out, n_in]
|
||||
_grouped_experts = {"gate_and_up_projs": "up_proj", "down_projs": "down_proj"}
|
||||
|
||||
@classmethod
|
||||
def filter_tensors(cls, item: tuple[str, Callable[[], Tensor]]) -> tuple[str, Callable[[], Tensor]] | None:
|
||||
name, gen = item
|
||||
if name.startswith(("perception.", "ctc_timestamp.")) or "_extra_state" in name:
|
||||
return None
|
||||
if not name.startswith("llm."):
|
||||
# the FP8 and NVFP4 releases store the decoder as backbone.*
|
||||
raise ValueError(f"unexpected tensor {name}: only the BF16 checkpoint layout (llm.*) is supported")
|
||||
if name in cls._renames:
|
||||
name = cls._renames[name]
|
||||
elif name.startswith("llm.model.layers."):
|
||||
name = "backbone.layers." + name[len("llm.model.layers."):]
|
||||
elif name.startswith("llm.mtp.layers."):
|
||||
name = "mtp.layers." + name[len("llm.mtp.layers."):]
|
||||
else:
|
||||
raise ValueError(f"unexpected decoder tensor {name}")
|
||||
return super().filter_tensors((name.replace("._fp32_params.", "."), gen))
|
||||
|
||||
def modify_tensors(self, data_torch: Tensor, name: str, bid: int | None) -> Iterable[tuple[str, Tensor]]:
|
||||
leaf = name.rsplit(".", 1)[-1]
|
||||
if ".mixer.experts." in name and leaf in self._grouped_experts:
|
||||
if name.startswith("mtp."):
|
||||
assert self._mtp_bid is not None, f"{name}: MTP head is not exported"
|
||||
bid = self._mtp_bid
|
||||
assert bid is not None
|
||||
data_torch = data_torch.permute(0, 2, 1).contiguous()
|
||||
name = f"model.layers.{bid}.mlp.experts.{self._grouped_experts[leaf]}.weight"
|
||||
yield from ModelBase.modify_tensors(self, data_torch, name, bid)
|
||||
return
|
||||
yield from super().modify_tensors(data_torch, name, bid)
|
||||
|
||||
|
||||
@ModelBase.register("Nemotron3_5TranscribeForConditionalGeneration")
|
||||
class NemotronTranscribeAudioModel(MmprojModel):
|
||||
# NeMo ParallelExpertEncoder: ASR and speaker transformers, speaker activity fused into the ASR states
|
||||
has_vision_encoder = False
|
||||
has_audio_encoder = True
|
||||
|
||||
def get_audio_config(self) -> dict[str, Any] | None:
|
||||
asr = self.global_config["pe_encoder_config"]["asr_encoder_cfg"]
|
||||
return {
|
||||
"hidden_size": asr["d_model"],
|
||||
"intermediate_size": int(float(asr.get("ff_expansion", 4)) * asr["d_model"]),
|
||||
"num_hidden_layers": asr["n_layers"],
|
||||
"num_attention_heads": asr["n_heads"],
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _rope_dims(cfg: dict[str, Any]) -> int:
|
||||
assert cfg.get("self_attention_model") == "rope" and cfg.get("subsampling", "feature_stacking") == "feature_stacking"
|
||||
assert cfg.get("attn_mode", "full") == "full" and not cfg.get("xscaling", False) and cfg.get("pre_block_norm", True)
|
||||
assert float(cfg.get("rope_base", 10000.0)) == 10000.0
|
||||
n_rot = int(cfg["d_model"] // cfg["n_heads"] * float(cfg.get("rotary_fraction", 1.0)))
|
||||
assert n_rot >= 2 and n_rot % 2 == 0
|
||||
return n_rot
|
||||
|
||||
def set_gguf_parameters(self):
|
||||
super().set_gguf_parameters()
|
||||
pe = self.global_config["pe_encoder_config"]
|
||||
asr = pe["asr_encoder_cfg"]
|
||||
diar = pe["diarization_model_cfg"]
|
||||
spk = diar["encoder"]
|
||||
assert pe.get("asr_encoder_type") == "transformer" and pe.get("speaker_feature_mode", "thresholded") == "thresholded"
|
||||
assert pe.get("asr_normalize_type") == "per_feature" and pe.get("diar_normalize_type") in (None, "NA")
|
||||
assert asr["subsampling_factor"] == spk["subsampling_factor"] == 8 and asr["feat_in"] == spk["feat_in"]
|
||||
assert self._rope_dims(spk) == spk["d_model"] // spk["n_heads"] and not spk.get("qkv_bias", False)
|
||||
assert diar.get("high_resolution", False)
|
||||
# constants in clip: the ParallelExpertEncoder online settings and the Sortformer streaming config
|
||||
assert (pe.get("online_inference_length", 500), pe.get("chunk_left_context", 50), pe.get("chunk_right_context", 50),
|
||||
pe.get("diar_spkcache_len", 188), pe.get("diar_fifo_len", 40), pe.get("diar_spkcache_update_period", 300),
|
||||
pe.get("speaker_activity_threshold", 0.5)) == (500, 50, 50, 188, 40, 300, 0.5), \
|
||||
"streaming settings differ from the constants in tools/mtmd/models/nemotron-transcribe.cpp"
|
||||
sm = diar["sortformer_modules"]
|
||||
assert (sm["spkcache_sil_frames_per_spk"], sm["pred_score_threshold"], sm["scores_boost_latest"], sm["strong_boost_rate"],
|
||||
sm["weak_boost_rate"], sm["min_pos_scores_rate"], sm["use_learnable_sil_emb"]) == (1, 0.25, 0.05, 0.75, 1.5, 0.5, True), \
|
||||
"speaker cache settings differ from the constants in tools/mtmd/models/nemotron-transcribe.cpp"
|
||||
|
||||
self.gguf_writer.add_clip_projector_type(gguf.VisionProjectorType.NEMOTRON_TRANSCRIBE)
|
||||
self.gguf_writer.add_audio_num_mel_bins(asr["feat_in"])
|
||||
self.gguf_writer.add_audio_attention_layernorm_eps(1e-5)
|
||||
self.gguf_writer.add_audio_subsampling_factor(asr["subsampling_factor"])
|
||||
self.gguf_writer.add_audio_rope_dims(self._rope_dims(asr))
|
||||
self.gguf_writer.add_audio_spk_block_count(spk["n_layers"])
|
||||
self.gguf_writer.add_audio_spk_head_count(spk["n_heads"])
|
||||
|
||||
def generate_extra_tensors(self) -> Iterable[tuple[str, Tensor]]:
|
||||
# ParallelExpertEncoder._build_sinusoid_position_encoding
|
||||
pe = self.global_config["pe_encoder_config"]
|
||||
n_spk = int(pe["diarization_model_cfg"]["sortformer_modules"]["num_spks"])
|
||||
d = int(pe["asr_encoder_cfg"]["d_model"])
|
||||
scale = float(pe.get("spk_kernel_scale", 1.0))
|
||||
pos = torch.arange(n_spk, dtype=torch.float32)[:, None]
|
||||
div = torch.exp(torch.arange(0, d, 2, dtype=torch.float32) * -(np.log(10000.0) / d))
|
||||
kernel = torch.zeros(n_spk, d, dtype=torch.float32)
|
||||
kernel[:, 0::2] = torch.sin(pos * div)
|
||||
kernel[:, 1::2] = torch.cos(pos * div)
|
||||
# stored as [d, n_spk]: the graph multiplies it with the speaker activity directly
|
||||
yield self.format_tensor_name(gguf.MODEL_TENSOR.A_FUSION_SPK_KERNEL, suffix=""), (kernel * scale).T.contiguous()
|
||||
|
||||
def tensor_force_quant(self, name, new_name, bid, n_dims):
|
||||
if self.match_model_tensor_name(new_name, gguf.MODEL_TENSOR.A_SPK_HEAD_UPSAMPLE, None):
|
||||
return gguf.GGMLQuantizationType.F16 # ggml_conv_1d kernel
|
||||
return super().tensor_force_quant(name, new_name, bid, n_dims)
|
||||
|
||||
@classmethod
|
||||
def filter_tensors(cls, item: tuple[str, Callable[[], Tensor]]) -> tuple[str, Callable[[], Tensor]] | None:
|
||||
name, gen = item
|
||||
if not name.startswith("perception.") or "_extra_state" in name:
|
||||
return None
|
||||
# training-only head; the speaker model's unused front end
|
||||
if name.startswith(("perception.encoder.diarization_model.sortformer_modules.hidden_to_spks.",
|
||||
"perception.encoder.diarization_model.preprocessor.")):
|
||||
return None
|
||||
return name, gen
|
||||
|
||||
def modify_tensors(self, data_torch: Tensor, name: str, bid: int | None) -> Iterable[tuple[str, Tensor]]:
|
||||
if name == "perception.preprocessor.featurizer.fb":
|
||||
data_torch = data_torch.squeeze(0)
|
||||
yield from super().modify_tensors(data_torch, name, bid)
|
||||
|
||||
+159
-12
@@ -5,6 +5,7 @@ from pathlib import Path
|
||||
from typing import Any, Iterable, TYPE_CHECKING
|
||||
|
||||
import torch
|
||||
import torch.nn.functional as F
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from torch import Tensor
|
||||
@@ -45,6 +46,102 @@ def _tensor_shapes(dir_model: Path) -> dict[str, tuple[int, ...]]:
|
||||
return {name: tuple(part[name].shape) for name in part.keys()}
|
||||
|
||||
|
||||
def _has_voice_encoder(dir_model: Path) -> bool:
|
||||
# without voice cloning, the mimi encoder weights are all zero
|
||||
part_names = ModelBase.get_model_part_names(dir_model, "model", ".safetensors")
|
||||
with gguf.utility.SafetensorsLocal(dir_model / part_names[0]) as part:
|
||||
nonzero = {bool(part[name].mmap_bytes().any()) for name in part.keys() if name.startswith("mimi.encoder")}
|
||||
if len(nonzero) != 1:
|
||||
raise ValueError(f"{dir_model}: the mimi encoder is partly zeroed out")
|
||||
return nonzero.pop()
|
||||
|
||||
|
||||
def _load_safetensors(path: Path, prefixes: tuple[str, ...]) -> dict[str, Tensor]:
|
||||
dtypes = {"F32": torch.float32, "BF16": torch.bfloat16, "I64": torch.int64}
|
||||
with gguf.utility.SafetensorsLocal(path) as part:
|
||||
return {name: torch.from_numpy(part[name].mmap_bytes()).view(dtypes[part[name].dtype]).reshape(part[name].shape)
|
||||
for name in part.keys() if name.startswith(prefixes)}
|
||||
|
||||
|
||||
def _rope_pairs(x: Tensor, n_head: int, rope_theta: float) -> Tensor:
|
||||
# ggml NORM mode rope, x: [n_pos, n_embd]
|
||||
n_pos, n_embd = x.shape
|
||||
head_dim = n_embd // n_head
|
||||
angle = torch.arange(n_pos, dtype=x.dtype)[:, None, None] * \
|
||||
torch.pow(rope_theta, -torch.arange(0, head_dim, 2, dtype=x.dtype) / head_dim)
|
||||
x = x.view(n_pos, n_head, head_dim // 2, 2)
|
||||
return torch.stack([x[..., 0] * angle.cos() - x[..., 1] * angle.sin(),
|
||||
x[..., 0] * angle.sin() + x[..., 1] * angle.cos()], -1).reshape(n_pos, n_embd)
|
||||
|
||||
|
||||
def _voice_prompt_embd(weights: dict[str, Tensor], kv: list[Tensor], n_head: int, rope_theta: float) -> tuple[Tensor, float]:
|
||||
# the voice state only has K/V of each layer (kv[il] is [k/v, pos, n_embd]): layer 0 V gives each frame up to its scale, layer 1 V gives the scale
|
||||
# returns the frames without bos_before_voice, and the max relative K/V error when the frames are prompted again
|
||||
w = {name: t.double() for name, t in weights.items()}
|
||||
kv = [t.double() for t in kv]
|
||||
k0, v0, v1 = kv[0][0], kv[0][1], kv[1][1]
|
||||
n_pos, n_embd = v0.shape
|
||||
head_dim = n_embd // n_head
|
||||
|
||||
def p(il: int, name: str) -> Tensor:
|
||||
return w[f"flow_lm.transformer.layers.{il}.{name}"]
|
||||
|
||||
def norm(x: Tensor, il: int, name: str) -> Tensor:
|
||||
return F.layer_norm(x, (n_embd,), p(il, f"{name}.weight"), p(il, f"{name}.bias"), 1e-5)
|
||||
|
||||
def heads(t: Tensor) -> Tensor:
|
||||
return t.reshape(n_pos, n_head, head_dim).transpose(0, 1)
|
||||
|
||||
def rows(t: Tensor) -> Tensor:
|
||||
return t.transpose(0, 1).reshape(n_pos, n_embd)
|
||||
|
||||
def attn(il: int, h: Tensor, k: Tensor, v: Tensor) -> Tensor:
|
||||
q = _rope_pairs(h @ p(il, "self_attn.in_proj.weight").chunk(3)[0].T, n_head, rope_theta)
|
||||
return rows(F.scaled_dot_product_attention(heads(q), heads(k), heads(v), is_causal=True)) @ p(il, "self_attn.out_proj.weight").T
|
||||
|
||||
def ffn(il: int, x: Tensor) -> Tensor:
|
||||
return F.gelu(norm(x, il, "norm2") @ p(il, "linear1.weight").T) @ p(il, "linear2.weight").T
|
||||
|
||||
wv = p(0, "self_attn.in_proj.weight").chunk(3)[2]
|
||||
h = torch.linalg.solve(wv, v0.T).T # norm1(x)
|
||||
z = (h - p(0, "norm1.bias")) / p(0, "norm1.weight") # (x - mean(x)) / std(x)
|
||||
|
||||
# fit z on [speaker_proj, 1] to get the latent direction back
|
||||
proj = w["flow_lm.speaker_proj_weight"]
|
||||
fit = torch.linalg.lstsq(torch.cat([proj, torch.ones(n_embd, 1, dtype=proj.dtype)], 1), z[1:].T).solution
|
||||
frames = (proj @ fit[:-1]).T
|
||||
|
||||
a0 = attn(0, h, k0, v0)[1:]
|
||||
wv1 = p(1, "self_attn.in_proj.weight").chunk(3)[2]
|
||||
|
||||
def err(scale: Tensor) -> Tensor: # per frame relative error of layer 1 V
|
||||
x = scale[:, None] * frames + a0
|
||||
x = x + ffn(0, x)
|
||||
return (norm(x, 1, "norm1") @ wv1.T - v1[1:]).norm(dim=1) / v1[1:].norm(dim=1)
|
||||
|
||||
grid = torch.logspace(-3, 3, 49, dtype=torch.float64)
|
||||
best = torch.stack([err(s.expand(n_pos - 1)) for s in grid]).argmin(0)
|
||||
lo, hi = grid[(best - 1).clamp(min=0)], grid[(best + 1).clamp(max=len(grid) - 1)]
|
||||
for _ in range(40): # golden section search, all frames at once
|
||||
m1, m2 = hi - 0.618 * (hi - lo), lo + 0.618 * (hi - lo)
|
||||
left = err(m1) < err(m2)
|
||||
lo, hi = torch.where(left, lo, m1), torch.where(left, m2, hi)
|
||||
frames = (lo + hi)[:, None] / 2 * frames
|
||||
|
||||
# prompt the frames again and compare K/V with the shipped state
|
||||
x = torch.cat([w["flow_lm.bos_before_voice"].reshape(1, n_embd), frames])
|
||||
drift = 0.0
|
||||
for il, (k_ref, v_ref) in enumerate(kv):
|
||||
h = norm(x, il, "norm1")
|
||||
_, wk, wv = p(il, "self_attn.in_proj.weight").chunk(3)
|
||||
k, v = _rope_pairs(h @ wk.T, n_head, rope_theta), h @ wv.T
|
||||
for a, b in ((k, k_ref), (v, v_ref)):
|
||||
drift = max(drift, ((a - b).norm(dim=1) / b.norm(dim=1)).median().item())
|
||||
x = x + attn(il, h, k, v)
|
||||
x = x + ffn(il, x)
|
||||
return frames, drift
|
||||
|
||||
|
||||
@ModelBase.register_hparams_loader(lambda dir_model: "flow_lm.bos_emb" in _tensor_shapes(dir_model))
|
||||
def _load_hparams(dir_model: Path) -> dict[str, Any]:
|
||||
logger.info("gguf: detected pocket-tts checkpoint, deriving hparams from tensor shapes")
|
||||
@@ -194,25 +291,30 @@ class PocketTTSMmprojModel(MmprojModel):
|
||||
(gguf.MODEL_TENSOR.A_GEN_WAV_TFM_ATTN_Q, gguf.MODEL_TENSOR.A_GEN_WAV_TFM_ATTN_K, gguf.MODEL_TENSOR.A_GEN_WAV_TFM_ATTN_V),
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.has_audio_encoder = _has_voice_encoder(self.dir_model)
|
||||
|
||||
def set_gguf_parameters(self):
|
||||
self.gguf_writer.add_file_type(self.ftype)
|
||||
assert self.hparams_audio is not None
|
||||
|
||||
# voice-prompt encoder: mimi encoder + speaker_proj
|
||||
self.gguf_writer.add_clip_has_audio_encoder(True)
|
||||
# note: the 24kHz sample rate is hardcoded on the clip.cpp side, like the other audio models
|
||||
self.gguf_writer.add_clip_audio_projector_type(gguf.VisionProjectorType.POCKETTTS_SPKENC)
|
||||
self.gguf_writer.add_audio_projection_dim(self.n_embd_text)
|
||||
self.gguf_writer.add_audio_block_count(self.hparams_audio["num_hidden_layers"])
|
||||
self.gguf_writer.add_audio_embedding_length(self.hparams_audio["hidden_size"])
|
||||
self.gguf_writer.add_audio_feed_forward_length(self.hparams_audio["intermediate_size"])
|
||||
self.gguf_writer.add_audio_head_count(self.hparams_audio["num_attention_heads"])
|
||||
self.gguf_writer.add_audio_attention_layernorm_eps(1e-5)
|
||||
# mimi convolves the waveform directly, it is passed around as a 1-row "mel"
|
||||
self.gguf_writer.add_audio_num_mel_bins(1)
|
||||
if self.has_audio_encoder:
|
||||
self.gguf_writer.add_clip_has_audio_encoder(True)
|
||||
# note: the 24kHz sample rate is hardcoded on the mtmd side, like the other audio models
|
||||
self.gguf_writer.add_clip_audio_projector_type(gguf.VisionProjectorType.POCKETTTS_SPKENC)
|
||||
self.gguf_writer.add_audio_projection_dim(self.n_embd_text)
|
||||
self.gguf_writer.add_audio_block_count(self.hparams_audio["num_hidden_layers"])
|
||||
self.gguf_writer.add_audio_embedding_length(self.hparams_audio["hidden_size"])
|
||||
self.gguf_writer.add_audio_feed_forward_length(self.hparams_audio["intermediate_size"])
|
||||
self.gguf_writer.add_audio_head_count(self.hparams_audio["num_attention_heads"])
|
||||
self.gguf_writer.add_audio_attention_layernorm_eps(1e-5)
|
||||
# mimi convolves the waveform directly, it is passed around as a 1-row "mel"
|
||||
self.gguf_writer.add_audio_num_mel_bins(1)
|
||||
|
||||
# generation: flow-matching decoder + mimi decoder
|
||||
# the SEANet and flow net hparams are constant across the family, clip.cpp holds them
|
||||
# the SEANet and flow net hparams are constant across the family, mtmd holds them
|
||||
self.gguf_writer.add_clip_has_gen_audio_encoder(True)
|
||||
self.gguf_writer.add_clip_gen_audio_projector_type(gguf.VisionProjectorType.POCKETTTS_GEN)
|
||||
self.gguf_writer.add_gen_audio_projection_dim(self.n_embd_text)
|
||||
@@ -229,12 +331,57 @@ class PocketTTSMmprojModel(MmprojModel):
|
||||
# conv1d/conv1d_dw kernels must be F16, ggml_conv_1d(_dw) has no BF16 path
|
||||
if ".seanet." in new_name or new_name in ("a.downsample.conv.weight", "a.gen.wav.upsample.weight"):
|
||||
return gguf.GGMLQuantizationType.F16
|
||||
# voices are read on the host
|
||||
if new_name.startswith("voice."):
|
||||
return gguf.GGMLQuantizationType.F32
|
||||
return False
|
||||
|
||||
def generate_extra_tensors(self) -> Iterable[tuple[str, Tensor]]:
|
||||
# embeddings/<name>.safetensors hold the K/V state after the voice prompt (see get_state_for_audio_prompt() in the reference), turn it back into prompt embeddings
|
||||
paths = sorted((self.dir_model / "embeddings").glob("*.safetensors"))
|
||||
if not paths:
|
||||
return
|
||||
weights = _load_safetensors(self.dir_model / "model.safetensors",
|
||||
("flow_lm.transformer.layers.", "flow_lm.speaker_proj_weight", "flow_lm.bos_before_voice"))
|
||||
n_layer = self.global_config["num_hidden_layers"]
|
||||
for path in paths:
|
||||
state = _load_safetensors(path, ("transformer.layers.",))
|
||||
kv = []
|
||||
for il in range(n_layer):
|
||||
prefix = f"transformer.layers.{il}.self_attn/"
|
||||
if any(prefix + k not in state for k in ("cache", "offset")):
|
||||
break
|
||||
n_pos = int(state[prefix + "offset"].item())
|
||||
# older packs have no pad entry
|
||||
if prefix + "pad" in state and int(state[prefix + "pad"].item()) != 0:
|
||||
break
|
||||
kv.append(state[prefix + "cache"][:, 0, :n_pos].flatten(2)) # [k/v, pos, n_embd]
|
||||
if len(kv) != n_layer or any(t.shape != kv[0].shape for t in kv) or kv[0].shape[1] < 2 or \
|
||||
kv[0].shape[2] != self.global_config["hidden_size"]:
|
||||
logger.warning(f"voice {path.stem}: skipped, not an unpadded voice state of this backbone")
|
||||
continue
|
||||
embd, drift = _voice_prompt_embd(weights, kv, self.global_config["num_attention_heads"],
|
||||
self.global_config["rope_theta"])
|
||||
# some packs ship a state made with other weights, the reference still uses it: keep up to 50% error, warn above 5%
|
||||
if drift > 0.5:
|
||||
logger.warning(f"voice {path.stem}: skipped, its state does not belong to these weights (error {drift:.1e})")
|
||||
continue
|
||||
log = logger.warning if drift > 0.05 else logger.info
|
||||
log(f"voice {path.stem}: {embd.shape[0]} frames, prompting them again gives the shipped state within {drift:.1e}")
|
||||
yield (f"voice.{path.stem}", embd.float())
|
||||
|
||||
def modify_tensors(self, data_torch: Tensor, name: str, bid: int | None) -> Iterable[tuple[str, Tensor]]:
|
||||
del bid # the block index of the mimi transformers is parsed here, not by the base class
|
||||
T = gguf.MODEL_TENSOR
|
||||
|
||||
if name.startswith("voice."):
|
||||
yield (name, data_torch)
|
||||
return
|
||||
|
||||
if not self.has_audio_encoder and (name.startswith(("mimi.encoder", "mimi.downsample."))
|
||||
or name == "flow_lm.speaker_proj_weight"):
|
||||
return # voice-prompt encoder
|
||||
|
||||
if name in ("flow_lm.bos_emb", "flow_lm.bos_before_voice", "flow_lm.conditioner.embed.weight"):
|
||||
return # folded into the backbone embedding table
|
||||
if name.startswith("flow_lm.transformer.") or name.startswith("flow_lm.out_norm."):
|
||||
|
||||
+1
-1
@@ -170,7 +170,7 @@ class Qwen2MoeModel(TextModel):
|
||||
raise ValueError(f"Unprocessed experts: {experts}")
|
||||
|
||||
|
||||
@ModelBase.register("Qwen3ForCausalLM", "Qwen3Model")
|
||||
@ModelBase.register("Qwen3ForCausalLM", "Qwen3Model", "LlavaOnevision2ForConditionalGeneration")
|
||||
@ModelBase.example("Qwen/Qwen3-8B")
|
||||
class Qwen3Model(Qwen2Model):
|
||||
model_arch = gguf.MODEL_ARCH.QWEN3
|
||||
|
||||
@@ -235,11 +235,11 @@ class Qwen3TTSSpeakerEncoderModel(MmprojModel):
|
||||
|
||||
# handle speaker encoder config
|
||||
self.gguf_writer.add_audio_projection_dim(self.n_embd_text)
|
||||
# mel_spectrogram() front-end: sr=24000, n_fft=1024, hop=256, n_mels=128, fmin=0, fmax=12000 (=sr/2, the clip.cpp default)
|
||||
# mel_spectrogram() front-end: sr=24000, n_fft=1024, hop=256, n_mels=128, fmin=0, fmax=12000 (=sr/2, the mtmd default)
|
||||
self.gguf_writer.add_audio_num_mel_bins(128)
|
||||
# 3 SE-Res2Net stages; the stem conv, mfa, asp and fc are not counted here
|
||||
self.gguf_writer.add_audio_block_count(3)
|
||||
# ECAPA-TDNN has no attention/FFN, these are dummy to allow clip.cpp to load it
|
||||
# ECAPA-TDNN has no attention/FFN, these are dummy to allow mtmd to load it
|
||||
self.gguf_writer.add_audio_embedding_length(1536)
|
||||
self.gguf_writer.add_audio_head_count(1)
|
||||
self.gguf_writer.add_audio_feed_forward_length(1536)
|
||||
@@ -256,7 +256,7 @@ class Qwen3TTSSpeakerEncoderModel(MmprojModel):
|
||||
self.gguf_writer.add_gen_audio_head_count(code_predictor_config["num_attention_heads"])
|
||||
self.gguf_writer.add_gen_audio_head_count_kv(code_predictor_config["num_key_value_heads"])
|
||||
self.gguf_writer.add_gen_audio_attention_layernorm_eps(code_predictor_config["rms_norm_eps"])
|
||||
# note: code2wav hparams are hardcoded on the mtmd/clip.cpp side for now, not written here
|
||||
# note: code2wav hparams are hardcoded on the mtmd side for now, not written here
|
||||
|
||||
def _wav_decoder_config(self) -> dict[str, Any] | None:
|
||||
# code2wav has its own config.json, inside the speech_tokenizer dir
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
|
||||
from typing import Iterable, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from torch import Tensor
|
||||
|
||||
from .base import ModelBase, TextModel, gguf, logger
|
||||
|
||||
|
||||
@ModelBase.register("RicursiveForCausalLM")
|
||||
@ModelBase.example("ricursiveAI/Ripple-65B-Preview")
|
||||
class RicursiveModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.RICURSIVE
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
hparams = self.hparams
|
||||
|
||||
if (act := hparams.get("hidden_act", "silu")) != "silu":
|
||||
raise ValueError(f"Ricursive: unsupported hidden_act {act!r}")
|
||||
|
||||
# RicursiveConfig derives the layer pattern from layer_types alone, by default full attention iff i % 5 == 4
|
||||
if (layer_types := hparams.get("layer_types")) is None:
|
||||
layer_types = ["full_attention" if i % 5 == 4 else "sliding_attention" for i in range(self.block_count)]
|
||||
if len(layer_types) != self.block_count:
|
||||
raise ValueError(f"Ricursive: layer_types has {len(layer_types)} entries, expected {self.block_count}")
|
||||
if unknown := set(layer_types) - {"sliding_attention", "full_attention"}:
|
||||
raise ValueError(f"Ricursive: unsupported layer_types {sorted(unknown)}")
|
||||
self.is_swa = [t == "sliding_attention" for t in layer_types]
|
||||
# only sliding layers use RoPE, an all-full-attention model would have no positional encoding
|
||||
if not any(self.is_swa):
|
||||
raise ValueError("Ricursive: layer_types has no sliding_attention layer, all-full-attention models are not supported")
|
||||
# RicursiveConfig pops a stored hybrid_layer_pattern and recomputes it from layer_types
|
||||
if (pattern := hparams.get("hybrid_layer_pattern")) is not None and list(pattern) != [int(swa) for swa in self.is_swa]:
|
||||
logger.warning("Ricursive: hybrid_layer_pattern does not match layer_types, ignoring it")
|
||||
|
||||
if not hparams.get("gate_full_precision", True):
|
||||
logger.warning("Ricursive: gate_full_precision is false, llama.cpp computes the attention gate in f32")
|
||||
|
||||
# RicursiveConfig defaults; the reference ignores the tensors of a disabled feature
|
||||
self.use_valres = hparams.get("use_valres", False)
|
||||
self.use_gate = hparams.get("use_gated_attention", True)
|
||||
names = list(self.model_tensors)
|
||||
if bias := [name for name in names if name.endswith("bias")]:
|
||||
raise ValueError(f"Ricursive: bias tensors are not supported, found {bias[0]!r}")
|
||||
for enabled, suffix in ((self.use_valres, ".self_attn.value_res_lambda"), (self.use_gate, ".self_attn.g_proj.weight")):
|
||||
if enabled and sum(name.endswith(suffix) for name in names) != self.block_count:
|
||||
raise ValueError(f"Ricursive: expected one {suffix!r} tensor per layer")
|
||||
|
||||
def set_vocab(self):
|
||||
self._set_vocab_gpt2()
|
||||
# eos_token_id is [<|im_end|>, <|endoftext|>]: register the turn end as EOT so generation stops on it
|
||||
eos = self.hparams.get("eos_token_id")
|
||||
if isinstance(eos, list):
|
||||
extra = [e for e in eos if e != self.hparams.get("bos_token_id")]
|
||||
if extra:
|
||||
self.gguf_writer.add_eot_token_id(extra[0])
|
||||
logger.info(f"gguf: eot_token_id = {extra[0]}")
|
||||
|
||||
def set_gguf_parameters(self):
|
||||
super().set_gguf_parameters()
|
||||
hparams = self.hparams
|
||||
self.gguf_writer.add_vocab_size(hparams["vocab_size"])
|
||||
self.gguf_writer.add_rope_dimension_count(hparams["head_dim"])
|
||||
|
||||
self.gguf_writer.add_sliding_window(hparams["sliding_window"])
|
||||
self.gguf_writer.add_sliding_window_pattern(self.is_swa)
|
||||
# sliding layers use RoPE, full attention layers use no positional encoding
|
||||
self.gguf_writer.add_rope_pattern(self.is_swa)
|
||||
|
||||
if (embed_scale := hparams.get("embed_scale")) is not None:
|
||||
if embed_scale == 0:
|
||||
raise ValueError(f"Ricursive: unsupported embed_scale {embed_scale!r}")
|
||||
self.gguf_writer.add_embedding_scale(float(embed_scale))
|
||||
# absent and 0 both mean no clamp (the reference tests `if clamp_threshold:`)
|
||||
if (clamp := hparams.get("ffn_clamp_threshold")) is not None:
|
||||
if clamp < 0 or not math.isfinite(clamp):
|
||||
raise ValueError(f"Ricursive: unsupported ffn_clamp_threshold {clamp!r}")
|
||||
self.gguf_writer.add_swiglu_clamp([float(clamp)] * self.block_count)
|
||||
|
||||
def modify_tensors(self, data_torch: Tensor, name: str, bid: int | None) -> Iterable[tuple[str, Tensor]]:
|
||||
# value_res_lambda has no .weight suffix in the checkpoint
|
||||
if name.endswith(".value_res_lambda"):
|
||||
if not self.use_valres:
|
||||
return
|
||||
name += ".weight"
|
||||
elif name.endswith(".g_proj.weight") and not self.use_gate:
|
||||
return
|
||||
yield from super().modify_tensors(data_torch, name, bid)
|
||||
@@ -0,0 +1,133 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from typing import Callable, Iterable, TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from torch import Tensor
|
||||
|
||||
from .base import ModelBase, gguf
|
||||
from .deepseek import DeepseekV2Model
|
||||
|
||||
|
||||
@ModelBase.register("Xing4_0ForCausalLM")
|
||||
class Xing4_0Model(DeepseekV2Model):
|
||||
"""Xing4_0 : DeepSeek-V2/V3 backbone (MLA + MoE) + mHC residual mixing."""
|
||||
|
||||
model_arch = gguf.MODEL_ARCH.XING4_0
|
||||
|
||||
skip_mtp = False
|
||||
supports_mtp_export = True
|
||||
_n_main_layers: int | None = None
|
||||
|
||||
# map (prefix, kind) -> MODEL_TENSOR enum
|
||||
_hc_tensor_map = {
|
||||
("hc_attn", "fn"): gguf.MODEL_TENSOR.HC_ATTN_FN,
|
||||
("hc_attn", "base"): gguf.MODEL_TENSOR.HC_ATTN_BASE,
|
||||
("hc_attn", "scale"): gguf.MODEL_TENSOR.HC_ATTN_SCALE,
|
||||
("hc_ffn", "fn"): gguf.MODEL_TENSOR.HC_FFN_FN,
|
||||
("hc_ffn", "base"): gguf.MODEL_TENSOR.HC_FFN_BASE,
|
||||
("hc_ffn", "scale"): gguf.MODEL_TENSOR.HC_FFN_SCALE,
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self.block_count = self.hparams["num_hidden_layers"]
|
||||
if not self.no_mtp:
|
||||
self.block_count += self.hparams.get("num_nextn_predict_layers", 0)
|
||||
self.tensor_map = gguf.get_tensor_name_map(self.model_arch, self.block_count)
|
||||
|
||||
def index_tensors(self, remote_hf_model_id: str | None = None):
|
||||
# needed by filter_tensors() before any tensor is filtered
|
||||
type(self)._n_main_layers = self.hparams["num_hidden_layers"]
|
||||
return super().index_tensors(remote_hf_model_id=remote_hf_model_id)
|
||||
|
||||
@classmethod
|
||||
def filter_tensors(cls, item: tuple[str, Callable[[], Tensor]]) -> tuple[str, Callable[[], Tensor]] | None:
|
||||
if (titem := super().filter_tensors(item)) is None:
|
||||
return None
|
||||
name, gen = titem
|
||||
|
||||
# the NextN/MTP block lives past num_hidden_layers (model.layers.40 -> blk.40)
|
||||
assert cls._n_main_layers is not None
|
||||
is_mtp = (m := re.match(r"model\.layers\.(\d+)\.", name)) is not None and int(m.group(1)) >= cls._n_main_layers
|
||||
|
||||
# --no-mtp: drop the appended NextN block entirely.
|
||||
if is_mtp and cls.no_mtp:
|
||||
return None
|
||||
# --mtp: keep ONLY NextN-block tensors plus the shared embeddings/
|
||||
# norm/lm_head (so the resulting GGUF carries just the draft head).
|
||||
if cls.mtp_only and not is_mtp and name not in (
|
||||
"model.embed_tokens.weight", "model.norm.weight", "lm_head.weight",
|
||||
):
|
||||
return None
|
||||
|
||||
return name, gen
|
||||
|
||||
def set_gguf_parameters(self):
|
||||
rope_type = self.rope_parameters.get("rope_type") or self.rope_parameters.get("type")
|
||||
if rope_type == "rope":
|
||||
self.rope_parameters["rope_type"] = "yarn"
|
||||
if "type" in self.rope_parameters:
|
||||
self.rope_parameters["type"] = "yarn"
|
||||
# base.py's YARN branch accesses this with a direct key lookup
|
||||
self.rope_parameters.setdefault("original_max_position_embeddings",
|
||||
self.hparams.get("original_max_position_embeddings", 4096))
|
||||
|
||||
super().set_gguf_parameters()
|
||||
hparams = self.hparams
|
||||
|
||||
# NextN/MTP prediction layers
|
||||
if not self.no_mtp and (num_nextn_predict_layers := hparams.get("num_nextn_predict_layers")) is not None:
|
||||
self.gguf_writer.add_nextn_predict_layers(num_nextn_predict_layers)
|
||||
|
||||
self.gguf_writer.add_hyper_connection_count(
|
||||
hparams.get("hc_mult", 1))
|
||||
self.gguf_writer.add_hyper_connection_sinkhorn_iterations(
|
||||
hparams.get("hc_sinkhorn_iters", 20))
|
||||
self.gguf_writer.add_hyper_connection_epsilon(
|
||||
hparams.get("hc_eps", 1e-6))
|
||||
|
||||
def set_vocab(self):
|
||||
# Xing4_0 uses a SentencePiece tokenizer (tokenizer.model + Xing4_0Tokenizer).
|
||||
# V2's set_vocab tries GPT2/BPE first, which fails for SPM. Use the SPM path directly.
|
||||
# Note: no add_tokenizer_pre override — the C++ SPM load path ignores
|
||||
# tokenizer.ggml.pre entirely (pre-tokenizers only apply to BPE vocabs).
|
||||
self._set_vocab_sentencepiece()
|
||||
|
||||
def prepare_metadata(self, vocab_only: bool):
|
||||
from_dir = self.fname_out.is_dir()
|
||||
super().prepare_metadata(vocab_only=vocab_only)
|
||||
|
||||
if not self.mtp_only or not from_dir:
|
||||
return
|
||||
|
||||
output_type: str = self.ftype.name.partition("_")[2]
|
||||
fname_default: str = gguf.naming_convention(
|
||||
self.metadata.name, self.metadata.basename, self.metadata.finetune,
|
||||
self.metadata.version, size_label=None, output_type=output_type, model_type=None)
|
||||
self.fname_out = self.fname_out.parent / f"mtp-{fname_default}.gguf"
|
||||
|
||||
def modify_tensors(self, data_torch: Tensor, name: str, bid: int | None) -> Iterable[tuple[str, Tensor]]:
|
||||
# handle mHC tensors: model.layers.{N}.{attn_hc|ffn_hc}.{hc_fn|hc_base|hc_scale}
|
||||
match = re.match(r"model\.layers\.(\d+)\.(attn_hc|ffn_hc)\.(.+)$", name)
|
||||
if match:
|
||||
layer_idx = int(match.group(1))
|
||||
hc_type = match.group(2) # "attn_hc" or "ffn_hc"
|
||||
param = match.group(3) # "hc_fn", "hc_base", "hc_scale"
|
||||
|
||||
if bid is None:
|
||||
bid = layer_idx
|
||||
|
||||
prefix = "hc_attn" if hc_type == "attn_hc" else "hc_ffn"
|
||||
|
||||
kind = {"hc_fn": "fn", "hc_base": "base", "hc_scale": "scale"}.get(param)
|
||||
if kind is None:
|
||||
raise ValueError(f"unexpected mHC tensor: {name}")
|
||||
tensor_enum = self._hc_tensor_map[(prefix, kind)]
|
||||
gguf_name = self.format_tensor_name(tensor_enum, bid)
|
||||
yield (gguf_name, data_torch)
|
||||
return
|
||||
|
||||
yield from super().modify_tensors(data_torch, name, bid)
|
||||
@@ -198,6 +198,7 @@ pre_computed_hashes = [
|
||||
# jina-v2-de variants
|
||||
{"name": "jina-v2-de", "tokt": TOKENIZER_TYPE.BPE, "repo": "https://huggingface.co/aari1995/German_Semantic_V3", "chkhsh": "b3d1dd861f1d4c5c0d2569ce36baf3f90fe8a102db3de50dd71ff860d91be3df"},
|
||||
{"name": "gpt-2", "tokt": TOKENIZER_TYPE.BPE, "repo": "https://huggingface.co/evilfreelancer/ruGPT3XL", "chkhsh": "0fe1cf6eda062318a1af7270f3331a85c539a01778ff948e24388e949c5282f4"},
|
||||
{"name": "gpt-2", "tokt": TOKENIZER_TYPE.BPE, "repo": "https://huggingface.co/Lernex/Metis-1.6-Logos", "chkhsh": "df1bc34a6366466bcb36a9a1b1cc0afdb08cfe21c9250602c930f159085390a9"},
|
||||
# lfm2 variants
|
||||
{"name": "lfm2", "tokt": TOKENIZER_TYPE.BPE, "repo": "https://huggingface.co/LiquidAI/LFM2.5-8B-A1B", "chkhsh": "9e454714343b69b99b71795c1d27a68c2a1d15dab111f4d353109f966af29da7"},
|
||||
# hrm-text (DFM Mimir) is SPM-style BPE: normalizer maps ' ' -> '▁', merges
|
||||
|
||||
@@ -161,7 +161,7 @@ lspci -n | grep -Eo '19e5:d[0-9a-f]{3}' | cut -d: -f2
|
||||
| FP16 | Support | Support |
|
||||
| Q8_0 | Support | Partial |
|
||||
| Q4_0 | Support | Partial |
|
||||
| BF16 | Support | |
|
||||
| BF16 | Support | No |
|
||||
|
||||
> **310P note**
|
||||
> - `Q8_0`: data transform / buffer path is implemented, and `GET_ROWS` is supported, but quantized `MUL_MAT` / `MUL_MAT_ID` are not supported.
|
||||
@@ -274,7 +274,9 @@ cmake --build build --config release
|
||||
|
||||
**Notes**:
|
||||
|
||||
- CANN backend only supports FP16/Q4_0/Q8_0 models currently.
|
||||
- On 910B the CANN backend supports FP16, BF16 and Q4_0/Q8_0 models. On 310P, BF16 is not
|
||||
supported and quantized `MUL_MAT` / `MUL_MAT_ID` are not implemented, so only FP16 models
|
||||
are supported (see [DataType Supports](#datatype-supports)).
|
||||
|
||||
2. **Launch inference**
|
||||
|
||||
@@ -355,3 +357,7 @@ Enable ACL graph execution during the prefill stage, default is false. This opti
|
||||
### GGML_CANN_OPERATOR_FUSION
|
||||
|
||||
Enable operator fusion during computation, default is false. This option fuses compatible operators (e.g., ADD + RMS_NORM) to reduce overhead and improve performance.
|
||||
|
||||
### GGML_CANN_NO_PINNED
|
||||
|
||||
Disable pinned (host-locked) host buffers. When it is set (any value), `aclrtMallocHost` is not called: the CANN host buffer type allocates regular CPU memory instead and the backend reports no `host_buffer` capability, so host-side staging uses pageable memory. Use it when pinned host allocation fails, or when the pinned memory is needed by other processes on the host.
|
||||
|
||||
@@ -817,7 +817,7 @@ User can use the device management in [docs/multi-gpu.md](https://github.com/ggm
|
||||
| GGML_SYCL_ENABLE_VMM | 0 or 1 (default) | Enable the virtual-memory device pool. |
|
||||
| GGML_SYCL_ENABLE_MKL_FA | 1 (default) or 0 | Enable oneMKL GEMM flash attention for XMX-accelerated prompt processing with quantized KV cache. Automatically activates during prefill (prompt processing) when all conditions are met: (1) flash-attn enabled (`-fa` or `--flash-attn on`), (2) KV cache quantized (`--cache-type-k q8_0 --cache-type-v q8_0` or other `*_0/*_1` types), (3) batch size ≥ 1024 (`--batch-size 1024`), (4) prompt length ≥ 1024 tokens. Set to 0 to force the TILE kernel for A/B testing. Example minimum command: `llama-cli -m model.gguf -fa -ngl 99 --cache-type-k q8_0 --cache-type-v q8_0 --batch-size 1024 -p "your prompt"` |
|
||||
| GGML_SYCL_MKL_FA_DEBUG | 0 (default) or 1 | Enable per-call diagnostic logging for MKL flash attention: GEMM/softmax timings, interleaved-head detection, and buffer memory usage. |
|
||||
| GGML_SYCL_MEMTRACE | 0 (default), 1, 2 | Enable record and output memory allocation diagnostics. Requires `-lv 4`. <br>0 - Disable<br>1 - Basic memory info, including current and peak allocations, as well allocations from other sources, around 50 lines per model load.<br>2 - More verbose, logging around 900 specific allocations and deallocations. |
|
||||
| GGML_SYCL_MEMTRACE | 0 (default), 1, 2 | Enable record and output memory allocation diagnostics. Requires `-lv 4`. <br>0 - Disable<br>1 - Basic memory info, including current and peak allocations, as well allocations from other sources, and the device free memory before each model buffer allocation, around 50 lines per model load.<br>2 - More verbose, logging around 900 specific allocations and deallocations. |
|
||||
| GGML_SYCL_MEMTRACE_STEP | 64 (default) or positive integer | With GGML_SYCL_MEMTRACE=1, the minimum growth in memory usage to trigger another log record. |
|
||||
| GGML_SYCL_MKL_FA_DIAG | 0 (default) or 1 | Enable output fingerprinting for MKL flash attention. Dumps the first 64 float output values for the first 6 FA calls with n_kv ≥ 1024, labeled with kernel type (MKL/TILE/VEC) for cross-kernel comparison. |
|
||||
| GGML_SYCL_ENABLE_FUSION | 0 or 1 (default) | Enable fused-kernel dispatch in graph compute. Unsupported types and layouts fall back to the standalone op kernels. See `ggml_sycl_can_fuse()`. |
|
||||
@@ -836,6 +836,7 @@ User can use the device management in [docs/multi-gpu.md](https://github.com/ggm
|
||||
| ZES_ENABLE_SYSMAN | 0 (default) or 1 | Support to get free memory of GPU by sycl::aspect::ext_intel_free_memory.<br>Recommended to use when --split-mode = layer |
|
||||
| UR_L0_ENABLE_RELAXED_ALLOCATION_LIMITS | 0 (default) or 1 | Allow SYCL/Unified Runtime Level Zero device allocations larger than 4 GiB. llama.cpp's direct Level Zero allocation path requests the relaxed maximum-size limit itself when GGML_SYCL_ENABLE_LEVEL_ZERO=1. |
|
||||
| GGML_SYCL_USM_SYSTEM | 0 (default) or 1 | Enable experimental support for [USM system allocations](https://github.khronos.org/SYCL_Reference/iface/usm_basic_concept.html#system-allocations) for large GPU buffers. This requires enough host memory for model weights and caches, an Intel Xe2+ GPU such as BMG or newer and supported on Linux only, with CONFIG_DRM_XE_GPUSVM enabled. |
|
||||
| GGML_SYCL_BMG_VRAM_CHECK | 1 (default) or 0 | Workaround for BMG (Arc B-series) GPUs, where the Level Zero driver accepts device allocations beyond VRAM and moves the overflow to system RAM, which can exhaust host memory when a model does not fit (e.g. `-ngl 999`, see https://github.com/intel/compute-runtime/issues/1047). When enabled, a model or split buffer that does not fit in the device's free memory is refused and the model load fails with an error. Set to 0 to disable. |
|
||||
|
||||
1. <a id="sycl-graph-footnote"></a>SYCL Graph support (`GGML_SYCL_ENABLE_GRAPH=1`) is limited to single-GPU workloads and may also depend on the model architecture and kernels in use.
|
||||
Performance depends on how often a recorded graph can be reused, which will vary by workload.
|
||||
|
||||
@@ -325,10 +325,14 @@ on 4 physical NPUs, or `--devices 'HTP0[0-1:0],HTP1[0-1:1]'` on 2 physical NPUs
|
||||
Controls the number of HVX hardware threads to use. The default is all (actual number varies depending on the hardware version).
|
||||
|
||||
- `GGML_HEXAGON_VTCM_SIZE=0`
|
||||
Overrides the VTCM size used by each session. Accepts `K`, `M` and `G` suffixes; a plain number is in MB. The default (0) uses the size the hardware reports. Values above the hardware size will fail to start the session.
|
||||
Overrides the VTCM size used by each session. Accepts `K`, `M` and `G` suffixes; a plain number is in MB.
|
||||
The default (0) uses the size the hardware reports. Values above the hardware size will fail to start the session.
|
||||
|
||||
- `GGML_HEXAGON_HOSTBUF=1` (default: 0, disabled)
|
||||
Enables allocating host buffers for debugging. By default, host buffers are disabled.
|
||||
- `GGML_HEXAGON_HOSTBUF=0` (default: 1, enabled)
|
||||
Controls host buffer (`HTP*-HOST`) allocation in shared FastRPC memory to avoid host-device tensor copies.
|
||||
CPU-assigned weights (input embeddings like `token_embd` and `per_layer_token_embd`, and tensors overridden with `-ot ...=CPU`)
|
||||
are placed in host buffers as well. On older drivers/FW, large models can run out of IOVA space when these are mapped.
|
||||
Pass `--no-host` to keep CPU-assigned weights in regular CPU memory (`-ot ...=CPU` alone is not sufficient).
|
||||
|
||||
- `GGML_HEXAGON_DMA64=0` (default: enabled on v81+)
|
||||
Disables 64-bit DMA for model weights. Set to `1` to enable it explicitly on a supported architecture.
|
||||
|
||||
@@ -255,7 +255,7 @@ Writing high-performance operators for Hexagon requires following specific guide
|
||||
### Tracing Instrumentation
|
||||
|
||||
- All kernels must include trace events for performance profiling and timeline visualization in Perfetto
|
||||
([`hex-profile.h`](../../../ggml/src/ggml-hexagon/htp/hex-profile.h)).
|
||||
([`htp-trace.h`](../../../ggml/src/ggml-hexagon/htp/htp-trace.h)).
|
||||
- Surround compute sections with `htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_COMP, (uint16_t) info)` and
|
||||
`htp_trace_event_stop(tr, HTP_TRACE_EVT_HVX_COMP, (uint16_t) info)`.
|
||||
- Use specific event types for major phases:
|
||||
|
||||
+3
-3
@@ -249,7 +249,7 @@ IBM VXE/VXE2 SIMD acceleration depends on the BLAS implementation. It is strongl
|
||||
| MXFP4 | ✅ | ❓ | ❓ |
|
||||
| Q5_0 | ✅ | ❓ | ❓ |
|
||||
| Q5_1 | ✅ | ❓ | ❓ |
|
||||
| Q8_0 | ✅ | ❓ | ❓ |
|
||||
| Q8_0 | ✅ | ✅ | ❓ |
|
||||
| Q2_K | 🚫 | ❓ | ❓ |
|
||||
| Q3_K | ✅ | ❓ | ❓ |
|
||||
| Q4_K | ✅ | ❓ | ❓ |
|
||||
@@ -266,11 +266,11 @@ IBM VXE/VXE2 SIMD acceleration depends on the BLAS implementation. It is strongl
|
||||
| IQ1_M | 🚫 | ❓ | ❓ |
|
||||
| IQ4_NL | ✅ | ❓ | ❓ |
|
||||
| IQ4_XS | ✅ | ❓ | ❓ |
|
||||
| FP32->FP16 | 🚫 | ❓ | ❓ |
|
||||
| FP32->FP16 | ✅ | ❓ | ❓ |
|
||||
| FP16->FP32 | 🚫 | ❓ | ❓ |
|
||||
|
||||
- ✅ - acceleration available
|
||||
- 🚫 - acceleration unavailable, will still run using scalar implementation
|
||||
- ❓ - acceleration unknown, please contribute if you can test it yourself
|
||||
|
||||
Last Updated by **Aaron Teo (aaron.teo1@ibm.com)** on Sep 8, 2026.
|
||||
Last Updated by **Aaron Teo (aaron.teo1@ibm.com)** on Nov 3, 2026.
|
||||
|
||||
@@ -128,7 +128,7 @@ Note: to debug the inference graph: you can use [llama-eval-callback](/examples/
|
||||
If the new model supports multimodal inputs, you will need to add a new encoder definition in `libmtmd`. You can find more information about llama.cpp's multimodal support in [the docs](../multimodal.md) and in the `tools/mtmd` source directory.
|
||||
|
||||
1. In the conversion script, make sure you add a subclass that extends `MmprojModel` or another class that inherits from the same base class.
|
||||
2. Add the encoder definition in `clip.cpp`.
|
||||
2. Add the encoder definition: hparams and tensor loading in `mtmd-model.cpp`, graph inputs in `mtmd-subcontext.cpp`.
|
||||
3. Implement the preprocessor in `mtmd.cpp`. In most cases, you can reuse an existing preprocessor.
|
||||
4. Implement the encoder GGML graph, either in a dedicated file if the model is truly different from existing ones, or by reusing an existing implementation (for example: siglip, pixtral, or qwen) and adding a model-specific projector.
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
# MoE cache
|
||||
|
||||
When the experts of MoE layers stay in host memory (`-cmoe`, `-ncmoe`, `-ot`), the MoE cache keeps the most used ones in device memory for small batches (decode, speculative decoding). Large batches still upload the experts they use.
|
||||
|
||||
| Argument | |
|
||||
|---|---|
|
||||
| `--moe-cache-mib N` | cache size in MiB, split among the GPUs like the layers (default: 0, disabled) |
|
||||
| `--moe-cache-cpu-share F` | share of the cache misses computed on the CPU from the host experts instead of uploaded, once the cache is full (default: 0) |
|
||||
|
||||
The cache hits run on the device. With `--moe-cache-cpu-share F` the CPU computes a share `F` of the misses while the device computes the hits and uploads the other misses into the cache. This is faster when the CPU reads the host experts faster than the device can upload them, for example with fast RAM, a PCIe 4 link or experts that are not in pinned memory. The host experts are pinned with `-lm none`, `-lm mlock` and `-lm dio`, unless `--no-host`, but not when they are mmap'd (the default). The device uploads pinned experts at the full speed of the link, so the CPU share often does not help then. Until the cache is full every miss is uploaded, so the cache fills as fast as without the CPU share. The best share depends on the machine, the model and the cache size.
|
||||
|
||||
## Picking the arguments
|
||||
|
||||
Put the script in front of your server command:
|
||||
|
||||
```bash
|
||||
python3 scripts/moe-cache-tune.py -- build/bin/llama-server -m model.gguf -cmoe -t 8 -c 32768
|
||||
```
|
||||
|
||||
It starts the server 6 times, at two cache sizes × shares 0, 0.5 and 0.95, and times the generation of a few thousand tokens. That takes a few minutes, mostly model loading.
|
||||
|
||||
From these runs it fits the upload and CPU speeds of the machine, then replays the routing of all the runs through a copy of the cache logic for other sizes and shares. It prints the measured speeds, the predicted t/s and the recommended arguments: the lowest share within 5% of the fastest.
|
||||
|
||||
- **Server command:** keep your own arguments (`-t`, `-c`, expert placement, load mode); the speeds and the free device memory depend on them.
|
||||
- **`--max-mib N`:** tunes a smaller cache than what fits on the device. The runs in `--out` are reused while the command stays the same, so trying another value is instant.
|
||||
- **`--markdown`:** prints Markdown tables to paste in a PR.
|
||||
+5
-5
@@ -19,7 +19,7 @@ Legend:
|
||||
| ADD | ❌ | ✅ | ✅ | ✅ | 🟡 | 🟡 | 🟡 | 🟡 | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| ADD1 | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| ADD_ID | ❌ | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| ARANGE | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| ARANGE | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| ARGMAX | ❌ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| ARGSORT | ❌ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | 🟡 | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| CEIL | ❌ | ❌ | ✅ | 🟡 | 🟡 | 🟡 | ✅ | 🟡 | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
@@ -34,7 +34,7 @@ Legend:
|
||||
| CONV_TRANSPOSE_1D | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| CONV_TRANSPOSE_2D | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| COS | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| COUNT_EQUAL | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| COUNT_EQUAL | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| CPY | ❌ | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | ❌ | ❌ |
|
||||
| CROSS_ENTROPY_LOSS | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| CROSS_ENTROPY_LOSS_BACK | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
@@ -62,7 +62,7 @@ Legend:
|
||||
| GELU_QUICK | ❌ | ✅ | ✅ | 🟡 | 🟡 | 🟡 | ✅ | 🟡 | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| GET_ROWS | ❌ | 🟡 | ✅ | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | ✅ | 🟡 | ❌ | ❌ |
|
||||
| GET_ROWS_BACK | ❌ | ❌ | 🟡 | 🟡 | ❌ | ❌ | ❌ | ❌ | 🟡 | 🟡 | ❌ | ❌ | ❌ |
|
||||
| GROUP_NORM | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| GROUP_NORM | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| HARDSIGMOID | ❌ | ✅ | ✅ | 🟡 | 🟡 | ❌ | ✅ | 🟡 | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| HARDSWISH | ❌ | ✅ | ✅ | 🟡 | 🟡 | ❌ | ✅ | 🟡 | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| IM2COL | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
@@ -71,7 +71,7 @@ Legend:
|
||||
| LEAKY_RELU | ❌ | ✅ | ✅ | ✅ | ❌ | 🟡 | 🟡 | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| LIGHTNING_INDEXER | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | 🟡 | ✅ | ❌ | ❌ | ❌ | ❌ |
|
||||
| LOG | ❌ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| MEAN | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | 🟡 | ✅ | ❌ | ❌ | ❌ |
|
||||
| MEAN | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | 🟡 | ✅ | ✅ | ❌ | ❌ |
|
||||
| MUL | ❌ | ✅ | ✅ | ✅ | 🟡 | 🟡 | 🟡 | 🟡 | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| MUL_MAT | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 |
|
||||
| MUL_MAT_HADAMARD | ❌ | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ | 🟡 |
|
||||
@@ -91,7 +91,7 @@ Legend:
|
||||
| POOL_2D | ❌ | 🟡 | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| REGLU | ❌ | ✅ | ✅ | ✅ | 🟡 | 🟡 | 🟡 | 🟡 | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| RELU | ❌ | ✅ | ✅ | 🟡 | 🟡 | 🟡 | ✅ | 🟡 | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| REPEAT | ❌ | ✅ | ✅ | 🟡 | 🟡 | 🟡 | ✅ | 🟡 | ✅ | ✅ | 🟡 | ❌ | ❌ |
|
||||
| REPEAT | ❌ | ✅ | ✅ | 🟡 | 🟡 | 🟡 | ✅ | ✅ | ✅ | ✅ | 🟡 | ❌ | ❌ |
|
||||
| REPEAT_BACK | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| RMS_NORM | ❌ | ✅ | ✅ | ✅ | 🟡 | ✅ | ✅ | 🟡 | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| RMS_NORM_BACK | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
|
||||
+8
-8
@@ -7682,19 +7682,19 @@
|
||||
"OpenCL","REPEAT","type=f32,ne=[10,5,4,1],nr=[1,2,1,1]","support","1","yes","OpenCL"
|
||||
"OpenCL","REPEAT","type=f32,ne=[10,5,4,1],nr=[1,1,2,1]","support","1","yes","OpenCL"
|
||||
"OpenCL","REPEAT","type=f32,ne=[10,5,4,1],nr=[1,1,1,2]","support","1","yes","OpenCL"
|
||||
"OpenCL","REPEAT","type=f16,ne=[10,5,4,1],nr=[2,1,1,1]","support","0","no","OpenCL"
|
||||
"OpenCL","REPEAT","type=i32,ne=[10,5,4,1],nr=[2,1,1,1]","support","0","no","OpenCL"
|
||||
"OpenCL","REPEAT","type=i16,ne=[10,5,4,1],nr=[1,1,1,2]","support","0","no","OpenCL"
|
||||
"OpenCL","REPEAT","type=bf16,ne=[10,5,4,1],nr=[2,1,1,1]","support","0","no","OpenCL"
|
||||
"OpenCL","REPEAT","type=f16,ne=[10,5,4,1],nr=[2,1,1,1]","support","1","yes","OpenCL"
|
||||
"OpenCL","REPEAT","type=i32,ne=[10,5,4,1],nr=[2,1,1,1]","support","1","yes","OpenCL"
|
||||
"OpenCL","REPEAT","type=i16,ne=[10,5,4,1],nr=[1,1,1,2]","support","1","yes","OpenCL"
|
||||
"OpenCL","REPEAT","type=bf16,ne=[10,5,4,1],nr=[2,1,1,1]","support","1","yes","OpenCL"
|
||||
"OpenCL","REPEAT","type=f32,ne=[10,5,4,3],nr=[1,1,1,1]","support","1","yes","OpenCL"
|
||||
"OpenCL","REPEAT","type=f32,ne=[10,5,4,3],nr=[2,1,1,1]","support","1","yes","OpenCL"
|
||||
"OpenCL","REPEAT","type=f32,ne=[10,5,4,3],nr=[1,2,1,1]","support","1","yes","OpenCL"
|
||||
"OpenCL","REPEAT","type=f32,ne=[10,5,4,3],nr=[1,1,2,1]","support","1","yes","OpenCL"
|
||||
"OpenCL","REPEAT","type=f32,ne=[10,5,4,3],nr=[1,1,1,2]","support","1","yes","OpenCL"
|
||||
"OpenCL","REPEAT","type=f16,ne=[10,5,4,3],nr=[2,1,1,1]","support","0","no","OpenCL"
|
||||
"OpenCL","REPEAT","type=i32,ne=[10,5,4,3],nr=[2,1,1,1]","support","0","no","OpenCL"
|
||||
"OpenCL","REPEAT","type=i16,ne=[10,5,4,3],nr=[1,1,1,2]","support","0","no","OpenCL"
|
||||
"OpenCL","REPEAT","type=bf16,ne=[10,5,4,3],nr=[2,1,1,1]","support","0","no","OpenCL"
|
||||
"OpenCL","REPEAT","type=f16,ne=[10,5,4,3],nr=[2,1,1,1]","support","1","yes","OpenCL"
|
||||
"OpenCL","REPEAT","type=i32,ne=[10,5,4,3],nr=[2,1,1,1]","support","1","yes","OpenCL"
|
||||
"OpenCL","REPEAT","type=i16,ne=[10,5,4,3],nr=[1,1,1,2]","support","1","yes","OpenCL"
|
||||
"OpenCL","REPEAT","type=bf16,ne=[10,5,4,3],nr=[2,1,1,1]","support","1","yes","OpenCL"
|
||||
"OpenCL","REPEAT_BACK","type=f32,ne=[8,6,4,2],nr=[1,1,1,1],v=0","support","0","no","OpenCL"
|
||||
"OpenCL","REPEAT_BACK","type=f32,ne=[8,6,4,2],nr=[2,1,1,1],v=0","support","0","no","OpenCL"
|
||||
"OpenCL","REPEAT_BACK","type=f32,ne=[8,6,4,2],nr=[1,2,1,1],v=0","support","0","no","OpenCL"
|
||||
|
||||
|
Can't render this file because it is too large.
|
+34
-13
@@ -5465,8 +5465,10 @@
|
||||
"WebGPU: WebGPU","CONV_TRANSPOSE_2D","kernel_type=f16,ne_input=[3,2,3,1],ne_kernel=[2,2,1,3],stride=1","support","0","no","WebGPU"
|
||||
"WebGPU: WebGPU","CONV_TRANSPOSE_2D","kernel_type=f16,ne_input=[10,10,9,1],ne_kernel=[3,3,1,9],stride=2","support","0","no","WebGPU"
|
||||
"WebGPU: WebGPU","CONV_TRANSPOSE_2D","kernel_type=f16,ne_input=[129,63,35,1],ne_kernel=[3,3,48,35],stride=1","support","0","no","WebGPU"
|
||||
"WebGPU: WebGPU","COUNT_EQUAL","type=f32,ne=[4,500,1,1]","support","0","no","WebGPU"
|
||||
"WebGPU: WebGPU","COUNT_EQUAL","type=f32,ne=[4,5000,1,1]","support","0","no","WebGPU"
|
||||
"WebGPU: WebGPU","COUNT_EQUAL","type=f32,ne=[4,500,1,1],same_src=0","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","COUNT_EQUAL","type=f32,ne=[4,5000,1,1],same_src=0","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","COUNT_EQUAL","type=f32,ne=[4,500,1,1],same_src=1","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","COUNT_EQUAL","type=f32,ne=[4,5000,1,1],same_src=1","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","ARGMAX","type=f32,ne=[32,1,1,1]","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","ARGMAX","type=f32,ne=[32,513,1,1]","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","ARGMAX","type=f32,ne=[100,10,1,1]","support","1","yes","WebGPU"
|
||||
@@ -12278,13 +12280,23 @@
|
||||
"WebGPU: WebGPU","SUM","type=f32,ne=[11,5,6,3],permute=[0,2,1,3]","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","SUM","type=f32,ne=[11,5,6,3],permute=[0,3,2,1]","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","SUM","type=f32,ne=[11,5,6,3],permute=[0,1,3,2]","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","MEAN","type=f32,ne=[10,5,4,3]","support","0","no","WebGPU"
|
||||
"WebGPU: WebGPU","MEAN","type=f32,ne=[33,1,1,1]","support","0","no","WebGPU"
|
||||
"WebGPU: WebGPU","MEAN","type=f32,ne=[33,256,1,1]","support","0","no","WebGPU"
|
||||
"WebGPU: WebGPU","MEAN","type=f32,ne=[32769,1,1,1]","support","0","no","WebGPU"
|
||||
"WebGPU: WebGPU","MEAN","type=f32,ne=[32,1,1,1]","support","0","no","WebGPU"
|
||||
"WebGPU: WebGPU","MEAN","type=f32,ne=[32,256,1,1]","support","0","no","WebGPU"
|
||||
"WebGPU: WebGPU","MEAN","type=f32,ne=[32768,1,1,1]","support","0","no","WebGPU"
|
||||
"WebGPU: WebGPU","MEAN","type=f32,ne=[10,5,4,3],permute=0,slice=0","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","MEAN","type=f32,ne=[33,1,1,1],permute=0,slice=0","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","MEAN","type=f32,ne=[33,256,1,1],permute=0,slice=0","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","MEAN","type=f32,ne=[32769,1,1,1],permute=0,slice=0","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","MEAN","type=f32,ne=[32,1,1,1],permute=0,slice=0","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","MEAN","type=f32,ne=[32,256,1,1],permute=0,slice=0","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","MEAN","type=f32,ne=[32768,1,1,1],permute=0,slice=0","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","MEAN","type=f32,ne=[11,5,6,3],permute=1,slice=0","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","MEAN","type=f32,ne=[11,5,6,3],permute=0,slice=1","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","MEAN","type=f32,ne=[11,5,6,3],permute=1,slice=1","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","MEAN","type=f32,ne=[1,7,3,2],permute=0,slice=0","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","MEAN","type=f32,ne=[1023,5,1,1],permute=0,slice=0","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","MEAN","type=f32,ne=[1024,5,1,1],permute=0,slice=0","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","MEAN","type=f32,ne=[1025,5,1,1],permute=0,slice=0","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","MEAN","type=f32,ne=[17,65537,1,1],permute=0,slice=0","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","MEAN","type=f32,ne=[512,1,1,1],permute=0,slice=0","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","MEAN","type=f32,ne=[281,1536,1,1],permute=0,slice=0","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","SUM","type=f32,ne=[33,1,1,1]","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","SUM","type=f32,ne=[33,1024,1,1]","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","SUM","type=f32,ne=[33,256,1,1]","support","1","yes","WebGPU"
|
||||
@@ -12299,8 +12311,9 @@
|
||||
"WebGPU: WebGPU","SUM_ROWS","type=f32,ne=[33,1,1,1],permute=0,slice=0","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","SUM_ROWS","type=f32,ne=[33,1024,1,1],permute=0,slice=0","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","SUM_ROWS","type=f32,ne=[33,256,1,1],permute=0,slice=0","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","GROUP_NORM","type=f32,ne=[64,64,320,1],num_groups=32,eps=0.000001","support","0","no","WebGPU"
|
||||
"WebGPU: WebGPU","GROUP_NORM","type=f32,ne=[9,9,1280,1],num_groups=32,eps=0.000001","support","0","no","WebGPU"
|
||||
"WebGPU: WebGPU","GROUP_NORM","type=f32,ne=[64,64,320,1],num_groups=32,eps=0.000001","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","GROUP_NORM","type=f32,ne=[9,9,1280,1],num_groups=32,eps=0.000001","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","GROUP_NORM","type=f32,ne=[3,1,1,65537],num_groups=1,eps=0.000001","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","ACC","type=f32,ne_a=[256,17,1,1],ne_b=[256,16,1,1],stride_dim=-1","support","0","no","WebGPU"
|
||||
"WebGPU: WebGPU","ACC","type=f32,ne_a=[256,17,2,3],ne_b=[256,16,2,3],stride_dim=-1","support","0","no","WebGPU"
|
||||
"WebGPU: WebGPU","ACC","type=f32,ne_a=[256,17,2,3],ne_b=[128,16,2,3],stride_dim=-1","support","0","no","WebGPU"
|
||||
@@ -12326,8 +12339,16 @@
|
||||
"WebGPU: WebGPU","PAD_REFLECT_1D","type=f32,ne_a=[512,34,2,1],pad_0=10,pad_1=9","support","0","no","WebGPU"
|
||||
"WebGPU: WebGPU","PAD_REFLECT_1D","type=f32,ne_a=[3000,384,4,1],pad_0=10,pad_1=9","support","0","no","WebGPU"
|
||||
"WebGPU: WebGPU","ROLL","shift0=3,shift1=-2,shift3=1,shift4=-1","support","0","no","WebGPU"
|
||||
"WebGPU: WebGPU","ARANGE","type=f32,start=0.000000,stop=10.000000,step=1.000000","support","0","no","WebGPU"
|
||||
"WebGPU: WebGPU","ARANGE","type=f32,start=0.000000,stop=1048576.000000,step=1.000000","support","0","no","WebGPU"
|
||||
"WebGPU: WebGPU","ARANGE","type=f32,start=0.000000,stop=10.000000,step=1.000000","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","ARANGE","type=f32,start=3.000000,stop=3.500000,step=1.000000","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","ARANGE","type=f32,start=-10.000000,stop=10.000000,step=0.300000","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","ARANGE","type=f32,start=-1.000000,stop=62.750000,step=0.250000","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","ARANGE","type=f32,start=-1.000000,stop=63.000000,step=0.250000","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","ARANGE","type=f32,start=-1.000000,stop=63.250000,step=0.250000","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","ARANGE","type=f32,start=-1.000000,stop=254.750000,step=0.250000","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","ARANGE","type=f32,start=-1.000000,stop=255.000000,step=0.250000","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","ARANGE","type=f32,start=-1.000000,stop=255.250000,step=0.250000","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","ARANGE","type=f32,start=0.000000,stop=1048576.000000,step=1.000000","support","1","yes","WebGPU"
|
||||
"WebGPU: WebGPU","TIMESTEP_EMBEDDING","type=f32,ne_a=[2,1,1,1],dim=320,max_period=10000","support","0","no","WebGPU"
|
||||
"WebGPU: WebGPU","LEAKY_RELU","type=f32,ne_a=[10,5,4,3],negative_slope=0.100000","support","0","no","WebGPU"
|
||||
"WebGPU: WebGPU","CUMSUM","type=f32,ne=[10,5,4,3]","support","1","yes","WebGPU"
|
||||
|
||||
|
Can't render this file because it is too large.
|
@@ -103,6 +103,9 @@ int main(int argc, char ** argv) {
|
||||
params.cpuparams_batch.n_threads = params.speculative.draft.cpuparams_batch.n_threads;
|
||||
params.tensor_buft_overrides = params.speculative.draft.tensor_buft_overrides;
|
||||
|
||||
// the MoE cache is only used by the target context
|
||||
params.moe_cache_size = 0;
|
||||
|
||||
auto llama_init_dft = common_init_from_params(params);
|
||||
|
||||
model_dft = llama_init_dft->model();
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ project("ggml" C CXX ASM)
|
||||
|
||||
### GGML Version
|
||||
set(GGML_VERSION_MAJOR 0)
|
||||
set(GGML_VERSION_MINOR 28)
|
||||
set(GGML_VERSION_MINOR 29)
|
||||
set(GGML_VERSION_PATCH 0)
|
||||
set(GGML_VERSION_BASE "${GGML_VERSION_MAJOR}.${GGML_VERSION_MINOR}.${GGML_VERSION_PATCH}")
|
||||
|
||||
|
||||
@@ -211,6 +211,18 @@ extern "C" {
|
||||
|
||||
// Context management and operations for faster communication between backends, used for tensor parallelism (meta backend)
|
||||
typedef void * (*ggml_backend_comm_init_t)(ggml_backend_t * backends, size_t n_backends);
|
||||
|
||||
// Builds the communicator for the case where each rank is a separate process, so a process
|
||||
// owns one backend of the communicator rather than all of them.
|
||||
//
|
||||
// The caller provides bootstrap_callback, which moves bytes between the ranks before the
|
||||
// communicator exists. Each rank passes size bytes in send_buf, and recv_buf receives
|
||||
// world_size * size bytes in rank order. The backend decides what to exchange and how many
|
||||
// times to call it, and every rank must make the same calls in the same order.
|
||||
// comm_init_rank blocks until all world_size ranks have joined.
|
||||
typedef bool (*ggml_backend_comm_bootstrap_callback)(void * user_data, const void * send_buf, void * recv_buf, size_t size);
|
||||
typedef void * (*ggml_backend_comm_init_rank_t)(ggml_backend_t backend, int rank, int world_size, ggml_backend_comm_bootstrap_callback bootstrap_callback, void * bootstrap_callback_data);
|
||||
|
||||
typedef void (*ggml_backend_comm_free_t)(void * comm_ctx);
|
||||
typedef bool (*ggml_backend_comm_allreduce_tensor_t)(void * comm_ctx, struct ggml_tensor ** tensors);
|
||||
|
||||
|
||||
+24
-4
@@ -1519,6 +1519,7 @@ extern "C" {
|
||||
// note: this op has undefined behaviour if a given `a` is referenced more than once for a given `b`
|
||||
// (i.e. duplicate experts per token are not guaranteed to be supported in all backends)
|
||||
// TODO: add backend support: https://github.com/ggml-org/llama.cpp/pull/29998#issuecomment-6153742533
|
||||
// the CPU backend skips negative ids, their rows of the result are zero
|
||||
GGML_API struct ggml_tensor * ggml_mul_mat_id(
|
||||
struct ggml_context * ctx,
|
||||
struct ggml_tensor * as,
|
||||
@@ -2034,10 +2035,6 @@ extern "C" {
|
||||
float beta_slow),
|
||||
"use ggml_rope_ext_inplace instead");
|
||||
|
||||
// compute correction dims for YaRN RoPE scaling
|
||||
GGML_API void ggml_rope_yarn_corr_dims(
|
||||
int n_dims, int n_ctx_orig, float freq_base, float beta_fast, float beta_slow, float dims[2]);
|
||||
|
||||
// rotary position embedding backward, i.e compute dx from dy
|
||||
// a - dy
|
||||
GGML_API struct ggml_tensor * ggml_rope_ext_back(
|
||||
@@ -2080,6 +2077,11 @@ extern "C" {
|
||||
struct ggml_tensor * a,
|
||||
int n_offs);
|
||||
|
||||
// control rounding of YaRN correction bounds (default: true)
|
||||
GGML_API struct ggml_tensor * ggml_rope_set_truncate(
|
||||
struct ggml_tensor * a,
|
||||
bool truncate);
|
||||
|
||||
// im2col
|
||||
// converts data into a format that effectively results in a convolution when combined with matrix multiplication
|
||||
GGML_API struct ggml_tensor * ggml_im2col(
|
||||
@@ -2516,6 +2518,24 @@ extern "C" {
|
||||
float max_bias,
|
||||
float logit_softcap);
|
||||
|
||||
// same as ggml_flash_attn_ext, but each q slice attends to its own list of K/V rows
|
||||
// q: [n_embd_k, n_batch, n_head, ne3]
|
||||
// k: [n_embd_k, n_rows, n_head_kv, 1 ] shared by all q slices
|
||||
// v: [n_embd_v, n_rows, n_head_kv, 1 ]
|
||||
// mask: [n_kv, n_batch, ne32, ne3]
|
||||
// kv_rows: [n_kv, ne3] I32, mask column i of slice i3 uses row kv_rows[i, i3] of k and v
|
||||
// negative rows are padding, their mask entries must be -inf
|
||||
GGML_API struct ggml_tensor * ggml_flash_attn_ext_rows(
|
||||
struct ggml_context * ctx,
|
||||
struct ggml_tensor * q,
|
||||
struct ggml_tensor * k,
|
||||
struct ggml_tensor * v,
|
||||
struct ggml_tensor * mask,
|
||||
struct ggml_tensor * kv_rows,
|
||||
float scale,
|
||||
float max_bias,
|
||||
float logit_softcap);
|
||||
|
||||
GGML_DEPRECATED(GGML_API void ggml_flash_attn_ext_set_prec(
|
||||
struct ggml_tensor * a,
|
||||
enum ggml_prec prec),
|
||||
|
||||
@@ -216,6 +216,12 @@ set_target_properties(ggml-base PROPERTIES
|
||||
configure_file(ggml-version.h.in ${CMAKE_CURRENT_BINARY_DIR}/ggml-version.h @ONLY)
|
||||
|
||||
target_include_directories(ggml-base PRIVATE . ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
# icx/icpx default to -fp-model=fast, which contracts and reassociates the reference quantizers, so their output
|
||||
# depends on the compiler; keep ggml-base IEEE-exact so the CPU reference matches gcc/clang builds
|
||||
if (CMAKE_C_COMPILER_ID STREQUAL "IntelLLVM")
|
||||
target_compile_options(ggml-base PRIVATE -fp-model=precise)
|
||||
endif()
|
||||
if (GGML_BACKEND_DL)
|
||||
target_compile_definitions(ggml-base PUBLIC GGML_BACKEND_DL)
|
||||
endif()
|
||||
|
||||
@@ -489,6 +489,32 @@ static struct ggml_tensor * ggml_backend_meta_buffer_simple_tensor(const struct
|
||||
return it->second[index];
|
||||
}
|
||||
|
||||
// bytes spanned by all dims except skip_dim
|
||||
static size_t ggml_backend_meta_inner_extent(const struct ggml_tensor * tensor, int skip_dim) {
|
||||
size_t extent = 0;
|
||||
for (int i = 0; i < GGML_MAX_DIMS; i++) {
|
||||
if (i != skip_dim && tensor->ne[i] > 1) {
|
||||
extent += (size_t) (tensor->ne[i] - 1) * tensor->nb[i];
|
||||
}
|
||||
}
|
||||
return extent;
|
||||
}
|
||||
|
||||
// the view dim that holds the split axis of src, or -1
|
||||
// all other dims of src and view must stay inside one slab of that axis
|
||||
static int ggml_backend_meta_view_slab_dim(const struct ggml_tensor * view, const struct ggml_tensor * src, int axis) {
|
||||
const size_t slab = src->nb[axis];
|
||||
if (ggml_backend_meta_inner_extent(src, axis) >= slab) {
|
||||
return -1;
|
||||
}
|
||||
for (int dim = 0; dim < GGML_MAX_DIMS; dim++) {
|
||||
if (view->ne[dim] == src->ne[axis] && view->nb[dim] == slab) {
|
||||
return ggml_backend_meta_inner_extent(view, dim) < slab ? dim : -1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static struct ggml_backend_meta_split_state ggml_backend_meta_get_split_state(const struct ggml_tensor * tensor, bool assume_sync);
|
||||
|
||||
static struct ggml_backend_meta_split_state ggml_backend_meta_get_split_state(
|
||||
@@ -700,9 +726,39 @@ static struct ggml_backend_meta_split_state ggml_backend_meta_get_split_state(
|
||||
}
|
||||
GGML_ABORT("fatal error");
|
||||
}
|
||||
// permuted view: split the view dim that spans the src split axis, other dims must be inside one element of it or outside the span
|
||||
if (ggml_is_permuted(tensor) && !ggml_is_permuted(tensor->src[0]) && axis >= 0 && axis < GGML_MAX_DIMS-1) {
|
||||
const size_t nb_axis = tensor->src[0]->nb[axis];
|
||||
const size_t nb_next = tensor->src[0]->nb[axis+1];
|
||||
for (int dim = 0; dim < GGML_MAX_DIMS; dim++) {
|
||||
if (tensor->ne[dim] == 1 || tensor->nb[dim] < nb_axis || tensor->nb[dim]*tensor->ne[dim] != nb_next) {
|
||||
continue;
|
||||
}
|
||||
bool others_ok = true;
|
||||
for (int i = 0; i < GGML_MAX_DIMS; i++) {
|
||||
if (i == dim || tensor->ne[i] == 1) {
|
||||
continue;
|
||||
}
|
||||
others_ok = others_ok && (tensor->nb[i]*tensor->ne[i] <= tensor->nb[dim] || tensor->nb[i] % nb_next == 0);
|
||||
}
|
||||
if (others_ok) {
|
||||
return {ggml_backend_meta_split_axis(dim), {0}, {1}, 1};
|
||||
}
|
||||
}
|
||||
}
|
||||
if (src_ss[0].axis == GGML_BACKEND_SPLIT_AXIS_MIRRORED || src_ss[0].axis == GGML_BACKEND_SPLIT_AXIS_PARTIAL) {
|
||||
return src_ss[0];
|
||||
}
|
||||
// a view that only regroups dims inside one slab of the split axis keeps the split,
|
||||
// the per-device strides are only rescaled above nb[axis] (e.g. the KV streams of a permuted q)
|
||||
if (axis >= 0 && axis < GGML_MAX_DIMS && tensor->view_offs == tensor->src[0]->view_offs) {
|
||||
const int dim = ggml_backend_meta_view_slab_dim(tensor, tensor->src[0], axis);
|
||||
if (dim >= 0) {
|
||||
ggml_backend_meta_split_state ret = src_ss[0];
|
||||
ret.axis = ggml_backend_meta_split_axis(dim);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
GGML_ABORT("view of permuted tensor not implemented");
|
||||
//return {GGML_BACKEND_SPLIT_AXIS_UNKNOWN, {0}, {1}, 1};
|
||||
};
|
||||
@@ -1000,8 +1056,13 @@ static struct ggml_backend_meta_split_state ggml_backend_meta_get_split_state(
|
||||
split_state = handle_pad(src_ss);
|
||||
} break;
|
||||
case GGML_OP_PAD_REFLECT_1D:
|
||||
case GGML_OP_ROLL:
|
||||
case GGML_OP_ARANGE:
|
||||
case GGML_OP_ROLL: {
|
||||
split_state = handle_generic(src_ss, /*scalar_only =*/ true);
|
||||
} break;
|
||||
case GGML_OP_ARANGE: {
|
||||
// no sources, every device computes the full range
|
||||
split_state = {GGML_BACKEND_SPLIT_AXIS_MIRRORED, {0}, {1}, 1};
|
||||
} break;
|
||||
case GGML_OP_TIMESTEP_EMBEDDING: {
|
||||
split_state = handle_generic(src_ss, /*scalar_only =*/ true);
|
||||
} break;
|
||||
@@ -1747,13 +1808,14 @@ static ggml_backend_buffer_t ggml_backend_meta_buffer_type_alloc_buffer_n(ggml_b
|
||||
const size_t n_simple_bufts = ggml_backend_meta_buft_n_bufts(buft);
|
||||
|
||||
constexpr size_t compute_headroom = 16; // Maximum number of views per statically allocated tensor that can be created between evals.
|
||||
constexpr size_t compute_headroom_min = 256; // A buffer with few tensors can still get many views, e.g. a KV cache shared by many layers.
|
||||
const ggml_init_params params_static = {
|
||||
/*.mem_size =*/ n_tensors * ggml_tensor_overhead(),
|
||||
/*.mem_buffer =*/ nullptr,
|
||||
/*.no_alloc =*/ true,
|
||||
};
|
||||
const ggml_init_params params_compute = {
|
||||
/*.mem_size =*/ compute_headroom * n_tensors * ggml_tensor_overhead(),
|
||||
/*.mem_size =*/ std::max(compute_headroom * n_tensors, compute_headroom_min) * ggml_tensor_overhead(),
|
||||
/*.mem_buffer =*/ nullptr,
|
||||
/*.no_alloc =*/ true,
|
||||
};
|
||||
|
||||
@@ -1246,6 +1246,14 @@ struct ggml_backend_sched {
|
||||
int prev_graph_size;
|
||||
|
||||
int debug_realloc;
|
||||
|
||||
// inputs of the next split read from the backend of the current split before it computes, see ggml_backend_sched_prefetch_inputs
|
||||
ggml_backend_event_t prefetch_events[GGML_SCHED_MAX_BACKENDS]; // created on first use, NULL if the backend has no events
|
||||
bool prefetch_tried [GGML_SCHED_MAX_BACKENDS];
|
||||
struct ggml_tensor * prefetched[GGML_SCHED_MAX_SPLIT_INPUTS];
|
||||
int n_prefetched;
|
||||
int prefetch_split; // the split that reads the prefetched inputs
|
||||
int prefetch_backend_id; // the backend that copies them
|
||||
};
|
||||
|
||||
#define hash_id(tensor) ggml_hash_find_or_insert(&sched->hash_set, tensor)
|
||||
@@ -2086,6 +2094,16 @@ static void ggml_backend_sched_copy_input(ggml_backend_sched_t sched, struct ggm
|
||||
ggml_backend_t input_backend = ggml_backend_sched_get_tensor_backend(sched, input);
|
||||
struct ggml_tensor * input_cpy = tensor_copy(input, split_backend_id, sched->cur_copy);
|
||||
|
||||
// read before the previous split, wait for the copy only
|
||||
if (split == &sched->splits[sched->prefetch_split]) {
|
||||
for (int i = 0; i < sched->n_prefetched; i++) {
|
||||
if (sched->prefetched[i] == input) {
|
||||
ggml_backend_event_synchronize(sched->prefetch_events[sched->prefetch_backend_id]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (input->flags & GGML_TENSOR_FLAG_INPUT) {
|
||||
// inputs from the user must be copied immediately to prevent the user overwriting the data before the copy is done
|
||||
if (sched->events[split_backend_id][sched->cur_copy] != NULL) {
|
||||
@@ -2122,6 +2140,62 @@ static void ggml_backend_sched_copy_input(ggml_backend_sched_t sched, struct ggm
|
||||
}
|
||||
}
|
||||
|
||||
// the inputs of the next split that are computed on the backend of this split before it, and copied to host memory,
|
||||
// are copied before this split computes, so that the next split waits for these copies instead of this split
|
||||
// e.g. a CPU split runs while a GPU split computes, if it reads only the results of the earlier splits
|
||||
static void ggml_backend_sched_prefetch_inputs(ggml_backend_sched_t sched, int split_id) {
|
||||
sched->n_prefetched = 0;
|
||||
if (split_id + 1 >= sched->n_splits) {
|
||||
return;
|
||||
}
|
||||
struct ggml_backend_sched_split * split = &sched->splits[split_id];
|
||||
struct ggml_backend_sched_split * next = &sched->splits[split_id + 1];
|
||||
const int backend_id = split->backend_id;
|
||||
ggml_backend_t backend = sched->backends[backend_id];
|
||||
if (backend->iface.get_tensor_async == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < next->n_inputs && sched->n_prefetched < GGML_SCHED_MAX_SPLIT_INPUTS; i++) {
|
||||
struct ggml_tensor * input = next->inputs[i];
|
||||
if ((input->flags & GGML_TENSOR_FLAG_INPUT) || tensor_backend_id(input) != backend_id) {
|
||||
continue;
|
||||
}
|
||||
struct ggml_tensor * input_cpy = tensor_copy(input, next->backend_id, sched->cur_copy);
|
||||
if (input_cpy->buffer == NULL || !ggml_backend_buffer_is_host(input_cpy->buffer)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// not if this split computes or writes the input
|
||||
const struct ggml_tensor * base = input->view_src ? input->view_src : input;
|
||||
bool written = false;
|
||||
for (int j = 0; j < split->graph.n_nodes && !written; j++) {
|
||||
const struct ggml_tensor * node = split->graph.nodes[j];
|
||||
written = !ggml_is_view_op(node->op) && (node == base || node->view_src == base);
|
||||
}
|
||||
if (written) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!sched->prefetch_tried[backend_id]) {
|
||||
sched->prefetch_tried[backend_id] = true;
|
||||
sched->prefetch_events[backend_id] = ggml_backend_event_new(backend->device);
|
||||
}
|
||||
if (sched->prefetch_events[backend_id] == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
ggml_backend_tensor_get_async(backend, input, input_cpy->data, 0, ggml_nbytes(input));
|
||||
sched->prefetched[sched->n_prefetched++] = input;
|
||||
}
|
||||
|
||||
if (sched->n_prefetched > 0) {
|
||||
sched->prefetch_split = split_id + 1;
|
||||
sched->prefetch_backend_id = backend_id;
|
||||
ggml_backend_event_record(sched->prefetch_events[backend_id], backend);
|
||||
}
|
||||
}
|
||||
|
||||
static enum ggml_status ggml_backend_sched_compute_splits(ggml_backend_sched_t sched) {
|
||||
GGML_ASSERT(sched);
|
||||
struct ggml_backend_sched_split * splits = sched->splits;
|
||||
@@ -2150,6 +2224,9 @@ static enum ggml_status ggml_backend_sched_compute_splits(ggml_backend_sched_t s
|
||||
ggml_backend_sched_copy_input(sched, split, split->inputs[input_id]);
|
||||
}
|
||||
}
|
||||
// after the copies above, which may read host memory reused by the copies of the next split
|
||||
// before the weights, whose copy callback may queue large uploads
|
||||
ggml_backend_sched_prefetch_inputs(sched, split_id);
|
||||
for (int input_id = 0; input_id < split->n_inputs; input_id++) {
|
||||
if (ggml_backend_sched_is_host_weight(split->inputs[input_id])) {
|
||||
ggml_backend_sched_copy_input(sched, split, split->inputs[input_id]);
|
||||
@@ -2286,6 +2363,7 @@ void ggml_backend_sched_free(ggml_backend_sched_t sched) {
|
||||
for (int c = 0; c < sched->n_copies; c++) {
|
||||
ggml_backend_event_free(sched->events[b][c]);
|
||||
}
|
||||
ggml_backend_event_free(sched->prefetch_events[b]);
|
||||
}
|
||||
ggml_gallocr_free(sched->galloc);
|
||||
ggml_free(sched->ctx);
|
||||
|
||||
@@ -2934,7 +2934,7 @@ void ggml_cann_rope(ggml_backend_cann_context & ctx, ggml_tensor * dst) {
|
||||
const float theta_scale = powf(freq_base, -2.0f / n_dims);
|
||||
|
||||
float corr_dims[2];
|
||||
ggml_rope_yarn_corr_dims(n_dims, n_ctx_orig, freq_base, beta_fast, beta_slow, corr_dims);
|
||||
ggml_rope_yarn_corr_dims(n_dims, n_ctx_orig, freq_base, beta_fast, beta_slow, true, corr_dims);
|
||||
|
||||
bool is_neox = mode & GGML_ROPE_TYPE_NEOX;
|
||||
const bool is_imrope = mode == GGML_ROPE_TYPE_IMROPE; // qwen3vl apply interleaved mrope
|
||||
@@ -3289,7 +3289,7 @@ void ggml_cann_rope_cache_preload(ggml_backend_cann_context & ctx, ggml_tensor *
|
||||
const float theta_scale = powf(freq_base, -2.0f / n_dims);
|
||||
|
||||
float corr_dims[2];
|
||||
ggml_rope_yarn_corr_dims(n_dims, n_ctx_orig, freq_base, beta_fast, beta_slow, corr_dims);
|
||||
ggml_rope_yarn_corr_dims(n_dims, n_ctx_orig, freq_base, beta_fast, beta_slow, true, corr_dims);
|
||||
|
||||
bool is_neox = mode & GGML_ROPE_TYPE_NEOX;
|
||||
const bool is_imrope = mode == GGML_ROPE_TYPE_IMROPE;
|
||||
|
||||
@@ -2547,6 +2547,9 @@ static bool ggml_backend_cann_supports_op(ggml_backend_dev_t dev, const ggml_ten
|
||||
}
|
||||
case GGML_OP_ROPE:
|
||||
{
|
||||
if (!ggml_rope_get_truncate(op)) {
|
||||
return false;
|
||||
}
|
||||
if (((const int32_t *) op->op_params)[15] != 0) {
|
||||
return false; // FIXME: support ggml_rope_set_offset
|
||||
}
|
||||
@@ -2670,6 +2673,10 @@ static bool ggml_backend_cann_supports_op(ggml_backend_dev_t dev, const ggml_ten
|
||||
return true;
|
||||
case GGML_OP_FLASH_ATTN_EXT:
|
||||
{
|
||||
// K/V row lists (ggml_flash_attn_ext_rows) are not supported
|
||||
if (op->src[5] != nullptr) {
|
||||
return false;
|
||||
}
|
||||
#ifdef ASCEND_310P
|
||||
// FA not support on 310p device
|
||||
return false;
|
||||
|
||||
@@ -29,7 +29,7 @@ void ggml_quantize_mat_q8_0_4x8(const float * GGML_RESTRICT x, void * GGML_RESTR
|
||||
assert(k % QK8_0 == 0);
|
||||
const int nb = k / QK8_0;
|
||||
|
||||
#if defined(__riscv_v_intrinsic)
|
||||
#if defined(__riscv_v)
|
||||
block_q8_0x4 * GGML_RESTRICT y = (block_q8_0x4 *) vy;
|
||||
const size_t vl_calc = __riscv_vsetvl_e32m8(QK8_0);
|
||||
const size_t vl_save = __riscv_vsetvl_e64m2(4);
|
||||
|
||||
@@ -345,7 +345,7 @@ static inline int32x4_t ggml_nvfp4_dot8(const int8x8_t q4_lo, const int8x8_t q8_
|
||||
#include <immintrin.h>
|
||||
#endif
|
||||
|
||||
#ifdef __riscv_v_intrinsic
|
||||
#if defined(__riscv_v)
|
||||
#include <riscv_vector.h>
|
||||
#endif
|
||||
|
||||
|
||||
@@ -224,8 +224,8 @@ static const struct ggml_type_traits_cpu type_traits_cpu[GGML_TYPE_COUNT] = {
|
||||
},
|
||||
[GGML_TYPE_F16] = {
|
||||
.from_float = (ggml_from_float_t) ggml_cpu_fp32_to_fp16,
|
||||
.vec_dot = (ggml_vec_dot_t) ggml_vec_dot_f16,
|
||||
.vec_dot_type = GGML_TYPE_F16,
|
||||
.vec_dot = (ggml_vec_dot_t) ggml_vec_dot_f16_f32,
|
||||
.vec_dot_type = GGML_TYPE_F32,
|
||||
.nrows = 1,
|
||||
},
|
||||
[GGML_TYPE_Q1_0] = {
|
||||
@@ -746,7 +746,7 @@ static void ggml_init_arm_arch_features(void) {}
|
||||
#endif
|
||||
#endif // __ARM_ARCH
|
||||
|
||||
#if defined(__riscv) && defined(__riscv_v_intrinsic)
|
||||
#if defined(__riscv) && defined(__riscv_v)
|
||||
#include <riscv_vector.h>
|
||||
static void ggml_init_riscv_arch_features(void) {
|
||||
ggml_riscv_arch_features.rvv_vlen = __riscv_vlenb();
|
||||
@@ -1284,9 +1284,12 @@ void ggml_compute_forward_mul_mat(
|
||||
const int ith = params->ith;
|
||||
const int nth = params->nth;
|
||||
|
||||
enum ggml_type const vec_dot_type = type_traits_cpu[src0->type].vec_dot_type;
|
||||
ggml_from_float_t const from_float = type_traits_cpu[vec_dot_type].from_float;
|
||||
int64_t const vec_dot_num_rows = type_traits_cpu[src0->type].nrows;
|
||||
enum ggml_type const vec_dot_type = type_traits_cpu[src0->type].vec_dot_type;
|
||||
ggml_from_float_t const from_float = type_traits_cpu[vec_dot_type].from_float;
|
||||
int64_t const vec_dot_num_rows = type_traits_cpu[src0->type].nrows;
|
||||
|
||||
// TODO: a more efficient F16 x F16 path can be used here if ggml_prec_get_src(dst, 1) allows converting src1 to F16
|
||||
// the code needs to be refactored to enable this (src1 is currently converted based on vec_dot_type alone)
|
||||
|
||||
GGML_ASSERT(ne0 == ne01);
|
||||
GGML_ASSERT(ne1 == ne11);
|
||||
@@ -1509,8 +1512,8 @@ static void ggml_compute_forward_mul_mat_id_one_chunk(
|
||||
|
||||
const enum ggml_type type = src0->type;
|
||||
|
||||
ggml_vec_dot_t const vec_dot = type_traits_cpu[type].vec_dot;
|
||||
enum ggml_type const vec_dot_type = type_traits_cpu[type].vec_dot_type;
|
||||
ggml_vec_dot_t const vec_dot = type_traits_cpu[type].vec_dot;
|
||||
enum ggml_type const vec_dot_type = type_traits_cpu[type].vec_dot_type;
|
||||
|
||||
const int64_t blck_0 = 16;
|
||||
const int64_t blck_1 = 16;
|
||||
@@ -1577,8 +1580,11 @@ static void ggml_compute_forward_mul_mat_id(
|
||||
|
||||
const bool src1_cont = ggml_is_contiguous(src1);
|
||||
|
||||
enum ggml_type const vec_dot_type = type_traits_cpu[type].vec_dot_type;
|
||||
ggml_from_float_t const from_float = type_traits_cpu[vec_dot_type].from_float;
|
||||
enum ggml_type const vec_dot_type = type_traits_cpu[type].vec_dot_type;
|
||||
ggml_from_float_t const from_float = type_traits_cpu[vec_dot_type].from_float;
|
||||
|
||||
// TODO: a more efficient F16 x F16 path can be used here if ggml_prec_get_src(dst, 1) allows converting src1 to F16
|
||||
// the code needs to be refactored to enable this (src1 is currently converted based on vec_dot_type alone)
|
||||
|
||||
// we don't support permuted src0 or src1
|
||||
GGML_ASSERT(nb00 == ggml_type_size(type));
|
||||
@@ -2965,8 +2971,8 @@ struct ggml_cplan ggml_graph_plan(
|
||||
if ((node->src[0]->type == GGML_TYPE_F16 ||
|
||||
node->src[0]->type == GGML_TYPE_BF16) &&
|
||||
node->src[1]->type == GGML_TYPE_F32) {
|
||||
cur += sizeof(float)*ne10*ne11;
|
||||
cur += sizeof(ggml_fp16_t)*ne00*ne01*ne02;
|
||||
cur += sizeof(ggml_fp16_t)*ne10*ne11;
|
||||
} else if (node->src[0]->type == GGML_TYPE_F32 &&
|
||||
node->src[1]->type == GGML_TYPE_F32) {
|
||||
cur += sizeof(float)*ne00*ne01*ne02;
|
||||
@@ -2995,8 +3001,8 @@ struct ggml_cplan ggml_graph_plan(
|
||||
GGML_ASSERT(node->src[0]->type == GGML_TYPE_F16 || node->src[0]->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(node->src[1]->type == GGML_TYPE_F32);
|
||||
|
||||
cur += sizeof(float) * ne10 * ne11 * ne12 * ne13;
|
||||
cur += ggml_type_size(node->src[0]->type) * ne00 * ne01 * ne02 * ne03;
|
||||
cur += ggml_type_size(node->src[0]->type) * ne10 * ne11 * ne12 * ne13;
|
||||
|
||||
} break;
|
||||
case GGML_OP_TOP_K:
|
||||
@@ -3556,7 +3562,7 @@ void ggml_cpu_fp16_to_fp32(const ggml_fp16_t * x, float * y, int64_t n) {
|
||||
_mm_storeu_ps(y + i, y_vec);
|
||||
}
|
||||
|
||||
#elif defined(__riscv_v_intrinsic) && defined(__riscv_zvfhmin)
|
||||
#elif defined(__riscv_v) && defined(__riscv_zvfhmin)
|
||||
// calculate step size
|
||||
const int epr = __riscv_vsetvlmax_e16m2();
|
||||
const int step = epr * 2;
|
||||
@@ -3626,7 +3632,7 @@ void ggml_cpu_bf16_to_fp32(const ggml_bf16_t * x, float * y, int64_t n) {
|
||||
(const __m128i *)(x + i))),
|
||||
16)));
|
||||
}
|
||||
#elif defined(__riscv_v_intrinsic) && defined(__riscv_zvfbfmin)
|
||||
#elif defined(__riscv_v) && defined(__riscv_zvfbfmin)
|
||||
// calculate step size
|
||||
const int epr = __riscv_vsetvlmax_e16m2();
|
||||
const int step = epr * 2;
|
||||
@@ -3746,7 +3752,7 @@ int ggml_cpu_has_arm_fma(void) {
|
||||
}
|
||||
|
||||
int ggml_cpu_has_riscv_v(void) {
|
||||
#if defined(__riscv_v_intrinsic)
|
||||
#if defined(__riscv_v)
|
||||
return 1;
|
||||
#else
|
||||
return 0;
|
||||
@@ -3754,7 +3760,7 @@ int ggml_cpu_has_riscv_v(void) {
|
||||
}
|
||||
|
||||
int ggml_cpu_get_rvv_vlen(void) {
|
||||
#if defined(__riscv) && defined(__riscv_v_intrinsic)
|
||||
#if defined(__riscv) && defined(__riscv_v)
|
||||
return ggml_riscv_arch_features.rvv_vlen;
|
||||
#else
|
||||
return 0;
|
||||
|
||||
@@ -455,10 +455,11 @@ static bool ggml_backend_cpu_device_supports_op(ggml_backend_dev_t dev, const st
|
||||
src0->type == GGML_TYPE_F32 && op->type == GGML_TYPE_F32) {
|
||||
return src1->type == GGML_TYPE_F32 || src1->type == GGML_TYPE_F16;
|
||||
}
|
||||
// BF16 in src1 is widened into the F32 work buffer
|
||||
// F16 or BF16 in src1 is widened into the F32 work buffer
|
||||
return src1->type == GGML_TYPE_F32 ||
|
||||
src1->type == ggml_get_type_traits_cpu(src0->type)->vec_dot_type ||
|
||||
(src1->type == GGML_TYPE_BF16 && ggml_get_type_traits_cpu(src0->type)->vec_dot_type == GGML_TYPE_F32);
|
||||
((src1->type == GGML_TYPE_F16 || src1->type == GGML_TYPE_BF16) &&
|
||||
ggml_get_type_traits_cpu(src0->type)->vec_dot_type == GGML_TYPE_F32);
|
||||
case GGML_OP_SOFT_MAX_BACK: {
|
||||
if (op->src[0]->type != GGML_TYPE_F32 || op->src[1]->type != GGML_TYPE_F32) {
|
||||
return false;
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
#define VECTOR_REGISTERS 16
|
||||
#endif
|
||||
|
||||
#if defined(__riscv_v_intrinsic)
|
||||
#if defined(__riscv_v)
|
||||
#define LMUL 4
|
||||
#endif
|
||||
|
||||
@@ -180,7 +180,7 @@ inline float32x4_t madd(float32x4_t a, float32x4_t b, float32x4_t c) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__riscv_v_intrinsic)
|
||||
#if defined(__riscv_v)
|
||||
template <> inline vfloat32m1_t madd(vfloat32m1_t a, vfloat32m1_t b, vfloat32m1_t c) {
|
||||
return __riscv_vfmacc_vv_f32m1(c, a, b, __riscv_vsetvlmax_e32m1());
|
||||
}
|
||||
@@ -277,7 +277,7 @@ inline float hsum(__m512 x) {
|
||||
}
|
||||
#endif // __AVX512F__
|
||||
|
||||
#if defined(__riscv_v_intrinsic)
|
||||
#if defined(__riscv_v)
|
||||
inline float hsum(vfloat32m1_t x) {
|
||||
return __riscv_vfmv_f_s_f32m1_f32(
|
||||
__riscv_vfredusum_vs_f32m1_f32m1(x, __riscv_vfmv_v_f_f32m1(0, 1), __riscv_vsetvlmax_e32m1()));
|
||||
@@ -326,6 +326,12 @@ template <> inline float32x4_t load(const ggml_fp16_t * p) {
|
||||
|
||||
return vec_xl(0, (const float *)(tmp));
|
||||
}
|
||||
template <> inline float32x4_t load(const ggml_bf16_t * p) {
|
||||
uint64_t bits;
|
||||
memcpy(&bits, p, sizeof(bits));
|
||||
const uint64x2_t v_bits = { bits, bits };
|
||||
return GGML_BF16_TO_F32_HI((GGML_BF16_VEC) v_bits);
|
||||
}
|
||||
template <> inline float32x4_t load(const float * p) {
|
||||
return vec_xl(0, p);
|
||||
}
|
||||
@@ -458,7 +464,7 @@ template <> inline __m512bh load_partial(const ggml_bf16_t *p, int n) {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__riscv_v_intrinsic)
|
||||
#if defined(__riscv_v)
|
||||
template <> inline vfloat32m1_t load(const float *p) {
|
||||
return __riscv_vle32_v_f32m1(p, __riscv_vsetvlmax_e32m1());
|
||||
}
|
||||
@@ -503,7 +509,7 @@ template <> inline vbfloat16m4_t load(const ggml_bf16_t *p) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__riscv_v_intrinsic)
|
||||
#if defined(__riscv_v)
|
||||
template <typename T> T set_zero();
|
||||
|
||||
template <> inline vfloat32m1_t set_zero() {
|
||||
@@ -520,7 +526,7 @@ template <> inline vfloat32m8_t set_zero() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__riscv_v_intrinsic)
|
||||
#if defined(__riscv_v)
|
||||
template <typename T> size_t vlmax() {
|
||||
if constexpr (std::is_same_v<T, vfloat32m1_t>) { return __riscv_vsetvlmax_e32m1(); }
|
||||
else if constexpr (std::is_same_v<T, vfloat32m2_t>) { return __riscv_vsetvlmax_e32m2(); }
|
||||
@@ -732,7 +738,7 @@ class tinyBLAS {
|
||||
const int64_t ldc;
|
||||
};
|
||||
|
||||
#if defined(__riscv_v_intrinsic)
|
||||
#if defined(__riscv_v)
|
||||
template <typename D, typename V, typename TA, typename TB, typename TC>
|
||||
class tinyBLAS_RVV {
|
||||
public:
|
||||
@@ -1302,6 +1308,88 @@ class tinyBLAS_RVV {
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// QUANT ZERO MATRIX MULTIPLICATION
|
||||
|
||||
#if defined(__VXE__) || defined(__VXE2__)
|
||||
template <typename TA>
|
||||
class tinyBLAS_Q0_VXE {
|
||||
static_assert(sizeof(TA::qs) == QK8_0, "VXE weight loads require 32 quantized bytes per block");
|
||||
|
||||
public:
|
||||
tinyBLAS_Q0_VXE(int64_t k,
|
||||
const TA * A, int64_t lda,
|
||||
const block_q8_0 * B, int64_t ldb,
|
||||
float * C, int64_t ldc,
|
||||
int32_t ith, int32_t nth)
|
||||
: A(A), B(B), C(C), k(k), lda(lda), ldb(ldb), ldc(ldc), ith(ith), nth(nth) {
|
||||
}
|
||||
|
||||
void matmul(int64_t m, int64_t n) {
|
||||
constexpr int32_t tile_size = 2;
|
||||
const int64_t row_tiles = m / tile_size;
|
||||
const int64_t tiles = row_tiles * (n / tile_size);
|
||||
const int64_t duty = (tiles + nth - 1) / nth;
|
||||
const int64_t start = duty * ith;
|
||||
const int64_t end = MIN(start + duty, tiles);
|
||||
|
||||
for (int64_t job = start; job < end; ++job) {
|
||||
const int64_t ii = tile_size * (job % row_tiles);
|
||||
const int64_t jj = tile_size * (job / row_tiles);
|
||||
float32x4_t v_sum[tile_size][tile_size] = {};
|
||||
|
||||
for (int64_t l = 0; l < k; ++l) {
|
||||
int8x16_t v_xl[tile_size], v_xh[tile_size], v_yl[tile_size], v_yh[tile_size];
|
||||
float x_scale[tile_size], y_scale[tile_size];
|
||||
|
||||
for (int32_t i = 0; i < tile_size; ++i) {
|
||||
const TA & x = A[lda * (ii + i) + l];
|
||||
const block_q8_0 & y = B[ldb * (jj + i) + l];
|
||||
|
||||
const int8_t * x_qs = x.qs;
|
||||
const int8_t * y_qs = y.qs;
|
||||
v_xl[i] = vec_xl(0, x_qs);
|
||||
v_xh[i] = vec_xl(0, x_qs + QK8_0 / 2);
|
||||
v_yl[i] = vec_xl(0, y_qs);
|
||||
v_yh[i] = vec_xl(0, y_qs + QK8_0 / 2);
|
||||
x_scale[i] = unhalf(x.d);
|
||||
y_scale[i] = unhalf(y.d);
|
||||
}
|
||||
|
||||
for (int32_t j = 0; j < tile_size; ++j) {
|
||||
for (int32_t i = 0; i < tile_size; ++i) {
|
||||
const int32x4_t v_dot = dot_s8_wide(v_xl[i], v_yl[j]) + dot_s8_wide(v_xh[i], v_yh[j]);
|
||||
const float32x4_t v_scale = vec_splats(x_scale[i] * y_scale[j]);
|
||||
v_sum[j][i] = vec_madd(vec_float(v_dot), v_scale, v_sum[j][i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int32_t j = 0; j < tile_size; ++j) {
|
||||
for (int32_t i = 0; i < tile_size; ++i) {
|
||||
C[ldc * (jj + j) + ii + i] = hsum(v_sum[j][i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static int32x4_t dot_s8_wide(int8x16_t v_x, int8x16_t v_y) {
|
||||
const int16x8_t v_even = vec_mule(v_x, v_y);
|
||||
const int16x8_t v_odd = vec_mulo(v_x, v_y);
|
||||
// Two (-128) * (-128) products can overflow a signed 16-bit sum.
|
||||
return vec_unpackh(v_even) + vec_unpackl(v_even) + vec_unpackh(v_odd) + vec_unpackl(v_odd);
|
||||
}
|
||||
|
||||
const TA * const A;
|
||||
const block_q8_0 * const B;
|
||||
float * const C;
|
||||
const int64_t k;
|
||||
const int64_t lda;
|
||||
const int64_t ldb;
|
||||
const int64_t ldc;
|
||||
const int32_t ith;
|
||||
const int32_t nth;
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(__ARM_FEATURE_DOTPROD)
|
||||
template <typename TA>
|
||||
class tinyBLAS_Q0_ARM {
|
||||
@@ -3958,7 +4046,7 @@ bool llamafile_sgemm(const struct ggml_compute_params * params, int64_t m, int64
|
||||
params->ith, params->nth};
|
||||
tb.matmul(m, n);
|
||||
return true;
|
||||
#elif defined(__riscv_v_intrinsic)
|
||||
#elif defined(__riscv_v)
|
||||
#if LMUL == 1
|
||||
tinyBLAS_RVV<vfloat32m1_t, vfloat32m1_t, float, float, float> tb{ params,
|
||||
k, (const float *)A, lda,
|
||||
@@ -4006,6 +4094,14 @@ bool llamafile_sgemm(const struct ggml_compute_params * params, int64_t m, int64
|
||||
(float *)C, ldc};
|
||||
return tb.matmul(m, n);
|
||||
}
|
||||
#elif defined(__VXE__) || defined(__VXE2__)
|
||||
if (Btype == GGML_TYPE_BF16) {
|
||||
tinyBLAS<4, float32x4_t, float32x4_t, ggml_bf16_t, ggml_bf16_t, float> tb{ params, k,
|
||||
(const ggml_bf16_t *)A, lda,
|
||||
(const ggml_bf16_t *)B, ldb,
|
||||
(float *)C, ldc};
|
||||
return tb.matmul(m, n);
|
||||
}
|
||||
#elif defined(__MMA__)
|
||||
if (k % 8) {
|
||||
return false;
|
||||
@@ -4054,6 +4150,13 @@ bool llamafile_sgemm(const struct ggml_compute_params * params, int64_t m, int64
|
||||
(float *)C, ldc};
|
||||
return tb.matmul(m, n);
|
||||
}
|
||||
if (Btype == GGML_TYPE_F32) {
|
||||
tinyBLAS<16, __m512, __m512, ggml_fp16_t, float, float> tb{ params, k,
|
||||
(const ggml_fp16_t *)A, lda,
|
||||
(const float *)B, ldb,
|
||||
(float *)C, ldc};
|
||||
return tb.matmul(m, n);
|
||||
}
|
||||
#elif (defined(__AVX__) || defined(__AVX2__)) && defined(__F16C__)
|
||||
if (Btype == GGML_TYPE_F16) {
|
||||
tinyBLAS<8, __m256, __m256, ggml_fp16_t, ggml_fp16_t, float> tb{ params, k,
|
||||
@@ -4062,6 +4165,13 @@ bool llamafile_sgemm(const struct ggml_compute_params * params, int64_t m, int64
|
||||
(float *)C, ldc};
|
||||
return tb.matmul(m, n);
|
||||
}
|
||||
if (Btype == GGML_TYPE_F32) {
|
||||
tinyBLAS<8, __m256, __m256, ggml_fp16_t, float, float> tb{ params, k,
|
||||
(const ggml_fp16_t *)A, lda,
|
||||
(const float *)B, ldb,
|
||||
(float *)C, ldc};
|
||||
return tb.matmul(m, n);
|
||||
}
|
||||
#elif defined(__ARM_FEATURE_FP16_VECTOR_ARITHMETIC) && !defined(_MSC_VER)
|
||||
if (n < 8)
|
||||
return false;
|
||||
@@ -4148,6 +4258,17 @@ bool llamafile_sgemm(const struct ggml_compute_params * params, int64_t m, int64
|
||||
params->ith, params->nth};
|
||||
tb.matmul(m, n);
|
||||
return true;
|
||||
#elif defined(__VXE__) || defined(__VXE2__)
|
||||
if (m % 2 || n % 2) {
|
||||
return false;
|
||||
}
|
||||
tinyBLAS_Q0_VXE<block_q8_0> tb{
|
||||
k, (const block_q8_0 *)A, lda,
|
||||
(const block_q8_0 *)B, ldb,
|
||||
(float *)C, ldc,
|
||||
params->ith, params->nth};
|
||||
tb.matmul(m, n);
|
||||
return true;
|
||||
#elif defined(__MMA__)
|
||||
//TO-DO: Remove this condition once gemv forwarding is enabled.
|
||||
if (n < 8 && n != 4)
|
||||
|
||||
+100
-98
@@ -6310,8 +6310,8 @@ static void ggml_compute_forward_rope_flt(
|
||||
//const int n_past = ((int32_t *) dst->op_params)[0];
|
||||
const int n_dims = ((int32_t *) dst->op_params)[1];
|
||||
const int mode = ((int32_t *) dst->op_params)[2];
|
||||
//const int n_ctx = ((int32_t *) dst->op_params)[3];
|
||||
const int n_ctx_orig = ((int32_t *) dst->op_params)[4];
|
||||
const bool truncate = ggml_rope_get_truncate(dst);
|
||||
|
||||
memcpy(&freq_base, (int32_t *) dst->op_params + 5, sizeof(float));
|
||||
memcpy(&freq_scale, (int32_t *) dst->op_params + 6, sizeof(float));
|
||||
@@ -6356,7 +6356,7 @@ static void ggml_compute_forward_rope_flt(
|
||||
const float theta_scale = powf(freq_base, -2.0f/n_dims);
|
||||
|
||||
float corr_dims[2];
|
||||
ggml_rope_yarn_corr_dims(n_dims, n_ctx_orig, freq_base, beta_fast, beta_slow, corr_dims);
|
||||
ggml_rope_yarn_corr_dims(n_dims, n_ctx_orig, freq_base, beta_fast, beta_slow, truncate, corr_dims);
|
||||
|
||||
const bool is_imrope = mode == GGML_ROPE_TYPE_IMROPE; // qwen3vl apply interleaved mrope
|
||||
const bool mrope_used = mode & GGML_ROPE_TYPE_MROPE; // ggml_rope_multi, note: also true for vision (24 & 8 == true) and for imrope
|
||||
@@ -6514,17 +6514,28 @@ static void ggml_compute_forward_conv_transpose_1d_f16_f32(
|
||||
const int ith = params->ith;
|
||||
const int nth = params->nth;
|
||||
|
||||
const int nk = ne00*ne01*ne02;
|
||||
|
||||
GGML_ASSERT(nb00 == sizeof(ggml_fp16_t));
|
||||
GGML_ASSERT(nb10 == sizeof(float));
|
||||
|
||||
if (ith == 0) {
|
||||
memset(params->wdata, 0, params->wsize);
|
||||
|
||||
// permute source data (src1) from (L x Cin) to (Cin x L)
|
||||
{
|
||||
float * const wdata = (float *) params->wdata + 0;
|
||||
float * dst_data = wdata;
|
||||
|
||||
for (int64_t i11 = 0; i11 < ne11; i11++) {
|
||||
const float * const src = (float *)((char *) src1->data + i11*nb11);
|
||||
for (int64_t i10 = 0; i10 < ne10; i10++) {
|
||||
dst_data[i10*ne11 + i11] = src[i10];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// permute kernel data (src0) from (K x Cout x Cin) to (Cin x K x Cout)
|
||||
{
|
||||
ggml_fp16_t * const wdata = (ggml_fp16_t *) params->wdata + 0;
|
||||
ggml_fp16_t * const wdata = (ggml_fp16_t *)((char *) params->wdata + ne10*ne11*sizeof(float));
|
||||
|
||||
for (int64_t i02 = 0; i02 < ne02; i02++) {
|
||||
for (int64_t i01 = 0; i01 < ne01; i01++) {
|
||||
@@ -6537,19 +6548,6 @@ static void ggml_compute_forward_conv_transpose_1d_f16_f32(
|
||||
}
|
||||
}
|
||||
|
||||
// permute source data (src1) from (L x Cin) to (Cin x L)
|
||||
{
|
||||
ggml_fp16_t * const wdata = (ggml_fp16_t *) params->wdata + nk;
|
||||
ggml_fp16_t * dst_data = wdata;
|
||||
|
||||
for (int64_t i11 = 0; i11 < ne11; i11++) {
|
||||
const float * const src = (float *)((char *) src1->data + i11*nb11);
|
||||
for (int64_t i10 = 0; i10 < ne10; i10++) {
|
||||
dst_data[i10*ne11 + i11] = GGML_CPU_FP32_TO_FP16(src[i10]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// need to zero dst since we are accumulating into it
|
||||
memset(dst->data, 0, ggml_nbytes(dst));
|
||||
}
|
||||
@@ -6567,19 +6565,19 @@ static void ggml_compute_forward_conv_transpose_1d_f16_f32(
|
||||
const int ir0 = dr*ith;
|
||||
const int ir1 = MIN(ir0 + dr, nr);
|
||||
|
||||
ggml_fp16_t * const wdata = (ggml_fp16_t *) params->wdata + 0;
|
||||
ggml_fp16_t * const wdata_src = wdata + nk;
|
||||
float * const wdata_src = (float *) params->wdata + 0;
|
||||
ggml_fp16_t * const wdata_kernel = (ggml_fp16_t *)((char *) params->wdata + ne10*ne11*sizeof(float));
|
||||
|
||||
for (int i1 = ir0; i1 < ir1; i1++) {
|
||||
float * dst_data = (float *)((char *) dst->data + i1*nb1);
|
||||
ggml_fp16_t * wdata_kernel = wdata + i1*ne02*ne00;
|
||||
ggml_fp16_t * wdata_kernel_row = wdata_kernel + i1*ne02*ne00;
|
||||
for (int i10 = 0; i10 < ne10; i10++) {
|
||||
const int i1n = i10*ne11;
|
||||
for (int i00 = 0; i00 < ne00; i00++) {
|
||||
float v = 0;
|
||||
ggml_vec_dot_f16(ne02, &v, 0,
|
||||
(ggml_fp16_t *) wdata_src + i1n, 0,
|
||||
(ggml_fp16_t *) wdata_kernel + i00*ne02, 0, 1);
|
||||
ggml_vec_dot_f16_f32(ne02, &v, 0,
|
||||
wdata_kernel_row + i00*ne02, 0,
|
||||
wdata_src + i1n, 0, 1);
|
||||
dst_data[i10*s0 + i00] += v;
|
||||
}
|
||||
}
|
||||
@@ -7172,29 +7170,30 @@ void ggml_compute_forward_im2col_3d(
|
||||
}
|
||||
}
|
||||
|
||||
static void ggml_call_mul_mat(ggml_type type, const ggml_compute_params * params, int64_t m, int64_t n, int64_t k,
|
||||
static void ggml_call_mul_mat(ggml_type src0_type, ggml_type src1_type, const ggml_compute_params * params, int64_t m, int64_t n, int64_t k,
|
||||
void * a, void * b, float * c) {
|
||||
const ggml_type_traits * traits = ggml_get_type_traits(type);
|
||||
const ggml_type_traits * traits0 = ggml_get_type_traits(src0_type);
|
||||
const ggml_type_traits * traits1 = ggml_get_type_traits(src1_type);
|
||||
struct ggml_tensor src1 = {};
|
||||
src1.type = type;
|
||||
src1.type = src1_type;
|
||||
src1.ne[0] = k;
|
||||
src1.ne[1] = m;
|
||||
src1.ne[2] = 1;
|
||||
src1.ne[3] = 1;
|
||||
src1.nb[0] = traits->type_size;
|
||||
src1.nb[1] = k * traits->type_size;
|
||||
src1.nb[0] = traits1->type_size;
|
||||
src1.nb[1] = k * traits1->type_size;
|
||||
src1.nb[2] = src1.nb[1];
|
||||
src1.nb[3] = src1.nb[2];
|
||||
src1.data = a;
|
||||
|
||||
struct ggml_tensor src0 = {};
|
||||
src0.type = type;
|
||||
src0.type = src0_type;
|
||||
src0.ne[0] = k;
|
||||
src0.ne[1] = n;
|
||||
src0.ne[2] = 1;
|
||||
src0.ne[3] = 1;
|
||||
src0.nb[0] = traits->type_size;
|
||||
src0.nb[1] = k * traits->type_size;
|
||||
src0.nb[0] = traits0->type_size;
|
||||
src0.nb[1] = k * traits0->type_size;
|
||||
src0.nb[2] = src0.nb[1];
|
||||
src0.nb[3] = src0.nb[2];
|
||||
src0.data = b;
|
||||
@@ -7304,8 +7303,6 @@ static void ggml_compute_forward_conv_2d_impl(const ggml_compute_params * params
|
||||
GGML_ASSERT(kernel_type == GGML_TYPE_F16 || kernel_type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(kernel->type == kernel_type);
|
||||
|
||||
const ggml_type_traits * traits = ggml_get_type_traits(kernel_type);
|
||||
|
||||
const int32_t stride_x = dst->op_params[0];
|
||||
const int32_t stride_y = dst->op_params[1];
|
||||
const int32_t pad_x = dst->op_params[2];
|
||||
@@ -7331,7 +7328,7 @@ static void ggml_compute_forward_conv_2d_impl(const ggml_compute_params * params
|
||||
const int64_t knl_n = knl_w * knl_h * c_in;
|
||||
const int64_t patch_total = dst->ne[3] * dst_w * dst_h;
|
||||
|
||||
const int64_t space_per_patch = knl_n * traits->type_size + c_out * sizeof(float);
|
||||
const int64_t space_per_patch = knl_n * sizeof(float) + c_out * sizeof(float);
|
||||
const int64_t batch_size = params->wsize / space_per_patch;
|
||||
const int64_t patches_per_batch = batch_size > 8 ? (batch_size / 8) * 8 : batch_size;
|
||||
const int64_t batch_n = (patch_total + patches_per_batch - 1) / patches_per_batch;
|
||||
@@ -7358,7 +7355,7 @@ static void ggml_compute_forward_conv_2d_impl(const ggml_compute_params * params
|
||||
const int64_t src_y = p % dst_w;
|
||||
|
||||
const float * src_base = (const float *)((const char *)src_data + batch_n * src->nb[3]);
|
||||
char * dst_row = (char *) tmp + (p % patches_per_batch) * knl_n * traits->type_size;
|
||||
float * dst_row = (float *) tmp + (p % patches_per_batch) * knl_n;
|
||||
|
||||
for (int64_t ic = 0; ic < c_in; ++ic) {
|
||||
for (int64_t ky = 0; ky < knl_h; ++ky) {
|
||||
@@ -7376,12 +7373,7 @@ static void ggml_compute_forward_conv_2d_impl(const ggml_compute_params * params
|
||||
src_val = *src_ptr;
|
||||
}
|
||||
|
||||
char * element_ptr = dst_row + dst_idx * traits->type_size;
|
||||
if (kernel_type == GGML_TYPE_F32) {
|
||||
*(float *) element_ptr = src_val;
|
||||
} else if (kernel_type == GGML_TYPE_F16) {
|
||||
*(ggml_fp16_t *) element_ptr = GGML_CPU_FP32_TO_FP16(src_val);
|
||||
}
|
||||
dst_row[dst_idx] = src_val;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7389,12 +7381,12 @@ static void ggml_compute_forward_conv_2d_impl(const ggml_compute_params * params
|
||||
|
||||
ggml_barrier(params->threadpool);
|
||||
|
||||
float * gemm_output = (float *) ((char *) tmp + patches_per_batch * knl_n * traits->type_size);
|
||||
float * gemm_output = (float *) ((char *) tmp + patches_per_batch * knl_n * sizeof(float));
|
||||
|
||||
GGML_ASSERT(gemm_output + patch_n * c_out <= (float*)tmp + params->wsize);
|
||||
|
||||
// GEMM: patches[patch_n, knl_n] × kernel[knl_n, c_out] = output[patch_n, c_out]
|
||||
ggml_call_mul_mat(kernel_type, params, patch_n, c_out, knl_n, tmp, knl_data, gemm_output);
|
||||
ggml_call_mul_mat(kernel_type, GGML_TYPE_F32, params, patch_n, c_out, knl_n, tmp, knl_data, gemm_output);
|
||||
|
||||
ggml_barrier(params->threadpool);
|
||||
|
||||
@@ -7441,8 +7433,6 @@ static void ggml_compute_forward_conv_3d_impl(const ggml_compute_params * params
|
||||
GGML_ASSERT(kernel_type == GGML_TYPE_F16 || kernel_type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(kernel->type == kernel_type);
|
||||
|
||||
const ggml_type_traits * traits = ggml_get_type_traits(kernel_type);
|
||||
|
||||
const int32_t s0 = dst->op_params[0];
|
||||
const int32_t s1 = dst->op_params[1];
|
||||
const int32_t s2 = dst->op_params[2];
|
||||
@@ -7474,7 +7464,7 @@ static void ggml_compute_forward_conv_3d_impl(const ggml_compute_params * params
|
||||
const int64_t knl_n_total = knl_n_per_channel * c;
|
||||
const int64_t patch_total = n * dst_w * dst_h * dst_d;
|
||||
|
||||
const int64_t space_per_patch = knl_n_total * traits->type_size + oc * sizeof(float);
|
||||
const int64_t space_per_patch = knl_n_total * sizeof(float) + oc * sizeof(float);
|
||||
const int64_t batch_size = params->wsize / space_per_patch;
|
||||
const int64_t patches_per_batch = batch_size > 8 ? (batch_size / 8) * 8 : batch_size;
|
||||
const int64_t batch_n = (patch_total + patches_per_batch - 1) / patches_per_batch;
|
||||
@@ -7500,7 +7490,7 @@ static void ggml_compute_forward_conv_3d_impl(const ggml_compute_params * params
|
||||
const int64_t dst_y = p_in_depth / dst_w;
|
||||
const int64_t dst_x = p_in_depth % dst_w;
|
||||
|
||||
char * dst_row = (char *) tmp + (p % patches_per_batch) * knl_n_total * traits->type_size;
|
||||
float * dst_row = (float *) tmp + (p % patches_per_batch) * knl_n_total;
|
||||
|
||||
for (int64_t ic = 0; ic < c; ++ic) {
|
||||
for (int64_t kz = 0; kz < knl_d; ++kz) {
|
||||
@@ -7521,12 +7511,7 @@ static void ggml_compute_forward_conv_3d_impl(const ggml_compute_params * params
|
||||
src_val = *src_ptr;
|
||||
}
|
||||
|
||||
char * element_ptr = dst_row + dst_idx * traits->type_size;
|
||||
if (kernel_type == GGML_TYPE_F32) {
|
||||
*(float *)element_ptr = src_val;
|
||||
} else if (kernel_type == GGML_TYPE_F16) {
|
||||
*(ggml_fp16_t *)element_ptr = GGML_CPU_FP32_TO_FP16(src_val);
|
||||
}
|
||||
dst_row[dst_idx] = src_val;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7535,8 +7520,8 @@ static void ggml_compute_forward_conv_3d_impl(const ggml_compute_params * params
|
||||
|
||||
ggml_barrier(params->threadpool);
|
||||
|
||||
float * gemm_output = (float *) ((char *) tmp + patches_per_batch * knl_n_total * traits->type_size);
|
||||
ggml_call_mul_mat(kernel_type, params, patch_n_in_batch, oc, knl_n_total, tmp, knl_data, gemm_output);
|
||||
float * gemm_output = (float *) ((char *) tmp + patches_per_batch * knl_n_total * sizeof(float));
|
||||
ggml_call_mul_mat(kernel_type, GGML_TYPE_F32, params, patch_n_in_batch, oc, knl_n_total, tmp, knl_data, gemm_output);
|
||||
|
||||
ggml_barrier(params->threadpool);
|
||||
|
||||
@@ -7588,7 +7573,7 @@ static void ggml_compute_forward_conv_transpose_2d_impl(
|
||||
const int ith = params->ith;
|
||||
const int nth = params->nth;
|
||||
|
||||
const int nk = ne00*ne01*ne02*ne03;
|
||||
const int nsrc = ne10*ne11*ne12*ne13;
|
||||
|
||||
GGML_ASSERT(nb00 == ggml_type_size(src0->type));
|
||||
GGML_ASSERT(nb10 == sizeof(float));
|
||||
@@ -7596,9 +7581,26 @@ static void ggml_compute_forward_conv_transpose_2d_impl(
|
||||
if (ith == 0) {
|
||||
memset(params->wdata, 0, params->wsize);
|
||||
|
||||
// permute source data (src1) from (Sw x Sh x Cin) to (Cin x Sw x Sh), for all batches
|
||||
{
|
||||
float * const wdata = (float *) params->wdata + 0;
|
||||
for (int i13 = 0; i13 < ne13; i13++) {
|
||||
float * const wdata_b = wdata + i13*ne10*ne11*ne12;
|
||||
for (int i12 = 0; i12 < ne12; i12++) {
|
||||
for (int i11 = 0; i11 < ne11; i11++) {
|
||||
const float * const src = (float *)((char *) src1->data + i13*nb13 + i12*nb12 + i11*nb11);
|
||||
float * dst_data = wdata_b + i11*ne10*ne12;
|
||||
for (int i10 = 0; i10 < ne10; i10++) {
|
||||
dst_data[i10*ne12 + i12] = src[i10];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// permute kernel data (src0) from (Kw x Kh x Cout x Cin) to (Cin x Kw x Kh x Cout)
|
||||
{
|
||||
kernel_t * const wdata = (kernel_t *) params->wdata + 0;
|
||||
kernel_t * const wdata = (kernel_t *)((char *) params->wdata + nsrc*sizeof(float));
|
||||
|
||||
for (int64_t i03 = 0; i03 < ne03; i03++) {
|
||||
for (int64_t i02 = 0; i02 < ne02; i02++) {
|
||||
@@ -7613,27 +7615,6 @@ static void ggml_compute_forward_conv_transpose_2d_impl(
|
||||
}
|
||||
}
|
||||
|
||||
// permute source data (src1) from (Sw x Sh x Cin) to (Cin x Sw x Sh), for all batches
|
||||
{
|
||||
kernel_t * const wdata = (kernel_t *) params->wdata + nk;
|
||||
for (int i13 = 0; i13 < ne13; i13++) {
|
||||
kernel_t * const wdata_b = wdata + i13*ne10*ne11*ne12;
|
||||
for (int i12 = 0; i12 < ne12; i12++) {
|
||||
for (int i11 = 0; i11 < ne11; i11++) {
|
||||
const float * const src = (float *)((char *) src1->data + i13*nb13 + i12*nb12 + i11*nb11);
|
||||
kernel_t * dst_data = wdata_b + i11*ne10*ne12;
|
||||
for (int i10 = 0; i10 < ne10; i10++) {
|
||||
if constexpr (std::is_same_v<kernel_t, ggml_fp16_t>) {
|
||||
dst_data[i10*ne12 + i12] = GGML_CPU_FP32_TO_FP16(src[i10]);
|
||||
} else {
|
||||
dst_data[i10*ne12 + i12] = src[i10];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memset(dst->data, 0, ggml_nbytes(dst));
|
||||
}
|
||||
ggml_barrier(params->threadpool);
|
||||
@@ -7650,14 +7631,14 @@ static void ggml_compute_forward_conv_transpose_2d_impl(
|
||||
const int ip0 = dp*ith;
|
||||
const int ip1 = MIN(ip0 + dp, np);
|
||||
|
||||
kernel_t * const wdata = (kernel_t *) params->wdata + 0;
|
||||
kernel_t * const wdata_src = wdata + nk;
|
||||
float * const wdata_src = (float *) params->wdata + 0;
|
||||
kernel_t * const wdata_kernel = (kernel_t *)((char *) params->wdata + nsrc*sizeof(float));
|
||||
|
||||
for (int i2 = ip0; i2 < ip1; i2++) { // Cout
|
||||
kernel_t * wdata_kernel = wdata + i2*ne01*ne00*ne03;
|
||||
kernel_t * wdata_kernel_c = wdata_kernel + i2*ne01*ne00*ne03;
|
||||
for (int i3 = 0; i3 < ne3; i3++) { // batch
|
||||
float * dst_data = (float *)((char *) dst->data + i3*nb3 + i2*nb2);
|
||||
kernel_t * wdata_src_b = wdata_src + i3*ne10*ne11*ne12;
|
||||
float * wdata_src_b = wdata_src + i3*ne10*ne11*ne12;
|
||||
for (int i11 = 0; i11 < ne11; i11++) {
|
||||
for (int i10 = 0; i10 < ne10; i10++) {
|
||||
const int i1n = i11*ne10*ne12 + i10*ne12;
|
||||
@@ -7665,13 +7646,13 @@ static void ggml_compute_forward_conv_transpose_2d_impl(
|
||||
for (int i00 = 0; i00 < ne00; i00++) {
|
||||
float v = 0;
|
||||
if constexpr (std::is_same_v<kernel_t, ggml_fp16_t>) {
|
||||
ggml_vec_dot_f16(ne03, &v, 0,
|
||||
wdata_src_b + i1n, 0,
|
||||
wdata_kernel + i01*ne00*ne03 + i00*ne03, 0, 1);
|
||||
ggml_vec_dot_f16_f32(ne03, &v, 0,
|
||||
wdata_kernel_c + i01*ne00*ne03 + i00*ne03, 0,
|
||||
wdata_src_b + i1n, 0, 1);
|
||||
} else {
|
||||
ggml_vec_dot_f32(ne03, &v, 0,
|
||||
wdata_src_b + i1n, 0,
|
||||
wdata_kernel + i01*ne00*ne03 + i00*ne03, 0, 1);
|
||||
wdata_kernel_c + i01*ne00*ne03 + i00*ne03, 0,
|
||||
wdata_src_b + i1n, 0, 1);
|
||||
}
|
||||
dst_data[(i11*stride + i01)*ne0 + i10*stride + i00] += v;
|
||||
}
|
||||
@@ -8844,6 +8825,7 @@ static void ggml_compute_forward_flash_attn_ext_f16_one_chunk(
|
||||
const ggml_tensor * v = dst->src[2];
|
||||
const ggml_tensor * mask = dst->src[3];
|
||||
const ggml_tensor * sinks = dst->src[4];
|
||||
const ggml_tensor * kv_rows = dst->src[5];
|
||||
|
||||
GGML_TENSOR_LOCALS(int64_t, neq, q, ne)
|
||||
GGML_TENSOR_LOCALS(size_t, nbq, q, nb)
|
||||
@@ -8951,6 +8933,8 @@ static void ggml_compute_forward_flash_attn_ext_f16_one_chunk(
|
||||
const float * pq = (const float *) ((char *) q->data + (iq1*nbq1 + iq2*nbq2 + iq3*nbq3));
|
||||
q_to_vec_dot(pq, Q_q, DK);
|
||||
|
||||
const int32_t * rows = kv_rows ? (const int32_t *) ((const char *) kv_rows->data + iq3*kv_rows->nb[1]) : nullptr;
|
||||
|
||||
// online softmax / attention
|
||||
// loop over n_kv and n_head_kv
|
||||
// ref: https://arxiv.org/pdf/2112.05682.pdf
|
||||
@@ -8961,9 +8945,14 @@ static void ggml_compute_forward_flash_attn_ext_f16_one_chunk(
|
||||
continue;
|
||||
}
|
||||
|
||||
const int64_t ik1 = rows ? rows[ic] : ic;
|
||||
if (ik1 < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float s; // KQ value
|
||||
|
||||
const char * k_data = (const char *) k->data + ( ic*nbk1 + ik2*nbk2 + ik3*nbk3);
|
||||
const char * k_data = (const char *) k->data + (ik1*nbk1 + ik2*nbk2 + ik3*nbk3);
|
||||
kq_vec_dot(DK, &s, 0, k_data, 0, Q_q, 0, 1);
|
||||
|
||||
s = s*scale; // scale KQ value
|
||||
@@ -8979,7 +8968,7 @@ static void ggml_compute_forward_flash_attn_ext_f16_one_chunk(
|
||||
float ms = 1.0f; // upon new higher max val, scale VKQ and KQ sum with this value
|
||||
float vs = 1.0f; // post-softmax KQ value, expf(s - M)
|
||||
|
||||
const char * v_data = ((const char *) v->data + (ic*nbv1 + iv2*nbv2 + iv3*nbv3));
|
||||
const char * v_data = ((const char *) v->data + (ik1*nbv1 + iv2*nbv2 + iv3*nbv3));
|
||||
|
||||
if (v->type == GGML_TYPE_F16) {
|
||||
if (s > M) {
|
||||
@@ -9146,6 +9135,10 @@ static void ggml_compute_forward_flash_attn_ext_tiled(
|
||||
static constexpr int Q_TILE_SZ = ggml_fa_tile_config::Q;
|
||||
static constexpr int KV_TILE_SZ = ggml_fa_tile_config::KV;
|
||||
|
||||
// with kv_rows the loop runs over the mask columns and reads K/V rows through kv_rows
|
||||
const ggml_tensor * kv_rows = dst->src[5];
|
||||
const int64_t n_kv_cols = kv_rows ? kv_rows->ne[0] : nek1;
|
||||
|
||||
int ir = ir0;
|
||||
while (ir < ir1) {
|
||||
// q indices for the start of this tile
|
||||
@@ -9153,6 +9146,10 @@ static void ggml_compute_forward_flash_attn_ext_tiled(
|
||||
const int iq2 = (ir - iq3*neq2*neq1)/neq1;
|
||||
const int iq1 = (ir - iq3*neq2*neq1 - iq2*neq1);
|
||||
|
||||
// padding rows are masked, read row 0 for them
|
||||
const int32_t * rows = kv_rows ? (const int32_t *) ((const char *) kv_rows->data + iq3*kv_rows->nb[1]) : nullptr;
|
||||
auto kv_row = [rows](int64_t i) -> int64_t { return rows ? std::max<int32_t>(rows[i], 0) : i; };
|
||||
|
||||
// Number of valid rows in this tile:
|
||||
// - limited by tile size (Q_TILE_SZ)
|
||||
// - limited by chunk boundary (ir1 - ir)
|
||||
@@ -9212,8 +9209,8 @@ static void ggml_compute_forward_flash_attn_ext_tiled(
|
||||
memset(K_f32, 0, DK * KV_TILE_SZ * sizeof(float));
|
||||
memset(V32, 0, KV_TILE_SZ * DV * sizeof(float));
|
||||
|
||||
for (int64_t ic = 0; ic < nek1; ic += KV_TILE_SZ) {
|
||||
const int kv_tile = (int)std::min((int64_t)KV_TILE_SZ, nek1 - ic);
|
||||
for (int64_t ic = 0; ic < n_kv_cols; ic += KV_TILE_SZ) {
|
||||
const int kv_tile = (int)std::min((int64_t)KV_TILE_SZ, n_kv_cols - ic);
|
||||
|
||||
// skip the tile entirely if all the masks are -inf
|
||||
if (mask) {
|
||||
@@ -9240,7 +9237,7 @@ static void ggml_compute_forward_flash_attn_ext_tiled(
|
||||
// Pack K tile transposed: K_f32[dk][kv] so KV_TILE is contiguous (SIMD dim)
|
||||
// Zero-pad the last tile so the GEMM always operates on KV_TILE_SZ columns
|
||||
for (int tk = 0; tk < kv_tile; tk++) {
|
||||
const char * k_data = (const char *)k->data + (ic + tk)*nbk1 + ik2*nbk2 + ik3*nbk3;
|
||||
const char * k_data = (const char *)k->data + kv_row(ic + tk)*nbk1 + ik2*nbk2 + ik3*nbk3;
|
||||
if (kv_type == GGML_TYPE_F16) {
|
||||
const ggml_fp16_t * k_f16 = (const ggml_fp16_t *)k_data;
|
||||
for (int64_t dk = 0; dk < DK; dk++) {
|
||||
@@ -9305,7 +9302,7 @@ static void ggml_compute_forward_flash_attn_ext_tiled(
|
||||
// V accumulation: VKQ32 += softmax(KQ) * V
|
||||
// Pack V tile to contiguous F32, zero-padded
|
||||
for (int tk = 0; tk < kv_tile; tk++) {
|
||||
const char * v_data = (const char *)v->data + (ic + tk)*nbv1 + iv2*nbv2 + iv3*nbv3;
|
||||
const char * v_data = (const char *)v->data + kv_row(ic + tk)*nbv1 + iv2*nbv2 + iv3*nbv3;
|
||||
if (kv_type == GGML_TYPE_F16) {
|
||||
ggml_cpu_fp16_to_fp32((const ggml_fp16_t *)v_data, V32 + tk * DV, DV);
|
||||
} else {
|
||||
@@ -9477,8 +9474,12 @@ static void ggml_compute_forward_flash_attn_ext_f16(
|
||||
// When use_ref is set, force the vec-only reference implementation (no tiling, no KV-chunking)
|
||||
const bool use_ref = params->use_ref;
|
||||
|
||||
// with kv_rows the loops run over the mask columns, the split KV path does not support it
|
||||
const ggml_tensor * kv_rows = dst->src[5];
|
||||
const int64_t n_kv_cols = kv_rows ? kv_rows->ne[0] : nek1;
|
||||
|
||||
const bool kv_is_f32_or_f16 = (k->type == GGML_TYPE_F32 || k->type == GGML_TYPE_F16);
|
||||
const bool use_split_kv_path = !use_ref && (neq1 == 1 && neq3 == 1) && kv_is_f32_or_f16 && (k->type == v->type) && q->type == GGML_TYPE_F32 && nek1 >= 512;
|
||||
const bool use_split_kv_path = !use_ref && !kv_rows && (neq1 == 1 && neq3 == 1) && kv_is_f32_or_f16 && (k->type == v->type) && q->type == GGML_TYPE_F32 && nek1 >= 512;
|
||||
|
||||
if (use_split_kv_path) {
|
||||
const int64_t chunk_size = (nek1 + nth - 1) / nth;
|
||||
@@ -9557,7 +9558,7 @@ static void ggml_compute_forward_flash_attn_ext_f16(
|
||||
if (use_tiled) {
|
||||
ggml_compute_forward_flash_attn_ext_tiled(params, dst, ir0, ir1);
|
||||
} else {
|
||||
ggml_compute_forward_flash_attn_ext_f16_one_chunk(params, dst, ir0, ir1, 0, nek1, nullptr, 0);
|
||||
ggml_compute_forward_flash_attn_ext_f16_one_chunk(params, dst, ir0, ir1, 0, n_kv_cols, nullptr, 0);
|
||||
}
|
||||
|
||||
current_chunk = ggml_threadpool_chunk_add(params->threadpool, 1);
|
||||
@@ -9571,6 +9572,7 @@ void ggml_compute_forward_flash_attn_ext(
|
||||
switch (dst->op_params[3]) {
|
||||
case GGML_PREC_DEFAULT:
|
||||
case GGML_PREC_F32:
|
||||
case GGML_PREC_BF16:
|
||||
{
|
||||
// uses F32 accumulators
|
||||
ggml_compute_forward_flash_attn_ext_f16(params, dst);
|
||||
@@ -10094,7 +10096,7 @@ static void ggml_compute_forward_ssm_scan_f32(
|
||||
}
|
||||
|
||||
sumf = GGML_F32xt_REDUCE_ONE(sum);
|
||||
#elif defined(__riscv_v_intrinsic)
|
||||
#elif defined(__riscv_v)
|
||||
// todo: RVV implementation
|
||||
const int np = 0;
|
||||
#else
|
||||
@@ -11758,7 +11760,7 @@ static void ggml_compute_forward_rwkv_wkv7_f32(
|
||||
int64_t h_stride_2d = head_size * head_size;
|
||||
|
||||
#if defined(GGML_SIMD)
|
||||
#if defined(__ARM_FEATURE_SVE) || defined(__riscv_v_intrinsic)
|
||||
#if defined(__ARM_FEATURE_SVE) || defined(__riscv_v)
|
||||
// scalar Route to scalar implementation //TODO: Write SVE code and RVV code
|
||||
for (int64_t t = 0; t < T; t++) {
|
||||
int64_t t_offset = t * t_stride;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include "simd-mappings.h"
|
||||
|
||||
// TODO: add support for sizeless vector types
|
||||
#if defined(GGML_SIMD) && !defined(__ARM_FEATURE_SVE) && !defined(__riscv_v_intrinsic)
|
||||
#if defined(GGML_SIMD) && !defined(__ARM_FEATURE_SVE) && !defined(__riscv_v)
|
||||
|
||||
// TODO: untested on avx512
|
||||
// These are in units of GGML_F32_EPR
|
||||
@@ -149,7 +149,7 @@ static void simd_gemm(
|
||||
C += N;
|
||||
}
|
||||
}
|
||||
#elif defined(GGML_SIMD) && defined(__riscv_v_intrinsic)
|
||||
#elif defined(GGML_SIMD) && defined(__riscv_v)
|
||||
// RM accumulators + 1 B vector = RM + 1 <= 8 => RM <= 7
|
||||
// Microkernel: C[RM x vl] += A[RM x K] * B[K x N]
|
||||
template <int RM>
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
#include <arm_neon.h>
|
||||
#endif
|
||||
|
||||
#if defined(__riscv_v_intrinsic)
|
||||
// __riscv_v_intrinsic reports compiler API support and can be defined without
|
||||
// enabling V; use the ISA feature macro to select RVV code.
|
||||
#if defined(__riscv_v)
|
||||
#include <riscv_vector.h>
|
||||
#endif
|
||||
|
||||
@@ -1306,7 +1308,7 @@ static inline void __lzs_f16cx4_store(ggml_fp16_t * x, float32x4_t v_y) {
|
||||
#define GGML_BF16_FMA_HI(acc, x, y) \
|
||||
(acc) = GGML_F32x4_FMA((acc), GGML_BF16_TO_F32_HI(x), GGML_BF16_TO_F32_HI(y))
|
||||
|
||||
#elif defined(__riscv_v_intrinsic)
|
||||
#elif defined(__riscv_v)
|
||||
|
||||
// compatible with vlen >= 128
|
||||
|
||||
|
||||
@@ -198,7 +198,7 @@ template <typename BLOC_TYPE, int64_t INTER_SIZE, int64_t NB_COLS> class tensor_
|
||||
case GGML_TYPE_Q5_0:
|
||||
case GGML_TYPE_Q5_1:
|
||||
case GGML_TYPE_Q5_K:
|
||||
//case GGML_TYPE_MXFP4:
|
||||
case GGML_TYPE_MXFP4:
|
||||
forward_mul_mat(params, op);
|
||||
return true;
|
||||
default:
|
||||
@@ -1046,6 +1046,10 @@ class tensor_traits_common : public tensor_traits_base {
|
||||
return true;
|
||||
}
|
||||
case GGML_OP_FLASH_ATTN_EXT:
|
||||
// K/V row lists are handled by the generic CPU path
|
||||
if (op->src[5] != nullptr) {
|
||||
return false;
|
||||
}
|
||||
forward_flash_attn_ext_f16(params, op);
|
||||
return true;
|
||||
case GGML_OP_CONT:
|
||||
@@ -1176,7 +1180,7 @@ class tensor_traits_common : public tensor_traits_base {
|
||||
const int64_t DK = nek0;
|
||||
const int64_t DV = nev0;
|
||||
|
||||
const bool supported_prec = (dst->op_params[3] == GGML_PREC_F32 || dst->op_params[3] == GGML_PREC_DEFAULT);
|
||||
const bool supported_prec = (dst->op_params[3] == GGML_PREC_F32 || dst->op_params[3] == GGML_PREC_BF16 || dst->op_params[3] == GGML_PREC_DEFAULT);
|
||||
const bool supported_types = (q->type == GGML_TYPE_F32 && k->type == GGML_TYPE_F16 && v->type == GGML_TYPE_F16);
|
||||
const bool supported_shape = (DK > 0 && DK <= 128 && DV > 0 && DV <= 128);
|
||||
const bool supported_vlen = (__riscv_vlenb() == 128);
|
||||
@@ -1371,10 +1375,10 @@ static const ggml::cpu::tensor_traits * ggml_riscv64_spacemit_get_optimal_repack
|
||||
case GGML_TYPE_MXFP4:
|
||||
{
|
||||
#if defined(RISCV64_SPACEMIT_IME2)
|
||||
// TODO
|
||||
// if (cur->ne[1] % 32 == 0 && (ggml::cpu::riscv64_spacemit::global_spine_env_info.use_ime2)) {
|
||||
// return &ggml::cpu::riscv64_spacemit::mxfp4_32x32_q8_0;
|
||||
// }
|
||||
if (ggml_n_dims(cur) == 2 && cur->ne[0] % 32 == 0 && cur->ne[1] % 32 == 0 &&
|
||||
(ggml::cpu::riscv64_spacemit::global_spine_env_info.use_ime2)) {
|
||||
return &ggml::cpu::riscv64_spacemit::mxfp4_32x32_q8_0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
@@ -1609,6 +1613,9 @@ class extra_buffer_type : ggml::cpu::extra_buffer_type {
|
||||
if (op->src[1]->buffer && !ggml_backend_buft_is_host(op->src[1]->buffer->buft)) {
|
||||
return false;
|
||||
}
|
||||
if (op->src[0]->type == GGML_TYPE_MXFP4 && !ggml_is_contiguous(op->src[1])) {
|
||||
return false;
|
||||
}
|
||||
if (op->src[1]->type == GGML_TYPE_F32) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3754,7 +3754,7 @@ void gemm_kernel_i8mxfp4_m1(size_t blk_len,
|
||||
using blk_type = nrow_block_mxfp4<NB_COLS>;
|
||||
|
||||
GGML_ASSERT(blk_len == K_TILE);
|
||||
GGML_ASSERT(count_m == 1);
|
||||
GGML_ASSERT(count_m >= 1);
|
||||
GGML_UNUSED(quant_b_zp);
|
||||
|
||||
const size_t a_blk_stride = q8_blk_size(blk_len, true);
|
||||
@@ -3923,7 +3923,7 @@ void gemm_kernel_i8mxfp4_m1(size_t blk_len,
|
||||
:
|
||||
: [BCK] "r"(cnt), [NBLKS] "r"(nblks), [pA] "r"(quant_a_ptr), [pB] "r"(QuantBDataPtr), [pC] "r"(CPtr)
|
||||
: "cc", "memory", "t0", "t1", "t2", "t3", "t4", "f0", "s2", "s3", "s4", "s5", "s6", "s7", "v0", "v1",
|
||||
"v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v16", "v17", "v18", "v19",
|
||||
"v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19",
|
||||
"v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31");
|
||||
}
|
||||
}
|
||||
@@ -3943,7 +3943,7 @@ void gemm_kernel_i8mxfp4_m4(size_t blk_len,
|
||||
using blk_type = nrow_block_mxfp4<NB_COLS>;
|
||||
|
||||
GGML_ASSERT(blk_len == K_TILE);
|
||||
GGML_ASSERT(count_m == 4);
|
||||
GGML_ASSERT(count_m >= 4);
|
||||
GGML_UNUSED(quant_b_zp);
|
||||
|
||||
const size_t a_blk_stride = q8_blk_size(blk_len, true);
|
||||
@@ -5687,20 +5687,10 @@ size_t gemm_kernel_i8mxfp4(size_t blk_len,
|
||||
size_t k_blks,
|
||||
size_t ldc) {
|
||||
if (count_m >= 4) {
|
||||
#if 1
|
||||
gemm_kernel_i8mxfp4_mrow_ref<4, 32>(blk_len, quant_a_ptr, quant_b_data, quant_b_zp, c_ptr, count_m, count_n,
|
||||
k_blks, ldc);
|
||||
#else
|
||||
gemm_kernel_i8mxfp4_m4(blk_len, quant_a_ptr, quant_b_data, quant_b_zp, c_ptr, count_m, count_n, k_blks, ldc);
|
||||
#endif
|
||||
return 4;
|
||||
} else {
|
||||
#if 1
|
||||
gemm_kernel_i8mxfp4_mrow_ref<1, 32>(blk_len, quant_a_ptr, quant_b_data, quant_b_zp, c_ptr, count_m, count_n,
|
||||
k_blks, ldc);
|
||||
#else
|
||||
gemm_kernel_i8mxfp4_m1(blk_len, quant_a_ptr, quant_b_data, quant_b_zp, c_ptr, count_m, count_n, k_blks, ldc);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ void ggml_vec_dot_f32(int n, float * GGML_RESTRICT s, size_t bs, const float * G
|
||||
}
|
||||
// reduce sum1,sum2 to sum1
|
||||
GGML_F32_VEC_REDUCE(sumf, sum1, sum2, sum3, sum4, sum5, sum6, sum7, sum8);
|
||||
#elif defined(__riscv_v_intrinsic)
|
||||
#elif defined(__riscv_v)
|
||||
int vl = __riscv_vsetvlmax_e32m8();
|
||||
vfloat32m1_t vs = __riscv_vfmv_v_f_f32m1(0.0f, 1);
|
||||
vfloat32m8_t vsum;
|
||||
@@ -195,7 +195,7 @@ void ggml_vec_dot_bf16(int n, float * GGML_RESTRICT s, size_t bs, ggml_bf16_t *
|
||||
sumf += (ggml_float)_mm_cvtss_f32(g);
|
||||
|
||||
#undef LOAD
|
||||
#elif defined(__riscv_v_intrinsic) && defined(__riscv_zvfbfwma)
|
||||
#elif defined(__riscv_v) && defined(__riscv_zvfbfwma)
|
||||
size_t vl = __riscv_vsetvlmax_e32m4();
|
||||
|
||||
// initialize accumulators to all zeroes
|
||||
@@ -318,7 +318,7 @@ void ggml_vec_dot_f16(int n, float * GGML_RESTRICT s, size_t bs, ggml_fp16_t * G
|
||||
sum1_hi = svadd_f32_m(DEFAULT_PG32, sum1_hi, sum3_hi);
|
||||
|
||||
sumf = ggml_sve_sum_f32x2(sum1_lo, sum1_hi);
|
||||
#elif defined(__riscv_v_intrinsic)
|
||||
#elif defined(__riscv_v)
|
||||
#if defined(__riscv_zvfh)
|
||||
int vl = __riscv_vsetvlmax_e32m2();
|
||||
vfloat32m1_t vs = __riscv_vfmv_v_f_f32m1(0.0f, 1);
|
||||
@@ -377,6 +377,85 @@ void ggml_vec_dot_f16(int n, float * GGML_RESTRICT s, size_t bs, ggml_fp16_t * G
|
||||
*s = sumf;
|
||||
}
|
||||
|
||||
void ggml_vec_dot_f16_f32(int n, float * GGML_RESTRICT s, size_t bs, const ggml_fp16_t * GGML_RESTRICT x, size_t bx, const float * GGML_RESTRICT y, size_t by, int nrc) {
|
||||
assert(nrc == 1);
|
||||
GGML_UNUSED(nrc);
|
||||
GGML_UNUSED(bx);
|
||||
GGML_UNUSED(by);
|
||||
GGML_UNUSED(bs);
|
||||
|
||||
ggml_float sumf = 0.0;
|
||||
int i = 0;
|
||||
|
||||
// on AVX512 and AVX with F16C, x is widened to F32 in-register and accumulated in F32 over 4 independent sums
|
||||
#if defined(__AVX512F__)
|
||||
__m512 acc0 = _mm512_setzero_ps();
|
||||
__m512 acc1 = _mm512_setzero_ps();
|
||||
__m512 acc2 = _mm512_setzero_ps();
|
||||
__m512 acc3 = _mm512_setzero_ps();
|
||||
for (; i + 64 <= n; i += 64) {
|
||||
acc0 = _mm512_fmadd_ps(_mm512_cvtph_ps(_mm256_loadu_si256((const __m256i *)(x + i + 0))), _mm512_loadu_ps(y + i + 0), acc0);
|
||||
acc1 = _mm512_fmadd_ps(_mm512_cvtph_ps(_mm256_loadu_si256((const __m256i *)(x + i + 16))), _mm512_loadu_ps(y + i + 16), acc1);
|
||||
acc2 = _mm512_fmadd_ps(_mm512_cvtph_ps(_mm256_loadu_si256((const __m256i *)(x + i + 32))), _mm512_loadu_ps(y + i + 32), acc2);
|
||||
acc3 = _mm512_fmadd_ps(_mm512_cvtph_ps(_mm256_loadu_si256((const __m256i *)(x + i + 48))), _mm512_loadu_ps(y + i + 48), acc3);
|
||||
}
|
||||
for (; i + 16 <= n; i += 16) {
|
||||
acc0 = _mm512_fmadd_ps(_mm512_cvtph_ps(_mm256_loadu_si256((const __m256i *)(x + i))), _mm512_loadu_ps(y + i), acc0);
|
||||
}
|
||||
sumf = _mm512_reduce_add_ps(_mm512_add_ps(_mm512_add_ps(acc0, acc1), _mm512_add_ps(acc2, acc3)));
|
||||
#elif defined(__AVX__) && defined(__F16C__)
|
||||
__m256 acc0 = _mm256_setzero_ps();
|
||||
__m256 acc1 = _mm256_setzero_ps();
|
||||
__m256 acc2 = _mm256_setzero_ps();
|
||||
__m256 acc3 = _mm256_setzero_ps();
|
||||
for (; i + 32 <= n; i += 32) {
|
||||
acc0 = GGML_F32x8_FMA(acc0, _mm256_cvtph_ps(_mm_loadu_si128((const __m128i *)(x + i + 0))), _mm256_loadu_ps(y + i + 0));
|
||||
acc1 = GGML_F32x8_FMA(acc1, _mm256_cvtph_ps(_mm_loadu_si128((const __m128i *)(x + i + 8))), _mm256_loadu_ps(y + i + 8));
|
||||
acc2 = GGML_F32x8_FMA(acc2, _mm256_cvtph_ps(_mm_loadu_si128((const __m128i *)(x + i + 16))), _mm256_loadu_ps(y + i + 16));
|
||||
acc3 = GGML_F32x8_FMA(acc3, _mm256_cvtph_ps(_mm_loadu_si128((const __m128i *)(x + i + 24))), _mm256_loadu_ps(y + i + 24));
|
||||
}
|
||||
for (; i + 8 <= n; i += 8) {
|
||||
acc0 = GGML_F32x8_FMA(acc0, _mm256_cvtph_ps(_mm_loadu_si128((const __m128i *)(x + i))), _mm256_loadu_ps(y + i));
|
||||
}
|
||||
const __m256 acc = _mm256_add_ps(_mm256_add_ps(acc0, acc1), _mm256_add_ps(acc2, acc3));
|
||||
__m128 r = _mm_add_ps(_mm256_castps256_ps128(acc), _mm256_extractf128_ps(acc, 1));
|
||||
r = _mm_add_ps(r, _mm_movehl_ps(r, r));
|
||||
r = _mm_add_ss(r, _mm_movehdup_ps(r));
|
||||
sumf = _mm_cvtss_f32(r);
|
||||
#elif defined(GGML_SIMD)
|
||||
// convert chunks of x to F32 and reuse the F32 SIMD dot
|
||||
// TODO: convert F16 to F32 in-register and fuse the dot (needs a new SIMD macro); also avoid the per-chunk call overhead for tiny k
|
||||
float tx[64];
|
||||
for (; i + 64 <= n; i += 64) {
|
||||
const ggml_fp16_t * GGML_RESTRICT xr = x + i;
|
||||
float * GGML_RESTRICT tr = tx;
|
||||
for (int j = 0; j < 64; ++j) {
|
||||
tr[j] = GGML_CPU_FP16_TO_FP32(xr[j]);
|
||||
}
|
||||
float v;
|
||||
ggml_vec_dot_f32(64, &v, 0, tx, 0, y + i, 0, 1);
|
||||
sumf += v;
|
||||
}
|
||||
if (i < n) {
|
||||
const int nr = n - i;
|
||||
const ggml_fp16_t * GGML_RESTRICT xr = x + i;
|
||||
float * GGML_RESTRICT tr = tx;
|
||||
for (int j = 0; j < nr; ++j) {
|
||||
tr[j] = GGML_CPU_FP16_TO_FP32(xr[j]);
|
||||
}
|
||||
float v;
|
||||
ggml_vec_dot_f32(nr, &v, 0, tx, 0, y + i, 0, 1);
|
||||
sumf += v;
|
||||
i = n;
|
||||
}
|
||||
#endif
|
||||
for (; i < n; ++i) {
|
||||
sumf += (ggml_float)(GGML_CPU_FP16_TO_FP32(x[i])*y[i]);
|
||||
}
|
||||
|
||||
*s = sumf;
|
||||
}
|
||||
|
||||
void ggml_vec_silu_f32(const int n, float * y, const float * x) {
|
||||
int i = 0;
|
||||
#if defined(__AVX512F__) && defined(__AVX512DQ__)
|
||||
@@ -405,7 +484,7 @@ void ggml_vec_silu_f32(const int n, float * y, const float * x) {
|
||||
for (; i + 3 < n; i += 4) {
|
||||
vec_xst(ggml_v_silu(vec_xl(0, x + i)), 0, y + i);
|
||||
}
|
||||
#elif defined(__riscv_v_intrinsic)
|
||||
#elif defined(__riscv_v)
|
||||
for (int vl; i < n; i += vl) {
|
||||
vl = __riscv_vsetvl_e32m2(n - i);
|
||||
vfloat32m2_t vx = __riscv_vle32_v_f32m2(&x[i], vl);
|
||||
@@ -446,7 +525,7 @@ void ggml_vec_swiglu_f32(const int n, float * y, const float * x, const float *
|
||||
for (; i + 3 < n; i += 4) {
|
||||
vec_xst(vec_mul(ggml_v_silu(vec_xl(0, x + i)), vec_xl(0, g + i)), 0, y + i);
|
||||
}
|
||||
#elif defined(__riscv_v_intrinsic)
|
||||
#elif defined(__riscv_v)
|
||||
for (int vl; i < n; i += vl) {
|
||||
vl = __riscv_vsetvl_e32m2(n - i);
|
||||
vfloat32m2_t vx = __riscv_vle32_v_f32m2(&x[i], vl);
|
||||
@@ -602,7 +681,7 @@ ggml_float ggml_vec_cvar_f32(const int n, float * y, const float * x, const floa
|
||||
val = vec_mul(val, val);
|
||||
sum += (ggml_float)vec_hsum_f32x4(val);
|
||||
}
|
||||
#elif defined(__riscv_v_intrinsic)
|
||||
#elif defined(__riscv_v)
|
||||
vfloat64m1_t vsum = __riscv_vfmv_v_f_f64m1(0, 1);
|
||||
for (int vl; i < n; i += vl) {
|
||||
vl = __riscv_vsetvl_e32m2(n - i);
|
||||
@@ -681,7 +760,7 @@ ggml_float ggml_vec_soft_max_f32(const int n, float * y, const float * x, float
|
||||
vec_xst(v_val, 0, y + i);
|
||||
sum += (ggml_float)vec_hsum_f32x4(v_val);
|
||||
}
|
||||
#elif defined(__riscv_v_intrinsic)
|
||||
#elif defined(__riscv_v)
|
||||
vfloat64m1_t vsum = __riscv_vfmv_v_f_f64m1(0, 1);
|
||||
for (int avl; i < n; i += avl) {
|
||||
avl = __riscv_vsetvl_e32m2(n - i);
|
||||
|
||||
+10
-9
@@ -70,6 +70,7 @@ extern ggml_fp16_t ggml_table_gelu_quick_f16[1 << 16];
|
||||
void ggml_vec_dot_f32(int n, float * GGML_RESTRICT s, size_t bs, const float * GGML_RESTRICT x, size_t bx, const float * GGML_RESTRICT y, size_t by, int nrc);
|
||||
void ggml_vec_dot_bf16(int n, float * GGML_RESTRICT s, size_t bs, ggml_bf16_t * GGML_RESTRICT x, size_t bx, ggml_bf16_t * GGML_RESTRICT y, size_t by, int nrc);
|
||||
void ggml_vec_dot_f16(int n, float * GGML_RESTRICT s, size_t bs, ggml_fp16_t * GGML_RESTRICT x, size_t bx, ggml_fp16_t * GGML_RESTRICT y, size_t by, int nrc);
|
||||
void ggml_vec_dot_f16_f32(int n, float * GGML_RESTRICT s, size_t bs, const ggml_fp16_t * GGML_RESTRICT x, size_t bx, const float * GGML_RESTRICT y, size_t by, int nrc);
|
||||
|
||||
void ggml_vec_silu_f32(const int n, float * y, const float * x);
|
||||
ggml_float ggml_vec_cvar_f32(const int n, float * y, const float * x, const float mean); //it will also center y ( y = y - mean )
|
||||
@@ -206,7 +207,7 @@ inline static void ggml_vec_dot_f16_unroll(const int n, const int xs, float * GG
|
||||
sumf[0] = ggml_sve_sum_f32x2(sum_0_lo, sum_0_hi);
|
||||
sumf[1] = ggml_sve_sum_f32x2(sum_1_lo, sum_1_hi);
|
||||
np = n;
|
||||
#elif defined(__riscv_v_intrinsic)
|
||||
#elif defined(__riscv_v)
|
||||
#if defined(__riscv_zvfh)
|
||||
size_t vl = __riscv_vsetvlmax_e32m4();
|
||||
|
||||
@@ -396,7 +397,7 @@ inline static void ggml_vec_mad_f32(const int n, float * GGML_RESTRICT y, const
|
||||
|
||||
svst1_f32(pg, y + np2, ay1);
|
||||
}
|
||||
#elif defined(__riscv_v_intrinsic)
|
||||
#elif defined(__riscv_v)
|
||||
for (int i = 0, avl; i < n; i += avl) {
|
||||
avl = __riscv_vsetvl_e32m8(n - i);
|
||||
vfloat32m8_t ax = __riscv_vle32_v_f32m8(&x[i], avl);
|
||||
@@ -513,7 +514,7 @@ inline static void ggml_vec_mad_f16(const int n, ggml_fp16_t * GGML_RESTRICT y,
|
||||
svst1_f16(pg, (__fp16 *)(y + np2), hy);
|
||||
}
|
||||
np = n;
|
||||
#elif defined(__riscv_v_intrinsic) // implies __riscv_v_intrinsic
|
||||
#elif defined(__riscv_v)
|
||||
#if defined (__riscv_zvfh)
|
||||
const ggml_fp16_t s = GGML_CPU_FP32_TO_FP16(v);
|
||||
const _Float16 scale = *(const _Float16*)(&s);
|
||||
@@ -599,7 +600,7 @@ inline static void ggml_vec_mad_f32_unroll(const int n, const int xs, const int
|
||||
y[i] += x[k][i]*v[k][0];
|
||||
}
|
||||
}
|
||||
#elif defined(__riscv_v_intrinsic)
|
||||
#elif defined(__riscv_v)
|
||||
for (int i = 0, avl; i < n; i += avl) {
|
||||
avl = __riscv_vsetvl_e32m8(n - i);
|
||||
vfloat32m8_t ay = __riscv_vle32_v_f32m8(&y[i], avl);
|
||||
@@ -660,7 +661,7 @@ inline static void ggml_vec_mad1_f32(const int n, float * y, const float * x, co
|
||||
for (int i = 0; i < n; ++i) {
|
||||
y[i] = x[i]*s + b;
|
||||
}
|
||||
#elif defined(__riscv_v_intrinsic)
|
||||
#elif defined(__riscv_v)
|
||||
for (int i = 0, avl; i < n; i += avl) {
|
||||
avl = __riscv_vsetvl_e32m8(n - i);
|
||||
vfloat32m8_t ax = __riscv_vle32_v_f32m8(&x[i], avl);
|
||||
@@ -729,7 +730,7 @@ inline static void ggml_vec_scale_f32(const int n, float * y, const float v) {
|
||||
ay1 = svmul_f32_m(pg, ay1, vx);
|
||||
svst1_f32(pg, y + i, ay1);
|
||||
}
|
||||
#elif defined(__riscv_v_intrinsic)
|
||||
#elif defined(__riscv_v)
|
||||
for (int i = 0, avl; i < n; i += avl) {
|
||||
avl = __riscv_vsetvl_e32m8(n - i);
|
||||
vfloat32m8_t ay = __riscv_vle32_v_f32m8(&y[i], avl);
|
||||
@@ -793,7 +794,7 @@ inline static void ggml_vec_scale_f16(const int n, ggml_fp16_t * y, const float
|
||||
svst1_f16(pg, (__fp16 *)(y + np), out);
|
||||
}
|
||||
np = n;
|
||||
#elif defined(__riscv_v_intrinsic)
|
||||
#elif defined(__riscv_v)
|
||||
#if defined(__riscv_zvfh)
|
||||
const ggml_fp16_t s = GGML_CPU_FP32_TO_FP16(v);
|
||||
const _Float16 scale = *(const _Float16*)(&s);
|
||||
@@ -1411,7 +1412,7 @@ inline static float32x4_t ggml_v_gelu_quick(float32x4_t x) {
|
||||
return vec_div(x, vec_add(one, exp_cx));
|
||||
}
|
||||
|
||||
#elif defined(__riscv_v_intrinsic)
|
||||
#elif defined(__riscv_v)
|
||||
|
||||
// adapted from arm limited optimized routine
|
||||
// the maximum error is 1.45358 plus 0.5 ulps
|
||||
@@ -1469,7 +1470,7 @@ inline static vfloat32m2_t ggml_v_gelu_quick_m2(vfloat32m2_t x, int vl) {
|
||||
return __riscv_vfdiv_vv_f32m2(x, __riscv_vfadd_vf_f32m2(exp_cx, 1.0f, vl), vl);
|
||||
}
|
||||
|
||||
#endif // __ARM_NEON / __AVX2__ / __SSE2__ / __VXE__ / __riscv_v_intrinsic
|
||||
#endif // __ARM_NEON / __AVX2__ / __SSE2__ / __VXE__ / __riscv_v
|
||||
|
||||
inline static void ggml_vec_silu_f16(const int n, ggml_fp16_t * y, const ggml_fp16_t * x) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user