Skip to content

Commit d32b877

Browse files
authored
Merge branch 'main' into vulkan-compatibility
2 parents d5a431e + fba18e2 commit d32b877

231 files changed

Lines changed: 25626 additions & 1202 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.ci/docker/build.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,10 @@ case "${IMAGE_NAME}" in
8989
OS_VERSION=24.04
9090
GCC_VERSION=14
9191
;;
92-
executorch-ubuntu-26.04-gcc15)
92+
executorch-ubuntu-26.04-gcc14)
9393
LINTRUNNER=""
9494
OS_VERSION=26.04
95-
GCC_VERSION=15
95+
GCC_VERSION=14
9696
;;
9797
*)
9898
echo "Invalid image name ${IMAGE_NAME}"

.ci/scripts/export_model_artifact.sh

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ case "$HF_MODEL" in
195195
PREPROCESSOR_FEATURE_SIZE=""
196196
PREPROCESSOR_OUTPUT=""
197197
;;
198-
SocialLocalMobile/gemma-4-31B-it-HQQ-INT4)
198+
unsloth/gemma-4-31B-it-GGUF)
199199
MODEL_NAME="gemma4_31b"
200200
TASK=""
201201
MAX_SEQ_LEN=""
@@ -205,7 +205,7 @@ case "$HF_MODEL" in
205205
;;
206206
*)
207207
echo "Error: Unsupported model '$HF_MODEL'"
208-
echo "Supported models: mistralai/Voxtral-Mini-3B-2507, mistralai/Voxtral-Mini-4B-Realtime-2602, openai/whisper-{small, medium, large, large-v2, large-v3, large-v3-turbo}, google/gemma-3-4b-it, Qwen/Qwen3-0.6B, nvidia/diar_streaming_sortformer_4spk-v2, nvidia/parakeet-tdt, facebook/dinov2-small-imagenet1k-1-layer, SocialLocalMobile/Qwen3.5-35B-A3B-HQQ-INT4, SocialLocalMobile/gemma-4-31B-it-HQQ-INT4"
208+
echo "Supported models: mistralai/Voxtral-Mini-3B-2507, mistralai/Voxtral-Mini-4B-Realtime-2602, openai/whisper-{small, medium, large, large-v2, large-v3, large-v3-turbo}, google/gemma-3-4b-it, Qwen/Qwen3-0.6B, nvidia/diar_streaming_sortformer_4spk-v2, nvidia/parakeet-tdt, facebook/dinov2-small-imagenet1k-1-layer, SocialLocalMobile/Qwen3.5-35B-A3B-HQQ-INT4, unsloth/gemma-4-31B-it-GGUF"
209209
exit 1
210210
;;
211211
esac
@@ -406,8 +406,9 @@ if [ "$MODEL_NAME" = "qwen3_5_moe" ]; then
406406

407407
# Download prequantized model outside OUTPUT_DIR to avoid uploading on failure
408408
LOCAL_MODEL_DIR=$(mktemp -d)
409-
INDUCTOR_CACHE=$(mktemp -d)
410-
trap 'rm -rf "$LOCAL_MODEL_DIR" "$INDUCTOR_CACHE"' EXIT
409+
INDUCTOR_CACHE=$(mktemp -d "${RUNNER_TEMP:-/tmp}/inductor_cache_XXXXXX")
410+
INDUCTOR_TMPDIR=$(mktemp -d "${RUNNER_TEMP:-/tmp}/tmpdir_XXXXXX")
411+
trap 'rm -rf "$LOCAL_MODEL_DIR" "$INDUCTOR_CACHE" "$INDUCTOR_TMPDIR"' EXIT
411412

412413
python -c "from huggingface_hub import snapshot_download; snapshot_download('${HF_MODEL}', local_dir='${LOCAL_MODEL_DIR}')"
413414

