Skip to content

Commit 79d269d

Browse files
Merge branch 'main' into delete-exir-capture
2 parents 5ae6c54 + 0061fd2 commit 79d269d

688 files changed

Lines changed: 53402 additions & 36821 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/scripts/download_hf_hub.sh‎

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@ export HF_HUB_DISABLE_XET=1
77
# Arguments:
88
# 1. model_id: The Hugging Face repository ID (e.g., "organization/model_name")
99
# 2. subdir: The optional subdirectory in the repo to look for files (pass "" if not used)
10-
# 3. file_names: A space-separated list of filenames to be downloaded
10+
# 3. revision: The commit hash to download
11+
# 4. file_names: A space-separated list of filenames to be downloaded
1112
# Returns:
1213
# The directory containing the downloaded files
1314
function download_hf_files() {
1415
local model_id="$1"
1516
local subdir="$2"
16-
shift 2
17+
local revision="$3"
18+
shift 3
1719
local file_names=("$@") # Capture all remaining arguments as an array
1820

1921
local download_dir
@@ -24,7 +26,8 @@ from huggingface_hub import hf_hub_download
2426
# Download the first file and get its directory
2527
path = hf_hub_download(
2628
repo_id='${model_id}',
27-
filename='${subdir:+${subdir}/}${file_names[0]}'
29+
filename='${subdir:+${subdir}/}${file_names[0]}',
30+
revision='${revision}'
2831
)
2932
import os
3033
print(os.path.dirname(path))")
@@ -41,7 +44,8 @@ from huggingface_hub import hf_hub_download
4144
# Download the file
4245
hf_hub_download(
4346
repo_id='${model_id}',
44-
filename='${subdir:+${subdir}/}${file_name}'
47+
filename='${subdir:+${subdir}/}${file_name}',
48+
revision='${revision}'
4549
)"
4650

4751
if [ $? -ne 0 ]; then
@@ -67,6 +71,10 @@ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
6771
SUBDIR="$2"
6872
shift 2
6973
;;
74+
--revision)
75+
REVISION="$2"
76+
shift 2
77+
;;
7078
--files)
7179
shift
7280
FILES_TO_DOWNLOAD=()
@@ -83,13 +91,13 @@ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
8391
done
8492