@@ -427,6 +428,7 @@ if [ "$MODEL_NAME" = "qwen3_5_moe" ]; then
427428
# Export to .pte/.ptd (short cache dir avoids objcopy symbol length issues)
428429
echo "::group::Export"
429430
EXPORT_LOG=$(mktemp)
431+
TMPDIR="$INDUCTOR_TMPDIR" \
430432
TORCHINDUCTOR_CACHE_DIR="$INDUCTOR_CACHE" \
431433
python -m executorch.examples.models.qwen3_5_moe.export \
432434
--prequantized "$LOCAL_MODEL_DIR" \
@@ -467,21 +469,28 @@ if [ "$MODEL_NAME" = "qwen3_5_moe" ]; then
467469
exit 0
468470
fi
469471

470-
# Gemma 4 31B uses a prequantized checkpoint and custom export script
472+
# Gemma 4 31B: download the Q4_K_M GGUF and export via the GGUF loader
471473
if [ "$MODEL_NAME" = "gemma4_31b" ]; then
472474
pip install safetensors huggingface_hub gguf
473475

474-
# Download prequantized model outside OUTPUT_DIR to avoid uploading on failure
476+
# Download GGUF + tokenizer outside OUTPUT_DIR to avoid uploading on failure.
477+
# The unsloth GGUF repo ships the .gguf but no tokenizer.json, so the tokenizer
478+
# is fetched from the (non-GGUF) unsloth/gemma-4-31B-it repo.
475479
LOCAL_MODEL_DIR=$(mktemp -d)
476-
INDUCTOR_CACHE=$(mktemp -d)
477-
trap 'rm -rf "$LOCAL_MODEL_DIR" "$INDUCTOR_CACHE"' EXIT
480+
INDUCTOR_CACHE=$(mktemp -d "${RUNNER_TEMP:-/tmp}/inductor_cache_XXXXXX")
481+
INDUCTOR_TMPDIR=$(mktemp -d "${RUNNER_TEMP:-/tmp}/tmpdir_XXXXXX")
482+
trap 'rm -rf "$LOCAL_MODEL_DIR" "$INDUCTOR_CACHE" "$INDUCTOR_TMPDIR"' EXIT
478483

479-
python -c "from huggingface_hub import snapshot_download; snapshot_download('${HF_MODEL}', local_dir='${LOCAL_MODEL_DIR}')"
484+
GGUF_FILE="gemma-4-31B-it-Q4_K_M.gguf"
485+
python -c "from huggingface_hub import hf_hub_download; hf_hub_download('unsloth/gemma-4-31B-it-GGUF', '${GGUF_FILE}', local_dir='${LOCAL_MODEL_DIR}')"
486+
python -c "from huggingface_hub import hf_hub_download; hf_hub_download('unsloth/gemma-4-31B-it', 'tokenizer.json', local_dir='${LOCAL_MODEL_DIR}')"
487+
GGUF_PATH="${LOCAL_MODEL_DIR}/${GGUF_FILE}"
480488

481-
# Sanity check: run inference on the prequantized model
489+
# Sanity check: run inference on the GGUF model
482490
echo "::group::Inference sanity check"
483491
INFERENCE_OUTPUT=$(python -m executorch.examples.models.gemma4_31b.inference \
484-
--prequantized "$LOCAL_MODEL_DIR" \
492+
--gguf "$GGUF_PATH" \
493+
--tokenizer-path "${LOCAL_MODEL_DIR}/tokenizer.json" \
485494
--prompt "What is the capital of France?" \
486495
--max-new-tokens 32 \
487496
--temperature 0 \
@@ -494,13 +503,14 @@ if [ "$MODEL_NAME" = "gemma4_31b" ]; then
494503
echo "::endgroup::"
495504

496505
# Copy tokenizer for the runner
497-
cp "$LOCAL_MODEL_DIR/tokenizer.json" "${OUTPUT_DIR}/tokenizer.json"
506+
cp "${LOCAL_MODEL_DIR}/tokenizer.json" "${OUTPUT_DIR}/tokenizer.json"
498507

499508
# Export to .pte/.ptd (short cache dir avoids objcopy symbol length issues)
500509
echo "::group::Export"
510+
TMPDIR="$INDUCTOR_TMPDIR" \
501511
TORCHINDUCTOR_CACHE_DIR="$INDUCTOR_CACHE" \
502512
python -m executorch.examples.models.gemma4_31b.export \
503-
--prequantized "$LOCAL_MODEL_DIR" \
513+
--gguf "$GGUF_PATH" \
504514
--output-dir "${OUTPUT_DIR}"
505515
echo "::endgroup::"
506516

.ci/scripts/test_model.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ test_model_with_qnn() {
264264
;;
265265
esac
266266

267-
"${PYTHON_EXECUTABLE}" -m examples.qualcomm.${SCRIPT_FOLDER}.${EXPORT_SCRIPT} -b ${CMAKE_OUTPUT_DIR} -m ${QNN_CHIPSET} --ci --compile_only $EXTRA_FLAGS
267+
"${PYTHON_EXECUTABLE}" -m examples.qualcomm.${SCRIPT_FOLDER}.${EXPORT_SCRIPT} --build_folder ${CMAKE_OUTPUT_DIR} --soc_model ${QNN_CHIPSET} --ci --compile_only $EXTRA_FLAGS
268268
EXPORTED_MODEL=$(find "./${EXPORT_SCRIPT}" -type f -name "${MODEL_NAME}*.pte" -print -quit)
269269
}
270270

.ci/scripts/test_model_e2e.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ case "$HF_MODEL" in
228228
AUDIO_FILE=""
229229
IMAGE_PATH=""
230230
;;
231-
SocialLocalMobile/gemma-4-31B-it-HQQ-INT4)
231+
unsloth/gemma-4-31B-it-GGUF)
232232
MODEL_NAME="gemma4_31b"
233233
RUNNER_TARGET="gemma4_31b_runner"
234234
RUNNER_PATH="gemma4_31b"
@@ -242,7 +242,7 @@ case "$HF_MODEL" in
242242
;;
243243
*)
244244
echo "Error: Unsupported model '$HF_MODEL'"
245-
echo "Supported models: mistralai/Voxtral-Mini-3B-2507, mistralai/Voxtral-Mini-4B-Realtime-2602, nvidia/diar_streaming_sortformer_4spk-v2, openai/whisper series (whisper-{small, medium, large, large-v2, large-v3, large-v3-turbo}), google/gemma-3-4b-it, Qwen/Qwen3-0.6B, nvidia/parakeet-tdt, facebook/dinov2-small-imagenet1k-1-layer, SocialLocalMobile/Qwen3.5-35B-A3B-HQQ-INT4, SocialLocalMobile/gemma-4-31B-it-HQQ-INT4"
245+
echo "Supported models: mistralai/Voxtral-Mini-3B-2507, mistralai/Voxtral-Mini-4B-Realtime-2602, nvidia/diar_streaming_sortformer_4spk-v2, openai/whisper series (whisper-{small, medium, large, large-v2, large-v3, large-v3-turbo}), google/gemma-3-4b-it, Qwen/Qwen3-0.6B, nvidia/parakeet-tdt, facebook/dinov2-small-imagenet1k-1-layer, SocialLocalMobile/Qwen3.5-35B-A3B-HQQ-INT4, unsloth/gemma-4-31B-it-GGUF"
246246
exit 1
247247
;;
248248
esac