8593
# Validate required arguments
86-
if [ -z "$MODEL_ID" ] || [ ${#FILES_TO_DOWNLOAD[@]} -eq 0 ]; then
87-
echo "Usage: $0 --model_id <model_id> --subdir <subdir> --files <file1> [<file2> ...]" >&2
94+
if [ -z "$MODEL_ID" ] || [ -z "$REVISION" ] || [ ${#FILES_TO_DOWNLOAD[@]} -eq 0 ]; then
95+
echo "Usage: $0 --model_id <model_id> --revision <commit> --subdir <subdir> --files <file1> [<file2> ...]" >&2
8896
exit 1
8997
fi
9098

9199
# Call the function
92-
DOWNLOAD_DIR=$(download_hf_files "$MODEL_ID" "$SUBDIR" "${FILES_TO_DOWNLOAD[@]}")
100+
DOWNLOAD_DIR=$(download_hf_files "$MODEL_ID" "$SUBDIR" "$REVISION" "${FILES_TO_DOWNLOAD[@]}")
93101
if [ $? -eq 0 ]; then
94102
echo "$DOWNLOAD_DIR"
95103
else

‎.ci/scripts/test_espressif.sh‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ build_dir=$(cd "${build_dir}" && pwd)
2121
cd "${et_root}"
2222

2323
collect_artifacts() {
24+
local file operator_dir artifact_dir
2425
if [[ -n "${RUNNER_ARTIFACT_DIR:-}" ]]; then
2526
mkdir -p "${RUNNER_ARTIFACT_DIR}/esp32s3"
2627
for file in "${build_dir}"/*.log "${build_dir}"/*.bpte \
@@ -35,6 +36,18 @@ collect_artifacts() {
3536
cp "${file}" "${RUNNER_ARTIFACT_DIR}/esp32s3/"
3637
fi
3738
done
39+
for operator_dir in "${build_dir}"/operator-library-*; do
40+
[[ -d "${operator_dir}" ]] || continue
41+
artifact_dir="${RUNNER_ARTIFACT_DIR}/esp32s3/${operator_dir##*/}"
42+
mkdir -p "${artifact_dir}"
43+
for file in "${operator_dir}"/*.log "${operator_dir}"/*.bpte \
44+
"${operator_dir}/sdkconfig" "${operator_dir}"/*.elf \
45+
"${operator_dir}/merged-binary.bin"; do
46+
if [[ -f "${file}" ]]; then
47+
cp "${file}" "${artifact_dir}/"
48+
fi
49+
done
50+
done
3851
fi
3952
}
4053
trap collect_artifacts EXIT
@@ -54,6 +67,9 @@ python examples/espressif/export_espnn_test_programs.py \
5467
# runs inline without pthreadpool, which needs POSIX calls ESP-IDF lacks.
5568
espnn_ops=$(tr -d '\n' < "${build_dir}/espnn-tests/operators.txt" \
5669
| tr ',' '\n' | grep -v '^quantized_decomposed::' | paste -sd, -)
70+
if [[ "${espnn_kernels}" == optimized ]]; then
71+
espnn_ops="${espnn_ops},aten::sin.out"
72+
fi
5773

5874
cmake --preset esp-baremetal -G Ninja -B "${build_dir}/runtime" \
5975
-DCMAKE_TOOLCHAIN_FILE="${IDF_PATH}/tools/cmake/toolchain-esp32s3.cmake" \
@@ -136,3 +152,16 @@ import json, sys
136152
for entry in json.load(open(sys.argv[1])):
137153
print(entry["name"], entry["atol"], entry["rtol"])
138154
' "${build_dir}/espnn-tests/manifest.json")
155+
156+
if [[ "${espnn_kernels}" == optimized ]]; then
157+
# Stop on failure so later cases cannot overwrite its firmware and logs.
158+
ESPRESSIF_BUILD_DIR="${build_dir}" python -m pytest \
159+
-x -v --tb=short backends/espressif/test/ops -k implementation \
160+
2>&1 | tee "${build_dir}/operator-library-tests.log"
161+
for sdkconfig in "${build_dir}"/operator-library-*/sdkconfig; do
162+
if ! grep -qx 'CONFIG_NN_OPTIMIZED=y' "${sdkconfig}"; then
163+
echo "Expected CONFIG_NN_OPTIMIZED=y in ${sdkconfig}" >&2
164+
exit 1
165+
fi
166+
done
167+
fi
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#!/usr/bin/env bash
2+
# Copyright (c) Meta Platforms, Inc. and affiliates.
3+
# All rights reserved.
4+
#
5+
# This source code is licensed under the BSD-style license found in the
6+
# LICENSE file in the root directory of this source tree.
7+
8+
# Generates the ExecuTorch ESP-IDF component with every shipped profile,
9+
# builds the idf_component_smoke consumer for ESP32-S3 against each, and runs
10+
# the smoke profile build on the emulator.
11+
12+
set -euo pipefail
13+
14+
et_root=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)
15+
build_dir="${ESPRESSIF_BUILD_DIR:-${et_root}/cmake-out-esp-idf-component}"
16+
export ESPRESSIF_TOOLS_DIR="${ESPRESSIF_TOOLS_DIR:-${RUNNER_TEMP:-/tmp}/executorch-espressif}"
17+
mkdir -p "${build_dir}"
18+
build_dir=$(cd "${build_dir}" && pwd)
19+
cd "${et_root}"
20+
21+
collect_artifacts() {
22+
if [[ -n "${RUNNER_ARTIFACT_DIR:-}" ]]; then
23+
mkdir -p "${RUNNER_ARTIFACT_DIR}/esp-idf-component"
24+
for file in "${build_dir}"/*.log "${build_dir}/components/executorch/VERSION"; do
25+
if [[ -f "${file}" ]]; then
26+
cp "${file}" "${RUNNER_ARTIFACT_DIR}/esp-idf-component/"
27+
fi
28+
done
29+
fi
30+
}
31+
trap collect_artifacts EXIT
32+
33+
bash examples/espressif/setup.sh --minimal 2>&1 | tee "${build_dir}/setup.log"
34+
# shellcheck source=/dev/null
35+
source "${ESPRESSIF_TOOLS_DIR}/setup_path.sh"
36+
37+
python examples/espressif/export_smoke_model.py \
38+
--output "${build_dir}/smoke.bpte" --pte-output "${build_dir}/smoke.pte" \
39+
2>&1 | tee "${build_dir}/export.log"
40+
41+
component_dir="${build_dir}/components/executorch"
42+
profiles=$(find examples/espressif/idf_profiles -name '*.ops' -exec basename {} .ops \; \
43+
| sort | paste -sd, -)
44+
bash examples/espressif/build_idf_component.sh --profiles "${profiles}" \
45+
--out "${component_dir}" 2>&1 | tee "${build_dir}/generate.log"
46+
47+
project=examples/espressif/idf_component_smoke
48+
for profile in ${profiles//,/ }; do
49+
profile_upper=$(echo "${profile}" | tr '[:lower:]-' '[:upper:]_')
50+
firmware_dir="${build_dir}/firmware-${profile}"
51+
printf 'CONFIG_ET_OP_PROFILE_%s=y\n' "${profile_upper}" \
52+
> "${build_dir}/${profile}.defaults"
53+
idf.py -C "${project}" -B "${firmware_dir}" \
54+
-DIDF_TARGET=esp32s3 \
55+
-DSDKCONFIG="${build_dir}/sdkconfig-${profile}" \
56+
"-DSDKCONFIG_DEFAULTS=sdkconfig.defaults;${build_dir}/${profile}.defaults" \
57+
-DET_COMPONENT_DIR="${component_dir}" \
58+
-DET_SMOKE_PTE="${build_dir}/smoke.pte" build \
59+
2>&1 | tee "${build_dir}/firmware-${profile}.log"
60+
done
61+
62+
firmware_dir="${build_dir}/firmware-smoke"
63+
idf.py -C "${project}" -B "${firmware_dir}" merge-bin \
64+
2>&1 | tee "${build_dir}/firmware-merge.log"
65+
timeout 130s esp-emu --chip esp32s3 \
66+
--firmware "${firmware_dir}/merged-binary.bin" \
67+
--elf "${firmware_dir}/et_component_smoke.elf" \
68+
--net user --timeout 120s --exit-on 'Program complete.' \
69+
2>&1 | tee "${build_dir}/emulator.log"
70+
for marker in "ET_COMPONENT_SMOKE: PASS" "Program complete."; do
71+
if ! grep -qF "${marker}" "${build_dir}/emulator.log"; then
72+
echo "FAIL: missing '${marker}'; see ${build_dir}/emulator.log" >&2
73+
exit 1
74+
fi
75+
done
76+
echo "PASS: generated ESP-IDF component ran the smoke model on the ESP32-S3 emulator."

‎.ci/scripts/test_lora.sh‎

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,26 +57,43 @@ PY
5757
}
5858

5959
# Hosting lora adapter in personal repo for now.
60+
# The Hugging Face downloads below are pinned to commits the read-only
61+
# CI cache holds. To bump a pin, seed the cache first from a pytorch/executorch
62+
# branch (forks cannot write the cache): run pull.yml on it with
63+
# workflow_dispatch, or push to it after its pull request has the
64+
# ci-refresh-hf-cache label.
6065
python -m pip install -q huggingface_hub
6166
HF_ADAPTER_REPO="lucylq/qwen3_06B_lora_math"
6267
HF_ADAPTER_PATH=$(
6368
bash "$(dirname "${BASH_SOURCE[0]}")/download_hf_hub.sh" \
6469
--model_id "${HF_ADAPTER_REPO}" \
70+
--revision 0e6bc3a88a597c5abc4872734eec8db3a9fdd846 \
6571
--files "adapter_config.json" "adapter_model.safetensors"
6672
)
6773

6874
# Set environment variables for OmegaConf interpolation in yaml.
6975
export LORA_ADAPTER_CHECKPOINT="${HF_ADAPTER_PATH}/adapter_model.safetensors"
7076
export LORA_ADAPTER_CONFIG="${HF_ADAPTER_PATH}/adapter_config.json"
7177

78+
# Without a checkpoint, export downloads Qwen/Qwen3-0.6B from its main branch,
79+
# so convert the pinned commit the read-only CI cache holds instead.
80+
QWEN_SNAPSHOT=$($PYTHON_EXECUTABLE -m executorch.examples.models.llama.hf_download \
81+
snapshot Qwen/Qwen3-0.6B --revision c1899de289a04d12100db370d81485cdf75e47ca)
82+
QWEN_CHECKPOINT_DIR=$(mktemp -d "${RUNNER_TEMP:-/tmp}/qwen3_0_6b_XXXXXX")
83+
trap 'rm -rf "${QWEN_CHECKPOINT_DIR}"' EXIT
84+
QWEN_CHECKPOINT="${QWEN_CHECKPOINT_DIR}/qwen3_0_6b.pth"
85+
$PYTHON_EXECUTABLE -m executorch.examples.models.qwen3.convert_weights \
86+
"${QWEN_SNAPSHOT}" "${QWEN_CHECKPOINT}"
87+
7288
### SINGLE LORA PTE ###
7389
# Export LoRA PTE file.
7490
$PYTHON_EXECUTABLE -m extension.llm.export.export_llm \
7591
--config examples/models/qwen3/config/qwen3_xnnpack_lora.yaml \
92+
+base.checkpoint="${QWEN_CHECKPOINT}" \
7693
+export.output_name="qwen_lora_math_full.pte"
7794

7895
# Capture the path of the downloaded qwen artifacts
79-
HF_QWEN_PATH=$(python -c "from huggingface_hub import snapshot_download; print(snapshot_download('unsloth/Qwen3-0.6B'))")
96+
HF_QWEN_PATH=$(python -c "from huggingface_hub import snapshot_download; print(snapshot_download('unsloth/Qwen3-0.6B', revision='db4e90b8359f816f09bf5c944797ce116f26da3c'))")
8097
echo "Model downloaded to: $HF_QWEN_PATH"
8198

8299
### BUILD LLAMA RUNNER.
@@ -120,6 +137,7 @@ fi
120137
# Export LoRA PTE, LoRA PTD, foundation PTD file.
121138
$PYTHON_EXECUTABLE -m extension.llm.export.export_llm \
122139
--config examples/models/qwen3/config/qwen3_xnnpack_lora.yaml \
140+
+base.checkpoint="${QWEN_CHECKPOINT}" \
123141
+export.output_name="qwen_lora_math.pte" \
124142
+export.foundation_weights_file="qwen_foundation.ptd" \
125143
+export.lora_weights_file="qwen_lora_math.ptd"
@@ -179,6 +197,7 @@ The answer is: 12<|im_end|>"
179197
# and loading lora weights.
180198
$PYTHON_EXECUTABLE -m extension.llm.export.export_llm \
181199
--config examples/models/qwen3/config/qwen3_xnnpack_lora.yaml \
200+
+base.checkpoint="${QWEN_CHECKPOINT}" \
182201
base.lora_config=null \
183202
+export.output_name="qwen_q.pte" \
184203
+export.foundation_weights_file="qwen_foundation_q.ptd" \
@@ -188,6 +207,7 @@ $PYTHON_EXECUTABLE -m extension.llm.export.export_llm \
188207
# Export Quantized LoRA PTE, LoRA PTD, foundation PTD file.
189208
$PYTHON_EXECUTABLE -m extension.llm.export.export_llm \
190209
--config examples/models/qwen3/config/qwen3_xnnpack_lora.yaml \
210+
+base.checkpoint="${QWEN_CHECKPOINT}" \
191211
+export.output_name="qwen_lora_math_q.pte" \
192212
+export.foundation_weights_file="qwen_foundation_lora_q.ptd" \
193213
+export.lora_weights_file="qwen_lora_math_q.ptd" \

‎.ci/scripts/test_lora_multimethod.sh‎

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,25 +57,42 @@ PY
5757
}
5858

5959
# Download LoRA adapter.
60+
# The Hugging Face downloads below are pinned to commits the read-only
61+
# CI cache holds. To bump a pin, seed the cache first from a pytorch/executorch
62+
# branch (forks cannot write the cache): run pull.yml on it with
63+
# workflow_dispatch, or push to it after its pull request has the
64+
# ci-refresh-hf-cache label.
6065
python -m pip install -q huggingface_hub
6166
HF_ADAPTER_REPO="lucylq/qwen3_06B_lora_math"
6267
HF_ADAPTER_PATH=$(
6368
bash "$(dirname "${BASH_SOURCE[0]}")/download_hf_hub.sh" \
6469
--model_id "${HF_ADAPTER_REPO}" \
70+
--revision 0e6bc3a88a597c5abc4872734eec8db3a9fdd846 \
6571
--files "adapter_config.json" "adapter_model.safetensors"
6672
)
6773

6874
# Download base model (for tokenizer path).
69-
HF_QWEN_PATH=$(python -c "from huggingface_hub import snapshot_download; print(snapshot_download('unsloth/Qwen3-0.6B'))")
75+
HF_QWEN_PATH=$(python -c "from huggingface_hub import snapshot_download; print(snapshot_download('unsloth/Qwen3-0.6B', revision='db4e90b8359f816f09bf5c944797ce116f26da3c'))")
7076
echo "Model downloaded to: $HF_QWEN_PATH"
7177

78+
# Without a checkpoint, export downloads Qwen/Qwen3-0.6B from its main branch,
79+
# so convert the pinned commit the read-only CI cache holds instead.
80+
QWEN_SNAPSHOT=$($PYTHON_EXECUTABLE -m executorch.examples.models.llama.hf_download \
81+
snapshot Qwen/Qwen3-0.6B --revision c1899de289a04d12100db370d81485cdf75e47ca)
82+
QWEN_CHECKPOINT_DIR=$(mktemp -d "${RUNNER_TEMP:-/tmp}/qwen3_0_6b_XXXXXX")
83+
trap 'rm -rf "${QWEN_CHECKPOINT_DIR}"' EXIT
84+
QWEN_CHECKPOINT="${QWEN_CHECKPOINT_DIR}/qwen3_0_6b.pth"
85+
$PYTHON_EXECUTABLE -m executorch.examples.models.qwen3.convert_weights \
86+
"${QWEN_SNAPSHOT}" "${QWEN_CHECKPOINT}"
87+
7288
### EXPORT MULTIMETHOD PTE ###
7389
# Set environment variables for OmegaConf interpolation in yaml.
7490
export LORA_ADAPTER_CHECKPOINT="${HF_ADAPTER_PATH}/adapter_model.safetensors"
7591
export LORA_ADAPTER_CONFIG="${HF_ADAPTER_PATH}/adapter_config.json"
7692

7793
$PYTHON_EXECUTABLE -m extension.llm.export.export_llm \
78-
--config examples/models/qwen3/config/qwen3_multimethod.yaml
94+
--config examples/models/qwen3/config/qwen3_multimethod.yaml \
95+
+base.checkpoint="${QWEN_CHECKPOINT}"
7996

8097
### BUILD LLAMA RUNNER ###
8198
cmake_install_executorch_libraries

‎.ci/scripts/test_openvino.sh‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,8 @@ source "$(dirname "${BASH_SOURCE[0]}")/utils.sh"
1212

1313
source openvino/setupvars.sh
1414
cd backends/openvino/tests
15-
python test_runner.py --test_type ops
16-
python test_runner.py --test_type models
15+
# Run the model tests even when an op test fails, and still fail the job.
16+
status=0
17+
python test_runner.py --test_type ops || status=1
18+
python test_runner.py --test_type models || status=1
19+
exit "${status}"

‎.ci/scripts/test_torchao_huggingface_checkpoints.sh‎

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,16 @@ fi
4747

4848
MODEL_OUT=model.pte
4949

50+
# Hugging Face Hub revisions, pinned. On OSDC runners HF_HUB_CACHE is a read-only
51+
# mount seeded with these snapshots, so downloading an unpinned repo fails with
52+
# "Read-only file system" as soon as the repo gets a new commit, even a README
53+
# edit (LiquidAI/LFM2.5-1.2B-Instruct on 2026-11-03). To move to a newer
54+
# revision, update it here and add the ci-refresh-hf-cache label to the PR so
55+
# the cache gets seeded.
56+
QWEN3_4B_REVISION=3d10de24598fff7a1ff7297103693fe1d2b82a5e
57+
PHI_4_MINI_REVISION=ca214ad7becf450bed20235bc677418a092a718a
58+
LFM2_5_1_2B_REVISION=0f604ada3f766f9f257460c4c9f0b5d6f69d431b
59+
5060

5161
# Default to XNNPACK
5262
BACKEND_ARGS="-X --xnnpack-extended-ops"
@@ -57,7 +67,7 @@ fi
5767
case "$MODEL_NAME" in
5868
qwen3_4b)
5969
echo "Running Qwen3-4B export..."
60-
HF_MODEL_DIR=$(hf download pytorch/Qwen3-4B-INT8-INT4)
70+
HF_MODEL_DIR=$(hf download pytorch/Qwen3-4B-INT8-INT4 --revision "${QWEN3_4B_REVISION}")
6171
EXPECTED_MODEL_SIZE_UPPER_BOUND=$((3 * 1024 * 1024 * 1024)) # 3GB
6272
$PYTHON_EXECUTABLE -m executorch.examples.models.qwen3.convert_weights \
6373
$HF_MODEL_DIR \
@@ -80,7 +90,7 @@ case "$MODEL_NAME" in
8090

8191
phi_4_mini)
8292
echo "Running Phi-4-mini export..."
83-
HF_MODEL_DIR=$(hf download pytorch/Phi-4-mini-instruct-INT8-INT4)
93+
HF_MODEL_DIR=$(hf download pytorch/Phi-4-mini-instruct-INT8-INT4 --revision "${PHI_4_MINI_REVISION}")
8494
EXPECTED_MODEL_SIZE_UPPER_BOUND=$((3 * 1024 * 1024 * 1024)) # 3GB
8595
$PYTHON_EXECUTABLE -m executorch.examples.models.phi_4_mini.convert_weights \
8696
$HF_MODEL_DIR \
@@ -103,7 +113,7 @@ case "$MODEL_NAME" in
103113

104114
lfm2_5_1_2b)
105115
echo "Running LFM2.5-1.2B export..."
106-
HF_MODEL_DIR=$(hf download LiquidAI/LFM2.5-1.2B-Instruct)
116+
HF_MODEL_DIR=$(hf download LiquidAI/LFM2.5-1.2B-Instruct --revision "${LFM2_5_1_2B_REVISION}")
107117
EXPECTED_MODEL_SIZE_UPPER_BOUND=$((2500 * 1024 * 1024)) # 2.5GB
108118
$PYTHON_EXECUTABLE -m executorch.examples.models.lfm2.convert_weights \
109119
$HF_MODEL_DIR \

0 commit comments

Comments
 (0)