.ci/scripts/test_model_e2e_windows.ps1

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,11 @@ try {
176176

177177
Write-Host "::group::Build ExecuTorch (CUDA)"
178178
$numCores = [Math]::Max([Environment]::ProcessorCount - 1, 1)
179-
cmake --preset llm-release-cuda @cmakeCudaArgs
179+
# EXECUTORCH_BUILD_EXTENSION_IMAGE defaults OFF in the preset, so it must be
180+
# enabled explicitly here (matching the Makefile CUDA target used on Linux).
181+
# The dinov2 runner links the installed extension_image.lib; without this the
182+
# main install never builds it and dinov2_runner fails to link (LNK1181).
183+
cmake --preset llm-release-cuda -DEXECUTORCH_BUILD_EXTENSION_IMAGE=ON @cmakeCudaArgs
180184
cmake --build cmake-out --target install --config Release -j $numCores
181185
Write-Host "::endgroup::"
182186

.github/workflows/_llm_server.yml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
name: LLM Server Tests
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
docker-image:
7+
description: Docker image to use for Linux tests.
8+
required: false
9+
type: string
10+
default: ci-image:executorch-ubuntu-22.04-clang12
11+
12+
jobs:
13+
linux:
14+
uses: pytorch/test-infra/.github/workflows/linux_job_v2.yml@main
15+
permissions:
16+
id-token: write
17+
contents: read
18+
with:
19+
runner: linux.2xlarge
20+
docker-image: ${{ inputs.docker-image }}
21+
submodules: recursive
22+
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
23+
timeout: 60
24+
script: |
25+
set -eux
26+
27+
eval "$(conda shell.bash hook)"
28+
CONDA_ENV=$(conda env list --json | jq -r ".envs | .[-1]")
29+
conda activate "${CONDA_ENV}"
30+
31+
python -m pip install --progress-bar off \
32+
-r examples/llm_server/python/requirements.txt \
33+
httpx \
34+
pytest
35+
36+
export PYTHONPATH="$(dirname "${PWD}"):${PYTHONPATH:-}"
37+
export PYTHONDONTWRITEBYTECODE=1
38+
39+
python -m pytest -q examples/llm_server/python/tests
40+
41+
cmake -S . -B cmake-out \
42+
-DCMAKE_BUILD_TYPE=Release \
43+
-DCMAKE_INSTALL_PREFIX=cmake-out \
44+
-DEXECUTORCH_BUILD_EXTENSION_LLM=ON \
45+
-DEXECUTORCH_BUILD_EXTENSION_LLM_RUNNER=ON
46+
cmake --build cmake-out --target install -j "$(nproc)"
47+
48+
cmake -S examples/llm_server/cpp -B cmake-out/examples/llm_server/cpp \
49+
-DCMAKE_PREFIX_PATH="${PWD}/cmake-out"
50+
cmake --build cmake-out/examples/llm_server/cpp \
51+
--target test_worker_prefill_plan test_worker_loop \
52+
-j "$(nproc)"
53+
ctest --test-dir cmake-out/examples/llm_server/cpp --output-on-failure

.github/workflows/cuda.yml

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -258,8 +258,8 @@ jobs:
258258
name: "dinov2-small-imagenet1k-1-layer"
259259
- repo: "SocialLocalMobile"
260260
name: "Qwen3.5-35B-A3B-HQQ-INT4"
261-
- repo: "SocialLocalMobile"
262-
name: "gemma-4-31B-it-HQQ-INT4"
261+
- repo: "unsloth"
262+
name: "gemma-4-31B-it-GGUF"
263263
quant:
264264
- "non-quantized"
265265
- "quantized-int4-tile-packed"
@@ -281,12 +281,12 @@ jobs:
281281
quant: "quantized-int4-weight-only"
282282
# Gemma 4 31B uses a prequantized checkpoint, only tile-packed
283283
- model:
284-
repo: "SocialLocalMobile"
285-
name: "gemma-4-31B-it-HQQ-INT4"
284+
repo: "unsloth"
285+
name: "gemma-4-31B-it-GGUF"
286286
quant: "non-quantized"
287287
- model:
288-
repo: "SocialLocalMobile"
289-
name: "gemma-4-31B-it-HQQ-INT4"
288+
repo: "unsloth"
289+
name: "gemma-4-31B-it-GGUF"
290290
quant: "quantized-int4-weight-only"
291291
# Voxtral Realtime only supports int4-tile-packed on CUDA
292292
- model:
@@ -342,7 +342,7 @@ jobs:
342342
with:
343343
timeout: 150
344344
secrets-env: EXECUTORCH_HF_TOKEN
345-
runner: ${{ (matrix.model.name == 'Qwen3.5-35B-A3B-HQQ-INT4' || matrix.model.name == 'gemma-4-31B-it-HQQ-INT4') && 'mt-l-x86iavx512-11-125-a100' || 'mt-l-x86aavx2-29-113-a10g' }}
345+
runner: ${{ (matrix.model.name == 'Qwen3.5-35B-A3B-HQQ-INT4' || matrix.model.name == 'gemma-4-31B-it-GGUF') && 'mt-l-x86iavx512-11-125-a100' || 'mt-l-x86aavx2-29-113-a10g' }}
346346
gpu-arch-type: cuda
347347
gpu-arch-version: "13.0"
348348
use-custom-docker-registry: false
@@ -424,8 +424,8 @@ jobs:
424424
name: "dinov2-small-imagenet1k-1-layer"
425425
- repo: "SocialLocalMobile"
426426
name: "Qwen3.5-35B-A3B-HQQ-INT4"
427-
- repo: "SocialLocalMobile"
428-
name: "gemma-4-31B-it-HQQ-INT4"
427+
- repo: "unsloth"
428+
name: "gemma-4-31B-it-GGUF"
429429
quant:
430430
- "non-quantized"
431431
- "quantized-int4-tile-packed"
@@ -447,12 +447,12 @@ jobs:
447447
quant: "quantized-int4-weight-only"
448448
# Gemma 4 31B uses a prequantized checkpoint, only tile-packed
449449
- model:
450-
repo: "SocialLocalMobile"
451-
name: "gemma-4-31B-it-HQQ-INT4"
450+
repo: "unsloth"
451+
name: "gemma-4-31B-it-GGUF"
452452
quant: "non-quantized"
453453
- model:
454-
repo: "SocialLocalMobile"
455-
name: "gemma-4-31B-it-HQQ-INT4"
454+
repo: "unsloth"
455+
name: "gemma-4-31B-it-GGUF"
456456
quant: "quantized-int4-weight-only"
457457
# Voxtral Realtime only supports int4-tile-packed on CUDA
458458
- model:
@@ -502,7 +502,7 @@ jobs:
502502
quant: "non-quantized"
503503
with:
504504
timeout: 90
505-
runner: ${{ (matrix.model.name == 'Qwen3.5-35B-A3B-HQQ-INT4' || matrix.model.name == 'gemma-4-31B-it-HQQ-INT4') && 'mt-l-x86iavx512-11-125-a100' || 'mt-l-x86aavx2-29-113-a10g' }}
505+
runner: ${{ (matrix.model.name == 'Qwen3.5-35B-A3B-HQQ-INT4' || matrix.model.name == 'gemma-4-31B-it-GGUF') && 'mt-l-x86iavx512-11-125-a100' || 'mt-l-x86aavx2-29-113-a10g' }}
506506
gpu-arch-type: cuda
507507
gpu-arch-version: "13.0"
508508
use-custom-docker-registry: false

.github/workflows/docker-builds.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ jobs:
4343
executorch-ubuntu-22.04-mediatek-sdk,
4444
executorch-ubuntu-22.04-clang12-android,
4545
executorch-ubuntu-24.04-gcc14,
46-
executorch-ubuntu-26.04-gcc15,
46+
executorch-ubuntu-26.04-gcc14,
4747
]
4848
include:
4949
- docker-image-name: executorch-ubuntu-22.04-gcc11-aarch64

.github/workflows/pull.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1400,7 +1400,7 @@ jobs:
14001400
docker-image: ci-image:executorch-ubuntu-22.04-clang12
14011401
submodules: 'recursive'
14021402
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
1403-
timeout: 90
1403+
timeout: 120
14041404
script: |
14051405
set -eux
14061406

.github/workflows/trunk.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1045,6 +1045,20 @@ jobs:
10451045
build-tool: cmake
10461046
docker-image: ci-image:executorch-ubuntu-22.04-clang12
10471047

1048+
llm-server:
1049+
needs: [changed-files, run-decision]
1050+
if: |
1051+
contains(needs.changed-files.outputs.changed-files, 'examples/llm_server') ||
1052+
contains(needs.changed-files.outputs.changed-files, 'extension/llm/runner') ||
1053+
contains(needs.changed-files.outputs.changed-files, 'extension/llm/tokenizers') ||
1054+
contains(needs.changed-files.outputs.changed-files, '.github/workflows/_llm_server.yml') ||
1055+
contains(needs.changed-files.outputs.changed-files, '.github/workflows/trunk.yml') ||
1056+
needs.run-decision.outputs.is-full-run == 'true'
1057+
uses: ./.github/workflows/_llm_server.yml
1058+
permissions:
1059+
id-token: write
1060+
contents: read
1061+
10481062
test-models-windows:
10491063
needs: run-decision
10501064
if: |

0 commit comments

Comments
 (0)