aorabdel commited on
Commit
2f6f985
·
verified ·
1 Parent(s): 640608d

Sync model repo (text/metadata)

Browse files
Files changed (7) hide show
  1. .python-version +1 -0
  2. README.md +144 -172
  3. example.py +357 -100
  4. metadata.yaml +3 -1
  5. pyproject.toml +38 -0
  6. transcription.json +3 -3
  7. uv.lock +724 -0
.python-version ADDED
@@ -0,0 +1 @@
 
 
1
+ 3.12
README.md CHANGED
@@ -1,218 +1,190 @@
1
  ---
2
- library_name: executorch
3
- license: mit
4
  pipeline_tag: automatic-speech-recognition
5
- base_model: openai/whisper-small
6
- base_model_relation: quantized
7
  tags:
8
- - automatic-speech-recognition
9
- - whisper
10
- - int8
11
- - quantized
12
- - xnnpack
13
  - arm
 
 
14
  - executorch
15
- - edge-ai
16
- - librispeech
17
- datasets:
18
- - librispeech_asr
19
- metrics:
20
- - wer
21
- - cer
22
- model-index:
23
- - name: whisper-small-int8-xnnpack-executorch
24
- results:
25
- - task:
26
- type: automatic-speech-recognition
27
- dataset:
28
- type: librispeech_asr
29
- name: LibriSpeech ASR (test-clean)
30
- split: test
31
- args:
32
- evaluation_samples: 2620
33
- metrics:
34
- - type: wer
35
- value: 3.41
36
- name: WER (ExecuTorch)
37
- - type: cer
38
- value: 1.29
39
- name: CER (ExecuTorch)
40
  ---
41
 
42
- # Whisper Small INT8 (ExecuTorch + XNNPACK + KleidiAI)
43
 
44
- INT8 8da8w quantized version of [openai/whisper-small](https://huggingface.co/openai/whisper-small),
45
- optimized for ARM deployment using ExecuTorch, XNNPACK, and KleidiAI. The model targets
46
- on-device English speech-to-text transcription on Android and ARM-based edge hardware,
47
- delivering near-identical accuracy at substantially lower latency and memory footprint.
48
 
49
- ## Key Highlights
50
 
51
- Compared to the FP32 baseline on ARM hardware (Vivo X300, Arm C1):
52
 
53
- - **2.72x smaller** .pte artifact shrinks from 1074.76 MB to 395.05 MB
54
- - **1.40x faster inference** — end-to-end latency drops from 10927.0 ms to 7802.5 ms (p50)
55
- - **WER preserved** — 3.45% to 3.41% on LibriSpeech test-clean (2620 utterances)
56
 
57
- ## Model Details
58
 
59
- | Property | Value |
60
  |---|---|
61
- | Developed by | OpenAI |
62
- | Model type | Automatic Speech Recognition (encoder-decoder Transformer) |
63
- | Language | English |
64
- | License | MIT |
65
- | Base model | [openai/whisper-small](https://huggingface.co/openai/whisper-small) |
66
- | Modification | Post-training quantization (8da8w), not finetuned |
67
- | Parameter count | 241.73M |
68
- | PyTorch state dict size | 922.31 MB |
69
- | Optimized .pte size | 395.05 MB |
70
-
71
- ## How to Get Started
72
 
73
- ### Install dependencies
74
 
75
- ```bash
76
- pip install transformers torch soundfile numpy
77
- ```
 
 
 
 
78
 
79
- ### Run inference
80
 
81
- ```bash
82
- python example.py
83
- ```
 
 
 
 
 
 
84
 
85
- ### Core inference loop
86
-
87
- ```python
88
- from transformers import WhisperForConditionalGeneration, WhisperProcessor
89
- import torch
90
-
91
- MODEL_NAME = "openai/whisper-small"
92
- LANGUAGE = "en"
93
- TASK = "transcribe"
94
- MAX_NEW_TOKENS = 128
95
-
96
- processor = WhisperProcessor.from_pretrained(MODEL_NAME)
97
- model = WhisperForConditionalGeneration.from_pretrained(MODEL_NAME)
98
- model.eval()
99
-
100
- def transcribe(audio_path: str) -> str:
101
- """Load audio and return transcribed text."""
102
- import soundfile as sf
103
- import numpy as np
104
-
105
- audio_np, sr = sf.read(audio_path, dtype="float32")
106
- if audio_np.ndim == 2:
107
- audio_np = audio_np.mean(axis=1)
108
-
109
- features = processor.feature_extractor(
110
- audio_np, sampling_rate=sr, return_tensors="pt"
111
- ).input_features # [1, 80, 3000]
112
-
113
- with torch.no_grad():
114
- output_ids = model.generate(
115
- features,
116
- language=LANGUAGE,
117
- task=TASK,
118
- max_new_tokens=MAX_NEW_TOKENS,
119
- )
120
- return processor.tokenizer.batch_decode(output_ids, skip_special_tokens=True)[0].strip()
121
- ```
122
 
123
- > **Note on .pte artifacts:** The `pte_optimized/` and `pte_original/` directories contain
124
- > ExecuTorch-serialized models for on-device ARM inference. Running them requires the
125
- > ExecuTorch C++ seq2seq runner — they are not suitable for a simple Python
126
- > `method.execute()` call. The `example.py` script above uses the HuggingFace Transformers
127
- > library for Python-based evaluation and prototyping.
128
 
129
- ## Evaluation
130
 
131
- ### Testing data
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
 
133
- 2620 utterances from the LibriSpeech ASR `test-clean` split. Calibration: none required
134
- (dynamic activation quantization). Dynamic weight-only 8da8w — weights INT8 offline,
135
- activations INT8 quantized per-token at runtime.
136
 
137
- ### Metrics
 
 
 
138
 
139
- | Metric | Description |
140
- |---|---|
141
- | WER | Word Error Rate (lower is better) |
142
- | CER | Character Error Rate (lower is better) |
143
 
144
- ### Accuracy results
145
 
146
- | Model | WER | CER |
 
 
 
 
147
  |---|---|---|
148
- | openai/whisper-small (FP32) | 3.45% | 1.33% |
149
- | whisper-small INT8 8da8w (ExecuTorch) | **3.41%** | **1.29%** |
 
 
 
 
150
 
151
- ### Efficiency results (Vivo X300, Arm C1)
152
 
153
- | Metric | FP32 Original | INT8 Optimized | Improvement |
154
- |---|---|---|---|
155
- | .pte file size | 1074.76 MB | 395.05 MB | **2.72x smaller** |
156
- | End-to-end latency p50 | 10927.0 ms | 7802.5 ms | **1.40x faster** |
157
- | End-to-end latency p90 | 11742.0 ms | 8027.0 ms | 1.46x faster |
158
- | RTFx | 0.641 | 0.897 | **+40%** |
159
- | Decode throughput | 3.62 tok/s | 5.69 tok/s | **+57%** |
160
- | Prefill throughput | 620.0 tok/s | 745.6 tok/s | +20% |
161
- | Time to first token (TTFT) | 2683.9 ms | 2196.2 ms | -18% |
162
- | Peak memory (USS) | 5226.97 MB | 4662.29 MB | **1.12x less** |
163
- | Model load time | 1327.3 ms | 1015.0 ms | 1.31x faster |
164
 
165
- Benchmark conditions: batch size 1, ~7 s audio clips, 50 runs (10 warmup), offline mode,
166
- 16 kHz input on Android 16 / OriginOS 6.
167
 
168
- ## Technical Specifications
169
 
170
- ### Objective
 
 
 
171
 
172
- English speech-to-text transcription using Whisper's encoder-decoder Transformer
173
- architecture. The encoder processes 80-bin log-mel spectrograms; the decoder
174
- autoregressively generates token IDs which are decoded to text with the Whisper tokenizer.
175
 
176
- ### Quantization
 
 
177
 
178
- - **Method:** TorchAO 8da8w 8-bit dynamic activation quantization + 8-bit weight quantization
179
- - **Calibration:** none required (dynamic activation quantization). Dynamic weight-only 8da8w — weights INT8 offline, activations INT8 quantized per-token at runtime.
180
- - **Weight granularity:** per-channel
181
- - **Symmetry:** symmetric INT8
182
- - **Skipped layers (kept FP32):** `proj_out`/`lm_head`, encoder + decoder positional embeddings, `encoder.conv1` / `encoder.conv2`
183
 
184
- ### Export pipeline
185
 
186
- 1. Load pretrained FP32 `openai/whisper-small` from HuggingFace
187
- 2. Export encoder and decoder to ExecuTorch Seq2Seq format via Optimum ExecuTorch
188
- 3. Apply 8da8w (8-bit dynamic activation, 8-bit weight) quantization with TorchAO
189
- 4. Export tokenizer files (`tokenizer.json`, `tokenizer_config.json`, `special_tokens_map.json`)
190
- 5. Export audio preprocessor to `whisper_preprocessor.pte`
 
191
 
192
- ### Input preprocessing
193
 
194
- | Step | Parameters |
195
  |---|---|
196
- | Load audio as waveform | 16 kHz mono |
197
- | Log-mel spectrogram | n_mels=80, hop_length=160, n_fft=400, sample_rate=16000, duration=30s |
198
- | Pad or trim | 3000 time frames |
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
199
 
200
- **Input tensor:** `[1, 80, 3000]`, dtype `float32` log-mel spectrogram (batch=1, mel bins, time frames)
 
201
 
202
- ### Output postprocessing
203
 
204
- 1. Autoregressive greedy decoding with the Whisper tokenizer
205
- 2. Skip special tokens
206
 
207
- ## Known Limitations
208
 
209
- - Evaluated on English speech (LibriSpeech test-clean); performance on other languages or
210
- accents has not been measured for this INT8 variant.
211
- - The `.pte` runtime on Python requires the ExecuTorch C++ seq2seq runner — not a simple
212
- `method.execute()` call. Use `example.py` (HuggingFace Transformers) for Python prototyping.
213
- - Maximum audio duration: 30 seconds per chunk (3000 mel time frames at 16 kHz).
214
- Longer audio must be chunked externally.
215
- - Android latency measured on Vivo X300 with Arm C1 processor (1x C1-Ultra, 3x C1-Premium,
216
- 4x C1-Pro cores at 4.21 / 3.5 / 2.7 GHz). Results may differ on other ARM devices.
217
- - RTFx > 1.0 indicates real-time capable transcription on this hardware; values below 1.0
218
- on lower-tier devices are expected.
 
1
  ---
2
+ license: apache-2.0
 
3
  pipeline_tag: automatic-speech-recognition
4
+ library_name: executorch
 
5
  tags:
 
 
 
 
 
6
  - arm
7
+ - arm-optimized
8
+ - premium-smartphone
9
  - executorch
10
+ base_model: openai/whisper-small
11
+ base_model_relation: quantized
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  ---
13
 
14
+ # Whisper Small optimized for Arm-based Premium Smartphone
15
 
16
+ Whisper Small, an encoder-decoder Transformer for automatic speech recognition, quantized to INT8 and exported to ExecuTorch for on-device inference on Arm-based Premium Smartphone devices.
 
 
 
17
 
18
+ ## Summary
19
 
20
+ This repository contains an Arm-optimized version of openai/whisper-small for automatic speech recognition. The model is provided in ExecuTorch (`.pte`) format, targeting Premium Smartphone systems.
21
 
22
+ This version is intended to demonstrate efficient inference on Arm-based platforms while preserving the original model's intended behavior. Arm has evaluated this model on LibriSpeech ASR and measured performance on Vivo X300.
 
 
23
 
24
+ **Key results**
25
 
26
+ | Area | Result |
27
  |---|---|
28
+ | Model format | ExecuTorch (`.pte`) |
29
+ | Target device class | Premium Smartphone |
30
+ | Reference device | Vivo X300 (C1-Ultra, C1-Premium, C1-Pro; Android 16 / OriginOS 6) |
31
+ | Primary performance result | 7802.5 ms p50 latency, RTFx 0.90 |
32
+ | Accuracy result | Normalised WER 3.41%, CER 1.29% |
33
+ | Size / memory result | 395.05 MB, 2.72 x smaller than the baseline (1074.76 MB) |
 
 
 
 
 
34
 
35
+ ## Original model
36
 
37
+ | Field | Value |
38
+ |---|---|
39
+ | Original model | openai/whisper-small |
40
+ | Original source | Hugging Face |
41
+ | Original developer | OpenAI |
42
+ | Original model card | [openai/whisper-small](https://huggingface.co/openai/whisper-small) |
43
+ | Original license | [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0) |
44
 
45
+ ## Model files
46
 
47
+ | File | Description |
48
+ |---|---|
49
+ | `whisper_small_vivo_executorch_optimized.pte` | Arm-optimized model for deployment |
50
+ | `whisper_preprocessor.pte` | ExecuTorch module that computes the log-mel spectrogram from raw audio; loaded by `example.py` when present, with a Python-side fallback otherwise |
51
+ | `example.py` | Minimal inference example |
52
+ | `pyproject.toml` | Pinned runtime dependencies for `example.py`, resolved with uv |
53
+ | `uv.lock` | Locked dependency resolution for `pyproject.toml` |
54
+ | `config.yaml` | Model I/O contract used by the example |
55
+ | `benchmarks/` | FP32 baseline and Arm-optimized benchmark records |
56
 
57
+ ## Performance
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
 
59
+ Performance was measured on the reference configuration below. Results are intended to make the optimization reproducible but do not guarantee identical performance on every Arm-based system.
 
 
 
 
60
 
61
+ **Reference configuration**
62
 
63
+ | Field | Value |
64
+ |---|---|
65
+ | Device / platform | Vivo X300 |
66
+ | CPU / accelerator | C1-Ultra, C1-Premium, C1-Pro (aarch64, 8 cores), CPU execution backend |
67
+ | OS | Android 16 / OriginOS 6 |
68
+ | Runtime | ExecuTorch 1.1.0 |
69
+ | Backend / delegate | XNNPACK, KleidiAI |
70
+ | Batch size | 1 |
71
+ | Precision | INT8 weights (per-channel symmetric) and INT8 dynamic activations (PTQ-dynamic, no calibration required) |
72
+ | Runs | 10 warmup, 50 measured |
73
+
74
+ **Performance results**
75
+
76
+ | Metric | Original / baseline | Arm-optimized | Improvement |
77
+ |---|---:|---:|---:|
78
+ | p50 latency | 10927.0 ms | 7802.5 ms | 1.40 x faster |
79
+ | p90 latency | 11742.0 ms | 8027.0 ms | 1.46 x faster |
80
+ | p99 latency | 11742.0 ms | 8027.0 ms | 1.46 x faster |
81
+ | Model size | 1074.76 MB | 395.05 MB | 2.72 x smaller |
82
+ | Peak memory | 5226.97 MB | 4662.29 MB | 1.12 x less |
83
+ | RTFx | 0.64 | 0.90 | 1.40 x higher |
84
+ | Model load time | 1327.0 ms | 1015.0 ms | 1.31 x faster |
85
+
86
+ ## Accuracy
87
+
88
+ Accuracy was evaluated using the same preprocessing, input resolution, and evaluation protocol described below. Where possible, the optimized model is compared against the original model under the same evaluation conditions.
89
+
90
+ **Evaluation setup**
91
+
92
+ | Field | Value |
93
+ |---|---|
94
+ | Dataset | LibriSpeech ASR (librispeech_asr) |
95
+ | Split | test-clean |
96
+ | Number of samples | 2620 |
97
+ | Metric(s) | Normalised WER (Whisper-style), CER |
98
+ | Evaluation runtime | ExecuTorch |
99
 
100
+ **Accuracy results**
 
 
101
 
102
+ | Metric | Original / baseline | Arm-optimized | Change |
103
+ |---|---:|---:|---:|
104
+ | Normalised WER | 3.45% | 3.41% | -0.04 pp |
105
+ | CER | 1.33% | 1.29% | -0.04 pp |
106
 
107
+ Accuracy was measured using the evaluation setup described above. Users should re-evaluate the model on their own data before production use.
 
 
 
108
 
109
+ ## Arm optimization approach
110
 
111
+ Arm optimized this model for efficient inference on Arm-based platforms using a hardware-aware conversion and validation flow.
112
+
113
+ For this release, Arm used:
114
+
115
+ | Optimization area | Applied? | Notes |
116
  |---|---|---|
117
+ | Model conversion | Yes | Converted to ExecuTorch `.pte` via an Optimum ExecuTorch seq2seq export |
118
+ | Quantization | Yes | PTQ-dynamic INT8: 8-bit weights (per-channel symmetric), 8-bit dynamic activations; no calibration required |
119
+ | Runtime/backend selection | Yes | XNNPACK and KleidiAI optimisations |
120
+ | Graph/runtime compatibility updates | Yes | Performed as part of the ExecuTorch export pipeline |
121
+ | Accuracy validation | Yes | Compared against the original model or published baseline |
122
+ | Performance validation | Yes | Measured on the reference Arm platform |
123
 
124
+ The goal of this process is to improve deployment characteristics such as latency, memory use, model size, and runtime compatibility while preserving the model's intended behavior. Detailed conversion scripts, calibration configuration, or backend-specific implementation details may be provided separately where appropriate.
125
 
126
+ ## Using this model
 
 
 
 
 
 
 
 
 
 
127
 
128
+ ### Install dependencies
 
129
 
130
+ Dependencies are declared in `pyproject.toml`, which ships with this repository. Resolve and install them into a local virtual environment with uv:
131
 
132
+ ```bash
133
+ uv python install
134
+ uv sync --frozen
135
+ ```
136
 
137
+ ### Run the example
 
 
138
 
139
+ ```bash
140
+ uv run example.py
141
+ ```
142
 
143
+ Note: The Python/uv example runs on AWS Graviton (Ubuntu arm64) to confirm runtime compatibility only, and is intended as a guideline for building an equivalent run script on smartphone devices.
 
 
 
 
144
 
145
+ ### Expected input
146
 
147
+ | Property | Value |
148
+ |---|---|
149
+ | Input shape | [1, 80, 3000] |
150
+ | Input type | float32 |
151
+ | Input range | N/A (log-mel spectrogram magnitude, not a fixed bounded range) |
152
+ | Preprocessing | Load audio as a 16 kHz mono waveform; compute a log-mel spectrogram (mel bins 80, hop length 160, n_fft 400, sample rate 16000, duration 30 seconds); pad or trim to 3000 time frames |
153
 
154
+ ### Expected output
155
 
156
+ | Property | Value |
157
  |---|---|
158
+ | Output shape | N/A (variable-length token ID sequence, autoregressive generation) |
159
+ | Output type | Token ID sequence |
160
+ | Postprocessing | Greedy decoding with a fixed token-suppression list and a repetition-guard heuristic that trims repeated trailing token patterns; decode with the Whisper tokenizer, skipping special tokens |
161
+
162
+ ## Intended use
163
+
164
+ This model is intended for developers evaluating automatic speech recognition workloads on Arm-based platforms. It is suitable as a reference implementation for benchmarking, prototyping, and integration exploration.
165
+
166
+ ## Limitations
167
+
168
+ - Performance depends on the target device, runtime version, backend/delegate support, memory configuration, and system load.
169
+ - Accuracy was evaluated on LibriSpeech ASR and may not generalize to all domains.
170
+ - This release preserves the original model's intended task and behavior, but users should validate it for their own application, data, and deployment environment.
171
+ - This repository is not a replacement for the original model documentation.
172
+
173
+ ## Additional notes
174
+
175
+ Quantization keeps a small set of layers in FP32 to preserve accuracy: proj_out/lm_head, the encoder and decoder positional embeddings, and encoder.conv1/encoder.conv2. Audio inputs are limited to 30 seconds (3000 mel time frames) per chunk; longer audio must be chunked externally before inference.
176
+
177
+ `example.py` forces English transcription by hardcoding the decoder prefix to `<|en|>, <|transcribe|>, <|notimestamps|>`. This is an example-level default, not a model restriction: the bundled tokenizer and decoder support the full multilingual Whisper vocabulary (98 language tokens) and the `<|translate|>` task, so other languages or the translate task can be enabled by changing the forced-prefix token IDs in `example.py`, with no re-export required.
178
+
179
+ ## About this version
180
 
181
+ This repository contains a converted version of the openai/whisper-small model, originally developed by OpenAI.
182
+ Arm has converted the model to enable efficient execution on Arm-based platforms. No changes have been made to the model's intended behavior.
183
 
184
+ ## Original model and documentation
185
 
186
+ For full details of the original model, please refer to the original [model card](https://huggingface.co/openai/whisper-small).
 
187
 
188
+ ## Purpose of this release
189
 
190
+ This version is provided by Arm as a reference implementation to demonstrate performance on Arm-based systems. It is not a production-ready or supported solution. Users should evaluate the model independently for their use-case. Arm provides no warranties or ongoing support for this version.
 
 
 
 
 
 
 
 
 
example.py CHANGED
@@ -1,128 +1,385 @@
1
- """Whisper Small ASR inference example using HuggingFace Transformers.
2
 
3
- The optimized.pte and original.pte artifacts in the sibling pte_optimized/ and
4
- pte_original/ directories are ExecuTorch-optimized models (8da8w INT8 dynamic
5
- quantization) intended for on-device ARM inference (Android / Graviton).
6
- Running those artifacts directly requires the ExecuTorch C++ runtime and a
7
- specialized seq2seq runner — they are not suitable for a simple Python
8
- ``method.execute()`` call.
9
 
10
- This script demonstrates equivalent inference using the HuggingFace Transformers
11
- library, which is the recommended path for Python-based evaluation and prototyping.
12
 
13
  Requirements:
14
- pip install transformers torch soundfile numpy
15
  """
16
 
 
17
  import json
 
18
  from pathlib import Path
19
 
 
20
  import torch
21
- import torch.nn.functional as F
22
- from transformers import WhisperForConditionalGeneration, WhisperProcessor
23
 
24
- # ── Configuration ──────────────────────────────────────────────────────────────
25
  AUDIO_PATH = "sample_input.flac"
26
- MODEL_NAME = "openai/whisper-small"
27
- LANGUAGE = "en"
28
- TASK = "transcribe"
29
- MAX_NEW_TOKENS = 128
30
- SAMPLE_RATE = 16000
31
-
32
-
33
- # ── Audio Loading ──────────────────────────────────────────────────────────────
34
- def load_audio(audio_path: str) -> tuple[torch.Tensor, int]:
35
- """Load audio file and return (waveform_1d_float32, sample_rate)."""
36
- try:
37
- import soundfile as sf
38
-
39
- audio_np, sr = sf.read(audio_path, dtype="float32")
40
- if audio_np.ndim == 2:
41
- audio_np = audio_np.mean(axis=1)
42
- import numpy as np
43
-
44
- return torch.from_numpy(audio_np.astype(np.float32)), int(sr)
45
- except ImportError:
46
- import torchaudio
47
-
48
- waveform, sr = torchaudio.load(audio_path)
49
- if waveform.shape[0] > 1:
50
- waveform = waveform.mean(dim=0)
51
- else:
52
- waveform = waveform.squeeze(0)
53
- return waveform.float(), int(sr)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
 
 
 
 
 
 
55
 
56
- # ── Resampling ──────────────────────────────────────��──────────────────────────
57
- def resample_to_16k(waveform: torch.Tensor, sample_rate: int) -> torch.Tensor:
58
- """Resample waveform to 16 kHz using linear interpolation."""
59
- if sample_rate == SAMPLE_RATE:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  return waveform
61
- new_len = int(round(len(waveform) * SAMPLE_RATE / sample_rate))
62
- return F.interpolate(
63
- waveform.view(1, 1, -1), size=new_len, mode="linear", align_corners=False
64
- ).view(-1)
65
-
66
-
67
- # ── Preprocessing ──────────────────────────────────────────────────────────────
68
- def preprocess(audio_path: str, processor: WhisperProcessor) -> torch.Tensor:
69
- """Load audio and extract 80-bin log-mel spectrogram features [1, 80, 3000]."""
70
- waveform, sr = load_audio(audio_path)
71
- waveform_16k = resample_to_16k(waveform, sr)
72
- features = processor.feature_extractor(
73
- waveform_16k.numpy(), sampling_rate=SAMPLE_RATE, return_tensors="pt"
74
- ).input_features
75
- return features # [1, 80, 3000]
76
-
77
-
78
- # ── Inference ──────────────────────────────────────────────────────────────────
79
- def transcribe(
80
- audio_path: str,
81
- model: WhisperForConditionalGeneration,
82
- processor: WhisperProcessor,
83
- ) -> str:
84
- """Run Whisper inference and return transcribed text."""
85
- features = preprocess(audio_path, processor)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
  with torch.no_grad():
87
- output_ids = model.generate(
88
- features,
89
- language=LANGUAGE,
90
- task=TASK,
91
- max_new_tokens=MAX_NEW_TOKENS,
92
- )
93
- return processor.tokenizer.batch_decode(output_ids, skip_special_tokens=True)[0].strip()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
 
 
 
 
 
 
 
95
 
96
- # ── Save Results ───────────────────────────────────────────────────────────────
97
- def save_results(audio_path: str, text: str) -> None:
98
- """Save transcription result to JSON in the same directory as this script."""
99
- out_dir = Path(__file__).parent
100
- result = {
101
- "audio_file": str(Path(audio_path).name),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  "transcription": text,
103
- "model": MODEL_NAME,
104
- "language": LANGUAGE,
105
- "task": TASK,
106
  }
107
- out_path = out_dir / "transcription.json"
108
- with open(out_path, "w") as f:
109
- json.dump(result, f, indent=2)
110
- print(f"Transcription saved to: {out_path}")
111
 
112
 
113
- # ── Main ───────────────────────────────────────────────────────────────────────
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  def main() -> None:
115
- print(f"Loading model: {MODEL_NAME}")
116
- processor = WhisperProcessor.from_pretrained(MODEL_NAME)
117
- model = WhisperForConditionalGeneration.from_pretrained(MODEL_NAME)
118
- model.eval()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
 
120
- audio_path = str(Path(__file__).parent / AUDIO_PATH)
121
- print(f"Transcribing: {audio_path}")
122
- text = transcribe(audio_path, model, processor)
 
123
 
124
- print(f"\nTranscription: {text}")
125
- save_results(audio_path, text)
126
 
127
 
128
  if __name__ == "__main__":
 
1
+ """Minimal inference example for Whisper Small INT8 using ExecuTorch.
2
 
3
+ Loads a quantized .pte model and transcribes a single audio file.
4
+ The INT8 model was exported via Optimum-ExecuTorch with 8da8w quantization on
5
+ all Linear layers plus a manual weight-only INT8 pass on `decoder.embed_tokens`,
6
+ and uses separate 'encoder' and 'text_decoder' ExecuTorch methods with a
7
+ static KV cache.
 
8
 
9
+ This example resolves the tokenizer and preprocessor artifacts from the same
10
+ directory as the model, matching the benchmark flow used by the Whisper runner.
11
 
12
  Requirements:
13
+ pip install executorch torch transformers soundfile numpy
14
  """
15
 
16
+ import argparse
17
  import json
18
+ import time
19
  from pathlib import Path
20
 
21
+ import numpy as np
22
  import torch
23
+ from executorch.runtime import Runtime
24
+ from transformers import AutoTokenizer
25
 
26
+ # -- Configuration -------------------------------------------------------------
27
  AUDIO_PATH = "sample_input.flac"
28
+ PREPROCESSOR_FILENAME = "whisper_preprocessor.pte"
29
+ DEFAULT_LOCAL_MODEL_DIR = "pte_optimized"
30
+ MODEL_FILENAME = "whisper_small_vivo_executorch_optimized.pte"
31
+
32
+ DECODER_START_TOKEN_ID = 50258
33
+ FORCED_PREFIX_IDS = [50259, 50359, 50363] # <|en|>, <|transcribe|>, <|notimestamps|>
34
+ EOS_TOKEN_ID = 50257
35
+
36
+ MAX_GENERATION_TOKENS = 128
37
+ MAX_SECONDS_PER_SAMPLE = 120.0
38
+ REPETITION_GUARD_REPEATS = 3
39
+ REPETITION_GUARD_MIN_PATTERN_LEN = 2
40
+ REPETITION_GUARD_MAX_PATTERN_LEN = 16
41
+
42
+ SUPPRESS_TOKENS = (
43
+ 1, 2, 7, 8, 9, 10, 14, 25, 26, 27, 28, 29, 31, 58, 59, 60, 61, 62, 63,
44
+ 90, 91, 92, 93, 357, 366, 438, 532, 685, 705, 796, 930, 1058, 1220, 1267,
45
+ 1279, 1303, 1343, 1377, 1391, 1635, 1782, 1875, 2162, 2361, 2488, 3467,
46
+ 4008, 4211, 4600, 4808, 5299, 5855, 6329, 7203, 9609, 9959, 10563, 10786,
47
+ 11420, 11709, 11907, 13163, 13697, 13700, 14808, 15306, 16410, 16791,
48
+ 17992, 19203, 19510, 20724, 22305, 22935, 27007, 30109, 30420, 33409,
49
+ 34949, 40283, 40493, 40549, 47282, 49146, 50359, 50360, 50361,
50
+ )
51
+ BEGIN_SUPPRESS_TOKENS = (220, 50257)
52
+
53
+
54
+ def parse_args() -> argparse.Namespace:
55
+ parser = argparse.ArgumentParser(
56
+ description="Run Whisper Small ExecuTorch inference from an exported model bundle."
57
+ )
58
+ parser.add_argument(
59
+ "--model-dir",
60
+ default=None,
61
+ help=(
62
+ "Directory containing the ExecuTorch model, tokenizer files, and optionally "
63
+ "whisper_preprocessor.pte. Defaults to the local huggingface bundle."
64
+ ),
65
+ )
66
+ parser.add_argument(
67
+ "--audio",
68
+ default=AUDIO_PATH,
69
+ help="Path to the input audio file (.flac/.wav).",
70
+ )
71
+ return parser.parse_args()
72
+
73
 
74
+ def resolve_model_dir(script_dir: Path, requested_dir: str | None) -> Path:
75
+ candidates: list[Path] = []
76
+ if requested_dir:
77
+ candidates.append(Path(requested_dir))
78
+ candidates.append(script_dir / DEFAULT_LOCAL_MODEL_DIR)
79
 
80
+ for candidate in candidates:
81
+ bundle_dir = candidate.resolve()
82
+ if (bundle_dir / MODEL_FILENAME).exists():
83
+ return bundle_dir
84
+
85
+ searched = "\n".join(f"- {candidate.resolve()}" for candidate in candidates)
86
+ raise FileNotFoundError(
87
+ "Could not find a Whisper Small ExecuTorch model bundle. Searched:\n"
88
+ f"{searched}"
89
+ )
90
+
91
+
92
+ def load_audio(audio_path: str) -> tuple[np.ndarray, int]:
93
+ import soundfile as sf
94
+
95
+ waveform, sample_rate = sf.read(str(audio_path), dtype="float32")
96
+ if waveform.ndim == 2:
97
+ waveform = waveform.mean(axis=1)
98
+ return waveform, int(sample_rate)
99
+
100
+
101
+ def resample_to_16k(waveform: np.ndarray, sample_rate: int) -> np.ndarray:
102
+ if sample_rate == 16000:
103
  return waveform
104
+ target_len = int(round(len(waveform) * 16000 / sample_rate))
105
+ resampled = np.interp(
106
+ np.linspace(0, len(waveform) - 1, target_len),
107
+ np.arange(len(waveform)),
108
+ waveform,
109
+ )
110
+ return resampled.astype(np.float32)
111
+
112
+
113
+ def load_preprocessor(preprocessor_path: Path):
114
+ if not preprocessor_path.exists():
115
+ return None, None
116
+
117
+ runtime = Runtime.get()
118
+ program = runtime.load_program(str(preprocessor_path))
119
+ method_names = sorted(program.method_names)
120
+ method_name = "forward" if "forward" in method_names else method_names[0]
121
+ return program, program.load_method(method_name)
122
+
123
+
124
+ def preprocess(audio_path: str, preprocessor_method) -> torch.Tensor:
125
+ waveform, sample_rate = load_audio(audio_path)
126
+ waveform_16k = resample_to_16k(waveform, sample_rate)
127
+ waveform_tensor = torch.from_numpy(waveform_16k).float().contiguous()
128
+
129
+ if preprocessor_method is not None:
130
+ outputs = preprocessor_method.execute([waveform_tensor])
131
+ features = outputs[0]
132
+ if isinstance(features, (list, tuple)):
133
+ features = features[0]
134
+ return torch.as_tensor(features).float().contiguous()
135
+
136
+ from executorch.extension.audio.mel_spectrogram import WhisperAudioProcessor
137
+
138
+ fallback_preprocessor = WhisperAudioProcessor(
139
+ feature_size=80,
140
+ max_audio_len=300,
141
+ stack_output=True,
142
+ )
143
  with torch.no_grad():
144
+ features = fallback_preprocessor(waveform_tensor)
145
+ return features.float().contiguous()
146
+
147
+
148
+ def load_model(pte_path: str) -> tuple:
149
+ runtime = Runtime.get()
150
+ program = runtime.load_program(pte_path)
151
+ available = sorted(program.method_names)
152
+ print(f" Available methods: {available}")
153
+
154
+ if "encoder" in available and "text_decoder" in available:
155
+ return program, {
156
+ "format": "seq2seq",
157
+ "encoder": program.load_method("encoder"),
158
+ "decoder": program.load_method("text_decoder"),
159
+ }
160
+ if "forward" in available:
161
+ return program, {
162
+ "format": "forward",
163
+ "forward": program.load_method("forward"),
164
+ }
165
+ raise RuntimeError(f"Unknown export format. Methods found: {available}")
166
+
167
+
168
+ def apply_suppression(scores: torch.Tensor, first_free_step: bool) -> torch.Tensor:
169
+ vocab_size = scores.shape[-1]
170
+ out = scores.clone()
171
+ valid_suppress = [
172
+ t for t in SUPPRESS_TOKENS
173
+ if 0 <= t < vocab_size and t != EOS_TOKEN_ID
174
+ ]
175
+ if valid_suppress:
176
+ out[0, valid_suppress] = float("-inf")
177
+ if first_free_step:
178
+ valid_begin = [t for t in BEGIN_SUPPRESS_TOKENS if 0 <= t < vocab_size]
179
+ if valid_begin:
180
+ out[0, valid_begin] = float("-inf")
181
+ return out
182
+
183
 
184
+ def decode_tokens(tokenizer, token_ids: list[int]) -> str:
185
+ return tokenizer.decode(
186
+ token_ids,
187
+ skip_special_tokens=True,
188
+ clean_up_tokenization_spaces=False,
189
+ ).strip()
190
 
191
+
192
+ def find_repeated_suffix_pattern(
193
+ token_ids: list[int],
194
+ *,
195
+ repeats: int = REPETITION_GUARD_REPEATS,
196
+ min_pattern_len: int = REPETITION_GUARD_MIN_PATTERN_LEN,
197
+ max_pattern_len: int = REPETITION_GUARD_MAX_PATTERN_LEN,
198
+ ) -> int | None:
199
+ total = len(token_ids)
200
+ upper = min(max_pattern_len, total // repeats)
201
+ for pattern_len in range(min_pattern_len, upper + 1):
202
+ pattern = token_ids[-pattern_len:]
203
+ if all(
204
+ token_ids[-pattern_len * (idx + 1) : -pattern_len * idx or None] == pattern
205
+ for idx in range(repeats)
206
+ ):
207
+ return pattern_len
208
+ return None
209
+
210
+
211
+ def transcribe_seq2seq(
212
+ encoder_method,
213
+ decoder_method,
214
+ features: torch.Tensor,
215
+ tokenizer,
216
+ ) -> dict:
217
+ encoder_outputs = encoder_method.execute([features])
218
+ encoder_hidden = encoder_outputs[0]
219
+ if isinstance(encoder_hidden, (list, tuple)):
220
+ encoder_hidden = encoder_hidden[0]
221
+ encoder_hidden = torch.as_tensor(encoder_hidden).float().contiguous()
222
+
223
+ forced_prefix = list(FORCED_PREFIX_IDS)
224
+ tokens = [DECODER_START_TOKEN_ID]
225
+ cache_position = 0
226
+ forced_prefix_idx = 0
227
+ generated_token_count = 0
228
+ stop_reason = "max_tokens"
229
+ started = time.perf_counter()
230
+ generated_free_tokens: list[int] = []
231
+
232
+ for _step in range(MAX_GENERATION_TOKENS + len(forced_prefix)):
233
+ input_tensor = torch.tensor([[tokens[-1]]], dtype=torch.long).contiguous()
234
+ pos_tensor = torch.tensor([cache_position], dtype=torch.long).contiguous()
235
+
236
+ decoder_outputs = decoder_method.execute([input_tensor, encoder_hidden, pos_tensor])
237
+ flat_logits = decoder_outputs[0]
238
+ if isinstance(flat_logits, (list, tuple)):
239
+ flat_logits = flat_logits[0]
240
+ flat_logits = torch.as_tensor(flat_logits).float().flatten()
241
+
242
+ if forced_prefix_idx < len(forced_prefix):
243
+ next_token = forced_prefix[forced_prefix_idx]
244
+ forced_prefix_idx += 1
245
+ else:
246
+ scores = flat_logits.unsqueeze(0)
247
+ first_free = generated_token_count == 0
248
+ scores = apply_suppression(scores, first_free_step=first_free)
249
+ next_token = int(scores[0].argmax().item())
250
+ generated_token_count += 1
251
+ generated_free_tokens.append(next_token)
252
+
253
+ if next_token == EOS_TOKEN_ID:
254
+ stop_reason = "eos"
255
+ tokens.append(next_token)
256
+ cache_position += 1
257
+ break
258
+ repeated_suffix_len = find_repeated_suffix_pattern(generated_free_tokens)
259
+ if repeated_suffix_len is not None:
260
+ trim_count = repeated_suffix_len * REPETITION_GUARD_REPEATS
261
+ del generated_free_tokens[-trim_count:]
262
+ del tokens[-(trim_count - 1) :]
263
+ generated_token_count -= trim_count
264
+ stop_reason = "repetition_guard"
265
+ break
266
+ if time.perf_counter() - started >= MAX_SECONDS_PER_SAMPLE:
267
+ stop_reason = "timeout"
268
+ break
269
+
270
+ tokens.append(next_token)
271
+ cache_position += 1
272
+
273
+ elapsed = time.perf_counter() - started
274
+ text = decode_tokens(tokenizer, tokens)
275
+ return {
276
  "transcription": text,
277
+ "generated_tokens": generated_token_count,
278
+ "stop_reason": stop_reason,
279
+ "elapsed_s": round(elapsed, 3),
280
  }
 
 
 
 
281
 
282
 
283
+ def transcribe_forward(forward_method, features: torch.Tensor, tokenizer) -> dict:
284
+ prompt = [DECODER_START_TOKEN_ID] + list(FORCED_PREFIX_IDS)
285
+ decoder_ids = torch.tensor([prompt], dtype=torch.long).contiguous()
286
+ generated_token_count = 0
287
+ stop_reason = "max_tokens"
288
+ started = time.perf_counter()
289
+ generated_free_tokens: list[int] = []
290
+
291
+ with torch.no_grad():
292
+ for _step in range(MAX_GENERATION_TOKENS):
293
+ outputs = forward_method.execute([features, decoder_ids])
294
+ logits = outputs[0]
295
+ if isinstance(logits, (list, tuple)):
296
+ logits = logits[0]
297
+ logits = torch.as_tensor(logits).float()
298
+ next_token_scores = logits[:, -1, :]
299
+ first_free = generated_token_count == 0
300
+ next_token_scores = apply_suppression(next_token_scores, first_free_step=first_free)
301
+ next_token = next_token_scores.argmax(dim=-1, keepdim=True).long()
302
+ decoder_ids = torch.cat([decoder_ids, next_token], dim=1)
303
+ generated_token_count += 1
304
+ generated_free_tokens.append(int(next_token.item()))
305
+
306
+ if EOS_TOKEN_ID >= 0 and bool(torch.all(next_token == EOS_TOKEN_ID)):
307
+ stop_reason = "eos"
308
+ break
309
+ repeated_suffix_len = find_repeated_suffix_pattern(generated_free_tokens)
310
+ if repeated_suffix_len is not None:
311
+ trim_count = repeated_suffix_len * REPETITION_GUARD_REPEATS
312
+ generated_free_tokens = generated_free_tokens[:-trim_count]
313
+ decoder_ids = decoder_ids[:, :-trim_count]
314
+ generated_token_count -= trim_count
315
+ stop_reason = "repetition_guard"
316
+ break
317
+ if time.perf_counter() - started >= MAX_SECONDS_PER_SAMPLE:
318
+ stop_reason = "timeout"
319
+ break
320
+
321
+ elapsed = time.perf_counter() - started
322
+ text = decode_tokens(tokenizer, decoder_ids[0].tolist())
323
+ return {
324
+ "transcription": text,
325
+ "generated_tokens": generated_token_count,
326
+ "stop_reason": stop_reason,
327
+ "elapsed_s": round(elapsed, 3),
328
+ }
329
+
330
+
331
+ def save_results(result: dict, script_dir: Path) -> None:
332
+ output_path = script_dir / "transcription.json"
333
+ with open(output_path, "w", encoding="utf-8") as f:
334
+ json.dump(result, f, indent=2, ensure_ascii=False)
335
+ print(f"Saved transcription to {output_path}")
336
+
337
+
338
  def main() -> None:
339
+ args = parse_args()
340
+ script_dir = Path(__file__).parent
341
+ model_dir = resolve_model_dir(script_dir, args.model_dir)
342
+ model_path = model_dir / MODEL_FILENAME
343
+ audio_arg = Path(args.audio)
344
+ audio_path = audio_arg if audio_arg.is_absolute() else (script_dir / audio_arg).resolve()
345
+ preprocessor_path = model_dir / PREPROCESSOR_FILENAME
346
+
347
+ print(f"Loading tokenizer from {model_dir} ...")
348
+ tokenizer = AutoTokenizer.from_pretrained(
349
+ str(model_dir),
350
+ local_files_only=True,
351
+ use_fast=True,
352
+ )
353
+
354
+ _preprocessor_program = None
355
+ preprocessor_method = None
356
+ if preprocessor_path.exists():
357
+ print(f"Loading preprocessor from {preprocessor_path} ...")
358
+ _preprocessor_program, preprocessor_method = load_preprocessor(preprocessor_path)
359
+ else:
360
+ print("Local preprocessor .pte not found; falling back to WhisperAudioProcessor.")
361
+
362
+ print(f"Loading model from {model_path} ...")
363
+ program, methods = load_model(str(model_path))
364
+
365
+ print(f"Preprocessing audio: {audio_path}")
366
+ features = preprocess(str(audio_path), preprocessor_method)
367
+ print(f" Input features shape: {tuple(features.shape)}")
368
+
369
+ print("Running transcription ...")
370
+ if methods["format"] == "seq2seq":
371
+ result = transcribe_seq2seq(
372
+ methods["encoder"], methods["decoder"], features, tokenizer
373
+ )
374
+ else:
375
+ result = transcribe_forward(methods["forward"], features, tokenizer)
376
 
377
+ print(f"\nTranscription: {result['transcription']!r}")
378
+ print(f"Generated tokens: {result['generated_tokens']}")
379
+ print(f"Stop reason: {result['stop_reason']}")
380
+ print(f"Elapsed: {result['elapsed_s']:.3f} s")
381
 
382
+ save_results(result, script_dir)
 
383
 
384
 
385
  if __name__ == "__main__":
metadata.yaml CHANGED
@@ -8,8 +8,10 @@ description: >-
8
  INT8 linear layers with selective FP32 components to reduce size and improve inference efficiency
9
  while preserving transcription quality.
10
  id: Arm/whisper-small-int8-xnnpack-executorch
11
- filename: whisper-small-int8-executorch.pte
12
  base_model_id: openai/whisper-small
 
 
13
  profile: Arm-Optimized
14
  weight_dtype: int8
15
  quantization:
 
8
  INT8 linear layers with selective FP32 components to reduce size and improve inference efficiency
9
  while preserving transcription quality.
10
  id: Arm/whisper-small-int8-xnnpack-executorch
11
+ filename: whisper_small_vivo_executorch_optimized.pte
12
  base_model_id: openai/whisper-small
13
+ vendor: OpenAI
14
+ base_model_url: https://huggingface.co/openai/whisper-small
15
  profile: Arm-Optimized
16
  weight_dtype: int8
17
  quantization:
pyproject.toml ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [project]
2
+ name = "whisper-small-int8-xnnpack-executorch-runtime"
3
+ version = "0.1.0"
4
+ description = "Runtime dependencies for example.py (Whisper Small INT8, ExecuTorch + XNNPACK)"
5
+ requires-python = ">=3.12,<3.13"
6
+ dependencies = [
7
+ "executorch==1.1.0",
8
+ "torch==2.10.0",
9
+ "transformers==4.57.1",
10
+ "soundfile==0.13.1",
11
+ "numpy==2.5.2",
12
+ ]
13
+
14
+ [tool.uv]
15
+ package = false
16
+ # The example runs on Arm-based Linux; ExecuTorch and its Vivo X300 export target
17
+ # aarch64. Restricting the resolution environment keeps the lock to the wheels
18
+ # that platform actually installs.
19
+ environments = ["sys_platform == 'linux' and platform_machine == 'aarch64'"]
20
+ # coremltools targets Apple Core ML, which this XNNPACK-on-Arm-Linux example
21
+ # never uses. Nothing in example.py imports it.
22
+ exclude-dependencies = [
23
+ { package = { name = "executorch", version = "1.1.0" }, dependencies = ["coremltools"] },
24
+ ]
25
+
26
+ [tool.ai-portal.deployment]
27
+ schema-version = "1"
28
+ runtime = "executorch"
29
+ required-capabilities = ["XnnpackBackend"]
30
+
31
+ [tool.ai-portal.deployment.ubuntu]
32
+ packages = []
33
+
34
+ [tool.ai-portal.deployment.raspbian]
35
+ packages = []
36
+
37
+ [tool.ai-portal.deployment.files]
38
+ expected = ["transcription.json"]
transcription.json CHANGED
@@ -1,6 +1,6 @@
1
  {
2
- "transcription": "I thank all who have loved me in their hearts, with thanks and love from mine.",
3
- "generated_tokens": 19,
4
  "stop_reason": "eos",
5
- "elapsed_s": 1.114
6
  }
 
1
  {
2
+ "transcription": "Everything around appeared solitary, and would have been silent but for the continued plashing of the fountain, and the whole scene still maintained the monastic illusion which the fancy of Waverly had conjured up.",
3
+ "generated_tokens": 43,
4
  "stop_reason": "eos",
5
+ "elapsed_s": 2.891
6
  }
uv.lock ADDED
@@ -0,0 +1,724 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ version = 1
2
+ revision = 3
3
+ requires-python = "==3.12.*"
4
+ resolution-markers = [
5
+ "platform_machine == 'aarch64' and sys_platform == 'linux'",
6
+ ]
7
+ supported-markers = [
8
+ "platform_machine == 'aarch64' and sys_platform == 'linux'",
9
+ ]
10
+
11
+ [manifest]
12
+ excludes = [{ package = { name = "executorch", version = "1.1.0" }, dependencies = ["coremltools"] }]
13
+
14
+ [[package]]
15
+ name = "antlr4-python3-runtime"
16
+ version = "4.9.3"
17
+ source = { registry = "https://pypi.org/simple" }
18
+ sdist = { url = "https://files.pythonhosted.org/packages/3e/38/7859ff46355f76f8d19459005ca000b6e7012f2f1ca597746cbcd1fbfe5e/antlr4-python3-runtime-4.9.3.tar.gz", hash = "sha256:f224469b4168294902bb1efa80a8bf7855f24c99aef99cbefc1bcd3cce77881b", size = 117034, upload-time = "2021-11-06T17:52:23.524Z" }
19
+
20
+ [[package]]
21
+ name = "certifi"
22
+ version = "2026.7.22"
23
+ source = { registry = "https://pypi.org/simple" }
24
+ sdist = { url = "https://files.pythonhosted.org/packages/a3/c2/24167ea9858356b47a87a50d39908bfdb72ceeefe0041586e704e5376b3a/certifi-2026.7.22.tar.gz", hash = "sha256:741e2c3b351ddf169a738da9f2c048608ff7f2c5cc02f1ebc6b118bb090d5d55", size = 138112, upload-time = "2026-07-22T03:35:12.644Z" }
25
+ wheels = [
26
+ { url = "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl", hash = "sha256:62f22742b58a1a33014a2b6b706588a8d7e2a88ae7bd1a6ebe8c992928483775", size = 136983, upload-time = "2026-07-22T03:35:11.276Z" },
27
+ ]
28
+
29
+ [[package]]
30
+ name = "cffi"
31
+ version = "2.1.1"
32
+ source = { registry = "https://pypi.org/simple" }
33
+ dependencies = [
34
+ { name = "pycparser", marker = "implementation_name != 'PyPy'" },
35
+ ]
36
+ sdist = { url = "https://files.pythonhosted.org/packages/9e/ef/008a1939e372c06329a3fce4279c02f328488f3526744906eeec3da7ad5f/cffi-2.1.1.tar.gz", hash = "sha256:dd31f52ea1086513bb9df30f8fcee9b8918323ae067a3d5b78bc826a000712be", size = 530807, upload-time = "2026-08-03T21:21:18.939Z" }
37
+ wheels = [
38
+ { url = "https://files.pythonhosted.org/packages/44/de/f98430906df1545ffde0d543dd124a7a439bc2cd32b36b9c53f805df7333/cffi-2.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:68e62fe11f30d5ca8289242866f0a5291402d8529ca2178ab8afc5c9694ae890", size = 222389, upload-time = "2026-08-03T21:19:48.331Z" },
39
+ { url = "https://files.pythonhosted.org/packages/a0/d2/6cd24ae3be000a634109c247d1475d62e5616d0dc78c82770942ec384248/cffi-2.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:208f941bb9d18e768138677f0a6d2ce01f590df56043dda1df1535ac57c88517", size = 225232, upload-time = "2026-08-03T21:19:53.109Z" },
40
+ ]
41
+
42
+ [[package]]
43
+ name = "charset-normalizer"
44
+ version = "3.5.1"
45
+ source = { registry = "https://pypi.org/simple" }
46
+ sdist = { url = "https://files.pythonhosted.org/packages/e5/3f/143b048436775b0f76ac3eec145c019e8173ccc2885c8f20319b996d5e83/charset_normalizer-3.5.1.tar.gz", hash = "sha256:6117b84ea48435e5356dc737f5121485c30920ba43375fa7b434fd753df0eac3", size = 171764, upload-time = "2026-08-15T08:20:44.807Z" }
47
+ wheels = [
48
+ { url = "https://files.pythonhosted.org/packages/9a/4c/be49ada26b1f0232d57aa89bbebf997a5cc2332a5616b6eca26ff680044d/charset_normalizer-3.5.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4582c27e8c889d64811987b5967fbd3ae0c823fe1fd933b543d55ac20bb475fa", size = 238530, upload-time = "2026-08-15T08:17:11.563Z" },
49
+ { url = "https://files.pythonhosted.org/packages/f6/0b/c5292a2462d69b7378ea89793bbb5b2b6fcf6f7dd6d1667f9619094ad553/charset_normalizer-3.5.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:96fef3e886d6a9874b14f27fc193fbdc69d5d8035783d86aa4e1cea594e695f9", size = 240110, upload-time = "2026-08-15T08:17:20.547Z" },
50
+ { url = "https://files.pythonhosted.org/packages/d7/c7/9e48cee5c161fe24da823b61bf381921d77cb994a0a4de148e95018c1984/charset_normalizer-3.5.1-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cee5dd7c6fb5dd52a0fe2a740f9bc6e3593f5f8b1788bde49de02086f30182b2", size = 240930, upload-time = "2026-08-15T08:19:54.163Z" },
51
+ { url = "https://files.pythonhosted.org/packages/75/9c/019fbb9f4834491a160951349b1a3714439376f66e5f7cf18b4f18f0c7aa/charset_normalizer-3.5.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:a2028475ba855475b8b4d3cfeb4994269c967aea8b9892dfba907f4263a863a3", size = 241821, upload-time = "2026-08-15T08:20:02.321Z" },
52
+ { url = "https://files.pythonhosted.org/packages/cc/61/d01fc49b8dea277640b55a9e15960dbca9fdc8c9fde18e572d39c59f4019/charset_normalizer-3.5.1-py3-none-any.whl", hash = "sha256:6df0ec430f9a831772c23ca5a224cba36517a58a84bb32c32bb59a9fa67c47f6", size = 68658, upload-time = "2026-08-15T08:20:43.306Z" },
53
+ ]
54
+
55
+ [[package]]
56
+ name = "execnet"
57
+ version = "2.1.2"
58
+ source = { registry = "https://pypi.org/simple" }
59
+ sdist = { url = "https://files.pythonhosted.org/packages/bf/89/780e11f9588d9e7128a3f87788354c7946a9cbb1401ad38a48c4db9a4f07/execnet-2.1.2.tar.gz", hash = "sha256:63d83bfdd9a23e35b9c6a3261412324f964c2ec8dcd8d3c6916ee9373e0befcd", size = 166622, upload-time = "2025-11-12T09:56:37.75Z" }
60
+ wheels = [
61
+ { url = "https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl", hash = "sha256:67fba928dd5a544b783f6056f449e5e3931a5c378b128bc18501f7ea79e296ec", size = 40708, upload-time = "2025-11-12T09:56:36.333Z" },
62
+ ]
63
+
64
+ [[package]]
65
+ name = "executorch"
66
+ version = "1.1.0"
67
+ source = { registry = "https://pypi.org/simple" }
68
+ dependencies = [
69
+ { name = "expecttest" },
70
+ { name = "flatbuffers" },
71
+ { name = "hydra-core" },
72
+ { name = "hypothesis" },
73
+ { name = "kgb" },
74
+ { name = "mpmath" },
75
+ { name = "numpy" },
76
+ { name = "omegaconf" },
77
+ { name = "packaging" },
78
+ { name = "pandas" },
79
+ { name = "parameterized" },
80
+ { name = "pytest" },
81
+ { name = "pytest-json-report" },
82
+ { name = "pytest-rerunfailures" },
83
+ { name = "pytest-xdist" },
84
+ { name = "pytorch-tokenizers" },
85
+ { name = "pyyaml" },
86
+ { name = "ruamel-yaml" },
87
+ { name = "scikit-learn" },
88
+ { name = "sympy" },
89
+ { name = "tabulate" },
90
+ { name = "torch" },
91
+ { name = "torchao" },
92
+ { name = "typing-extensions" },
93
+ ]
94
+ wheels = [
95
+ { url = "https://files.pythonhosted.org/packages/c4/85/c03b1eba2ac6fde9586087c265f3c97dd2b3f847d088d3a92d601dbb02e7/executorch-1.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:a0d8214c3fb260c3d8a039f67fcd9a4dc5dc0c2c9f8b3c6de8f91e5666cfd829", size = 12185514, upload-time = "2026-01-28T15:58:47.89Z" },
96
+ ]
97
+
98
+ [[package]]
99
+ name = "expecttest"
100
+ version = "0.3.0"
101
+ source = { registry = "https://pypi.org/simple" }
102
+ sdist = { url = "https://files.pythonhosted.org/packages/22/0a/8868083a2b25c28811a88da6a4cb561f84feab0c9fa953c45820a3eb3a65/expecttest-0.3.0.tar.gz", hash = "sha256:6e8512fb86523ada1f94fd1b14e280f924e379064bb8a29ee399950e513eeccd", size = 7742, upload-time = "2024-12-11T15:32:15.72Z" }
103
+ wheels = [
104
+ { url = "https://files.pythonhosted.org/packages/27/fb/deeefea1ea549273817ca7bed3db2f39cc238a75a745a20e3651619f7335/expecttest-0.3.0-py3-none-any.whl", hash = "sha256:60f88103086e1754240b42175f622be83b6ffeac419434691ee5a5be819d0544", size = 8238, upload-time = "2024-12-11T15:32:13.523Z" },
105
+ ]
106
+
107
+ [[package]]
108
+ name = "filelock"
109
+ version = "3.32.4"
110
+ source = { registry = "https://pypi.org/simple" }
111
+ sdist = { url = "https://files.pythonhosted.org/packages/6d/30/03b03951873a1a0ffc7e8ca0e10c15597b59e8d0e39260704cd2ea087bc4/filelock-3.32.4.tar.gz", hash = "sha256:2bde2e4cf732e0153406d8a7bc80620ecf5e621fe0d25e41143c4e3b4733ff30", size = 222126, upload-time = "2026-08-23T17:37:55.363Z" }
112
+ wheels = [
113
+ { url = "https://files.pythonhosted.org/packages/01/a4/9b63d595d748e3aff8812b65eacc1a2c4bd90b7c2012e08e72373b4835eb/filelock-3.32.4-py3-none-any.whl", hash = "sha256:22e58ca3b1ae3b98993b762d7338367ae64fe50252bf78d59da3bfebcdf1cedd", size = 99864, upload-time = "2026-08-23T17:37:53.913Z" },
114
+ ]
115
+
116
+ [[package]]
117
+ name = "flatbuffers"
118
+ version = "25.12.19"
119
+ source = { registry = "https://pypi.org/simple" }
120
+ wheels = [
121
+ { url = "https://files.pythonhosted.org/packages/e8/2d/d2a548598be01649e2d46231d151a6c56d10b964d94043a335ae56ea2d92/flatbuffers-25.12.19-py2.py3-none-any.whl", hash = "sha256:7634f50c427838bb021c2d66a3d1168e9d199b0607e6329399f04846d42e20b4", size = 26661, upload-time = "2025-12-19T23:16:13.622Z" },
122
+ ]
123
+
124
+ [[package]]
125
+ name = "fsspec"
126
+ version = "2026.7.0"
127
+ source = { registry = "https://pypi.org/simple" }
128
+ sdist = { url = "https://files.pythonhosted.org/packages/00/78/f34251dadb8f3921264a1d9b8946f5e542014ee2614b285261b4e40e6775/fsspec-2026.7.0.tar.gz", hash = "sha256:c803c40f4cf860b49dea58ee3e1c33cb9c790520e233537e1340049f89b82a88", size = 317040, upload-time = "2026-07-28T16:34:51.052Z" }
129
+ wheels = [
130
+ { url = "https://files.pythonhosted.org/packages/fd/3c/6a2bf344106328fd04963664a60b9bb6496fc25df8e962fcdc1367285fb9/fsspec-2026.7.0-py3-none-any.whl", hash = "sha256:b57ddbafedfaef7018c1ecab32aa200a9d7ca26b77965f64e48b70061249d279", size = 206583, upload-time = "2026-07-28T16:34:49.538Z" },
131
+ ]
132
+
133
+ [[package]]
134
+ name = "hf-xet"
135
+ version = "1.6.0"
136
+ source = { registry = "https://pypi.org/simple" }
137
+ sdist = { url = "https://files.pythonhosted.org/packages/1b/ab/522a2ab67f27971a9d48ca666d4fca85ef7d5282d142e31fd087e27b1bbe/hf_xet-1.6.0.tar.gz", hash = "sha256:2e58454a340b3556dfa4972d5451aff4fba8dd42a236600ba1a1d2b1514f0fef", size = 920527, upload-time = "2026-08-03T22:33:13.243Z" }
138
+ wheels = [
139
+ { url = "https://files.pythonhosted.org/packages/9a/69/1f0cbc2fb22ae6082d094f743d1b8945a3f36f6089cb95f42b7ee348cda7/hf_xet-1.6.0-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:0e6e21fa3cdfcdcd76748564bf593870a5e013f47d97cf10aed63aa222cff5b7", size = 4262538, upload-time = "2026-08-03T22:33:05.287Z" },
140
+ { url = "https://files.pythonhosted.org/packages/d1/3a/4f4f2301ade26e404462d3336fa11f7958d914cabbabdd6e03c3c5d5658c/hf_xet-1.6.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4fc74352a17015bd0ee90038bc9efe38db894cde45f268b6712b04fce8cd0acb", size = 4460520, upload-time = "2026-08-03T22:33:06.81Z" },
141
+ ]
142
+
143
+ [[package]]
144
+ name = "huggingface-hub"
145
+ version = "0.36.2"
146
+ source = { registry = "https://pypi.org/simple" }
147
+ dependencies = [
148
+ { name = "filelock" },
149
+ { name = "fsspec" },
150
+ { name = "hf-xet" },
151
+ { name = "packaging" },
152
+ { name = "pyyaml" },
153
+ { name = "requests" },
154
+ { name = "tqdm" },
155
+ { name = "typing-extensions" },
156
+ ]
157
+ sdist = { url = "https://files.pythonhosted.org/packages/7c/b7/8cb61d2eece5fb05a83271da168186721c450eb74e3c31f7ef3169fa475b/huggingface_hub-0.36.2.tar.gz", hash = "sha256:1934304d2fb224f8afa3b87007d58501acfda9215b334eed53072dd5e815ff7a", size = 649782, upload-time = "2026-02-06T09:24:13.098Z" }
158
+ wheels = [
159
+ { url = "https://files.pythonhosted.org/packages/a8/af/48ac8483240de756d2438c380746e7130d1c6f75802ef22f3c6d49982787/huggingface_hub-0.36.2-py3-none-any.whl", hash = "sha256:48f0c8eac16145dfce371e9d2d7772854a4f591bcb56c9cf548accf531d54270", size = 566395, upload-time = "2026-02-06T09:24:11.133Z" },
160
+ ]
161
+
162
+ [[package]]
163
+ name = "hydra-core"
164
+ version = "1.3.5"
165
+ source = { registry = "https://pypi.org/simple" }
166
+ dependencies = [
167
+ { name = "antlr4-python3-runtime" },
168
+ { name = "omegaconf" },
169
+ { name = "packaging" },
170
+ ]
171
+ sdist = { url = "https://files.pythonhosted.org/packages/3e/e4/69a522676faf88994d93d8a5e69e0666c61cae7f73d1bbcc483222023e74/hydra_core-1.3.5.tar.gz", hash = "sha256:71c441eabbde086062045e4d3fce9e26015244f1a4ac721cf3e444c7edf10633", size = 3264337, upload-time = "2026-08-05T18:33:21.394Z" }
172
+ wheels = [
173
+ { url = "https://files.pythonhosted.org/packages/9c/97/f9d463a6f3c7d0955753eca5cbbf35b596ac471dd13fe357211a53fd37be/hydra_core-1.3.5-py3-none-any.whl", hash = "sha256:a3ff35b4ea6794e4c83d993016f4bde4ac35797ebe7a08f30e83ed9341880331", size = 155768, upload-time = "2026-08-05T18:33:19.834Z" },
174
+ ]
175
+
176
+ [[package]]
177
+ name = "hypothesis"
178
+ version = "6.165.10"
179
+ source = { registry = "https://pypi.org/simple" }
180
+ dependencies = [
181
+ { name = "sortedcontainers" },
182
+ ]
183
+ sdist = { url = "https://files.pythonhosted.org/packages/5c/e2/0fad246d2b6330e1f78479bfc566b5c22be82aee8a865cde9a08f648487d/hypothesis-6.165.10.tar.gz", hash = "sha256:68b45e09834cd80523cb1eb274463073c7a9af4e4ef7cff34d9615f355572d32", size = 503703, upload-time = "2026-08-16T22:56:15.404Z" }
184
+ wheels = [
185
+ { url = "https://files.pythonhosted.org/packages/db/52/6f0a9b7aab24b0635e2238f3fbddea5b54b17879ac813df42a3cc3384c5c/hypothesis-6.165.10-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76a7be86d986223b9f1bdb7e7cbcdb048649901fdb956c598ef73bdab1786cd5", size = 1108009, upload-time = "2026-08-16T22:54:53.082Z" },
186
+ { url = "https://files.pythonhosted.org/packages/cb/f9/df24eb28412f82465e2b7707f0ff1ec274d580bce389d4d9156617dc7bba/hypothesis-6.165.10-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2d0e0f8263d34dd8fa3b39eaa9a50bba56a8470b3dd9ebf6672d10840abe063e", size = 1283402, upload-time = "2026-08-16T22:54:18.054Z" },
187
+ { url = "https://files.pythonhosted.org/packages/04/66/4c71c5be7a49d84b8c3a9278c1807c4c81181ab5474beb27df9d4c40dc0e/hypothesis-6.165.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9ff356e97e3ab09db07c8b675efa67340103874a0bae7465acb83dad7a35f7f", size = 1106830, upload-time = "2026-08-16T22:55:10.389Z" },
188
+ { url = "https://files.pythonhosted.org/packages/a8/8b/794ced36864825492ac3712d5acab5a257b4601e6a9dc2ccdd3937198f87/hypothesis-6.165.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e9acb2c4d9cb532c3fedea74159f7b923c8c036328c9239b4049e7aa073bdd81", size = 1280780, upload-time = "2026-08-16T22:54:34.983Z" },
189
+ { url = "https://files.pythonhosted.org/packages/10/39/ef26fa79c1738dfe9cdb1a3584fb6717d26429ca6c9d011cc4fdf08130c2/hypothesis-6.165.10-cp315-abi3.abi3t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7730d8197086f65d8969a991d6728a1d420a51b19fea06535c896cb43a1e05d0", size = 1104876, upload-time = "2026-08-16T22:54:58.937Z" },
190
+ { url = "https://files.pythonhosted.org/packages/e0/60/31d504e364134d60af23e5f6365db0da3cf4a51b3ed3d4836e5a2cff12cf/hypothesis-6.165.10-cp315-abi3.abi3t-musllinux_1_2_aarch64.whl", hash = "sha256:e1bbeb7c506b07ee0422cf9b2f7212fefa4240957f03526d38d27bc6743a0a48", size = 1278684, upload-time = "2026-08-16T22:55:22.971Z" },
191
+ ]
192
+
193
+ [[package]]
194
+ name = "idna"
195
+ version = "3.19"
196
+ source = { registry = "https://pypi.org/simple" }
197
+ sdist = { url = "https://files.pythonhosted.org/packages/5f/f7/abb373e5757eaec4b922b92f97ec8d6d7e057cf06778247604fbc4e7c3f3/idna-3.19.tar.gz", hash = "sha256:5e0811a4383b21dc5838069f801c4fb62113b7447663d2530d2bd6e77b49bf15", size = 215237, upload-time = "2026-08-18T05:14:24.27Z" }
198
+ wheels = [
199
+ { url = "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl", hash = "sha256:815e7be7a7806d54abb586dc943addc79e8b2ee16915059658cbeff4b1b43bf4", size = 68550, upload-time = "2026-08-18T05:14:22.343Z" },
200
+ ]
201
+
202
+ [[package]]
203
+ name = "iniconfig"
204
+ version = "2.3.0"
205
+ source = { registry = "https://pypi.org/simple" }
206
+ sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" }
207
+ wheels = [
208
+ { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" },
209
+ ]
210
+
211
+ [[package]]
212
+ name = "jinja2"
213
+ version = "3.1.6"
214
+ source = { registry = "https://pypi.org/simple" }
215
+ dependencies = [
216
+ { name = "markupsafe" },
217
+ ]
218
+ sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" }
219
+ wheels = [
220
+ { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" },
221
+ ]
222
+
223
+ [[package]]
224
+ name = "joblib"
225
+ version = "1.5.3"
226
+ source = { registry = "https://pypi.org/simple" }
227
+ sdist = { url = "https://files.pythonhosted.org/packages/41/f2/d34e8b3a08a9cc79a50b2208a93dce981fe615b64d5a4d4abee421d898df/joblib-1.5.3.tar.gz", hash = "sha256:8561a3269e6801106863fd0d6d84bb737be9e7631e33aaed3fb9ce5953688da3", size = 331603, upload-time = "2025-12-15T08:41:46.427Z" }
228
+ wheels = [
229
+ { url = "https://files.pythonhosted.org/packages/7b/91/984aca2ec129e2757d1e4e3c81c3fcda9d0f85b74670a094cc443d9ee949/joblib-1.5.3-py3-none-any.whl", hash = "sha256:5fc3c5039fc5ca8c0276333a188bbd59d6b7ab37fe6632daa76bc7f9ec18e713", size = 309071, upload-time = "2025-12-15T08:41:44.973Z" },
230
+ ]
231
+
232
+ [[package]]
233
+ name = "kgb"
234
+ version = "7.3"
235
+ source = { registry = "https://pypi.org/simple" }
236
+ sdist = { url = "https://files.pythonhosted.org/packages/e8/00/9e56dee65ec791a92348fb54e8ced08c4c4db494b0f58cfb34737d087fb4/kgb-7.3.tar.gz", hash = "sha256:b8af7e79cb8b0df5a2ec596010b8e5d014845cfaa9203577b85b99d4df192927", size = 62922, upload-time = "2025-12-11T23:56:24.911Z" }
237
+ wheels = [
238
+ { url = "https://files.pythonhosted.org/packages/eb/d6/1c81a1292fc50ad93d0b145f1c241ecb7d541fba4dcec7166e2e1d99f9cd/kgb-7.3-py2.py3-none-any.whl", hash = "sha256:0b300cd6d234a951f60e54ccda78c99a355393d6ae878d3d5925e726ae2f0450", size = 59662, upload-time = "2025-12-11T23:56:23.699Z" },
239
+ ]
240
+
241
+ [[package]]
242
+ name = "markupsafe"
243
+ version = "3.0.3"
244
+ source = { registry = "https://pypi.org/simple" }
245
+ sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" }
246
+ wheels = [
247
+ { url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" },
248
+ { url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" },
249
+ ]
250
+
251
+ [[package]]
252
+ name = "mpmath"
253
+ version = "1.3.0"
254
+ source = { registry = "https://pypi.org/simple" }
255
+ sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106, upload-time = "2023-03-07T16:47:11.061Z" }
256
+ wheels = [
257
+ { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198, upload-time = "2023-03-07T16:47:09.197Z" },
258
+ ]
259
+
260
+ [[package]]
261
+ name = "networkx"
262
+ version = "3.6.1"
263
+ source = { registry = "https://pypi.org/simple" }
264
+ sdist = { url = "https://files.pythonhosted.org/packages/6a/51/63fe664f3908c97be9d2e4f1158eb633317598cfa6e1fc14af5383f17512/networkx-3.6.1.tar.gz", hash = "sha256:26b7c357accc0c8cde558ad486283728b65b6a95d85ee1cd66bafab4c8168509", size = 2517025, upload-time = "2025-12-08T17:02:39.908Z" }
265
+ wheels = [
266
+ { url = "https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl", hash = "sha256:d47fbf302e7d9cbbb9e2555a0d267983d2aa476bac30e90dfbe5669bd57f3762", size = 2068504, upload-time = "2025-12-08T17:02:38.159Z" },
267
+ ]
268
+
269
+ [[package]]
270
+ name = "numpy"
271
+ version = "2.5.2"
272
+ source = { registry = "https://pypi.org/simple" }
273
+ sdist = { url = "https://files.pythonhosted.org/packages/9a/80/db0b4559e57ec36362bedbb05530a87fafbcb6067708c946967a41d449e7/numpy-2.5.2.tar.gz", hash = "sha256:d482d171c406ae88c5b19cad3b6a1c4c5209f886ab74bc44c2c865c23f52d860", size = 20773161, upload-time = "2026-08-09T13:48:27.962Z" }
274
+ wheels = [
275
+ { url = "https://files.pythonhosted.org/packages/e5/21/4947e0e9d6c9fc2e2ff15b8949049ee44f63adb9cacc729ab8793f97e712/numpy-2.5.2-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8ee9c4eeb8454b3660a8b53493563c3e121c2fc94fbd72b848ef814ed7b676a9", size = 15612696, upload-time = "2026-08-09T13:45:04.151Z" },
276
+ { url = "https://files.pythonhosted.org/packages/14/25/3f0be4c1b9fdf5dd5e708a6806978564d7c46a055c000496309ff2a2f8af/numpy-2.5.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7999d4ddb0c4025018373fd787510d46e04c769467af22869707b3c1cfd459ab", size = 16974396, upload-time = "2026-08-09T13:45:11.316Z" },
277
+ ]
278
+
279
+ [[package]]
280
+ name = "omegaconf"
281
+ version = "2.3.1"
282
+ source = { registry = "https://pypi.org/simple" }
283
+ dependencies = [
284
+ { name = "antlr4-python3-runtime" },
285
+ { name = "pyyaml" },
286
+ ]
287
+ sdist = { url = "https://files.pythonhosted.org/packages/ce/3d/e4b57b8d9008c6ebe0d5eff901f91d5700cf7bdb8c8863df817463a7fd5e/omegaconf-2.3.1.tar.gz", hash = "sha256:e5e7de64aeebeddaf8e6d3f7a783b32ac2a01c0fbd9c878012caecb891a1f42a", size = 3298472, upload-time = "2026-06-11T05:05:12.885Z" }
288
+ wheels = [
289
+ { url = "https://files.pythonhosted.org/packages/a4/0e/152509871bf30df6fc38569f52a2db9b55dd41aae957adae50a053ac7778/omegaconf-2.3.1-py3-none-any.whl", hash = "sha256:3d701d14e9a8828f1edd28bb70b725908b34277cdd72cf7d6a83f94dadc6b6a0", size = 79502, upload-time = "2026-06-11T05:05:09.954Z" },
290
+ ]
291
+
292
+ [[package]]
293
+ name = "packaging"
294
+ version = "26.3"
295
+ source = { registry = "https://pypi.org/simple" }
296
+ sdist = { url = "https://files.pythonhosted.org/packages/7d/fa/3944b40b07da9ce895c0e6303a5ab7d53da063554f534556b134a54d6093/packaging-26.3.tar.gz", hash = "sha256:94edc256424af38762eb31306eed28beb9f0efc50a8837492c9d6fd6004aed79", size = 313412, upload-time = "2026-08-04T18:15:28.737Z" }
297
+ wheels = [
298
+ { url = "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl", hash = "sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c", size = 129956, upload-time = "2026-08-04T18:15:27.159Z" },
299
+ ]
300
+
301
+ [[package]]
302
+ name = "pandas"
303
+ version = "3.0.5"
304
+ source = { registry = "https://pypi.org/simple" }
305
+ dependencies = [
306
+ { name = "numpy" },
307
+ { name = "python-dateutil" },
308
+ ]
309
+ sdist = { url = "https://files.pythonhosted.org/packages/be/4f/5f3422a2afec5ffc46308b79e53291365a93748b498ac2e58bead0197916/pandas-3.0.5.tar.gz", hash = "sha256:dca3734d6ab7c906e6730f0788b0a1dbb9f2467731f9711f77995c8e9d62d712", size = 4658219, upload-time = "2026-07-22T22:19:28.819Z" }
310
+ wheels = [
311
+ { url = "https://files.pythonhosted.org/packages/e0/51/fac252f4a913ed5eabf3c11b880a9e8d5a6c10f0b2129d0462212d238b4d/pandas-3.0.5-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:73fa87b08a7ef706f8aafda39ddaccf2a99047bea62d8c88a0361bcafb2237bc", size = 10485458, upload-time = "2026-07-22T22:18:12.834Z" },
312
+ { url = "https://files.pythonhosted.org/packages/a4/8c/1f29b5be8d3fc47dd7567eb167fabba2085879b31e0287ce7cba6d3d2ff4/pandas-3.0.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2a29c53d85ea98c5e792c59ef82ee9fbe6ca902c0d0adb6b23f45ef894cd7bf6", size = 11499501, upload-time = "2026-07-22T22:18:17.689Z" },
313
+ { url = "https://files.pythonhosted.org/packages/f3/9a/ffbd852d58bd74a617fe2f8ee6a58a96982271ce41cf981eab22190b4a4b/pandas-3.0.5-cp312-cp312-pyemscripten_2024_0_wasm32.whl", hash = "sha256:b2acb4650527eec6822c3dadb2b771277b65e7dae7a267d4bccf65fd1bb3fbce", size = 7197652, upload-time = "2026-07-22T22:18:22.502Z" },
314
+ ]
315
+
316
+ [[package]]
317
+ name = "parameterized"
318
+ version = "0.9.0"
319
+ source = { registry = "https://pypi.org/simple" }
320
+ sdist = { url = "https://files.pythonhosted.org/packages/ea/49/00c0c0cc24ff4266025a53e41336b79adaa5a4ebfad214f433d623f9865e/parameterized-0.9.0.tar.gz", hash = "sha256:7fc905272cefa4f364c1a3429cbbe9c0f98b793988efb5bf90aac80f08db09b1", size = 24351, upload-time = "2023-03-27T02:01:11.592Z" }
321
+ wheels = [
322
+ { url = "https://files.pythonhosted.org/packages/00/2f/804f58f0b856ab3bf21617cccf5b39206e6c4c94c2cd227bde125ea6105f/parameterized-0.9.0-py2.py3-none-any.whl", hash = "sha256:4e0758e3d41bea3bbd05ec14fc2c24736723f243b28d702081aef438c9372b1b", size = 20475, upload-time = "2023-03-27T02:01:09.31Z" },
323
+ ]
324
+
325
+ [[package]]
326
+ name = "pluggy"
327
+ version = "1.6.0"
328
+ source = { registry = "https://pypi.org/simple" }
329
+ sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" }
330
+ wheels = [
331
+ { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
332
+ ]
333
+
334
+ [[package]]
335
+ name = "pycparser"
336
+ version = "3.0"
337
+ source = { registry = "https://pypi.org/simple" }
338
+ sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" }
339
+ wheels = [
340
+ { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" },
341
+ ]
342
+
343
+ [[package]]
344
+ name = "pygments"
345
+ version = "2.21.0"
346
+ source = { registry = "https://pypi.org/simple" }
347
+ sdist = { url = "https://files.pythonhosted.org/packages/49/2e/ced460408999b33da6b31b0021b0f37d329e202d4169aeb164493778f25b/pygments-2.21.0.tar.gz", hash = "sha256:610ca751c9bc2492b38eb9a38a7fbc93edbbb2d7182edaf34e66ae493dee5c8c", size = 5005329, upload-time = "2026-08-17T08:02:48.824Z" }
348
+ wheels = [
349
+ { url = "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl", hash = "sha256:2363c69b61c4a97c838da3b130dcd6468f4848992b21a82f2a63ec34377137d9", size = 1250147, upload-time = "2026-08-17T08:02:44.912Z" },
350
+ ]
351
+
352
+ [[package]]
353
+ name = "pytest"
354
+ version = "8.4.2"
355
+ source = { registry = "https://pypi.org/simple" }
356
+ dependencies = [
357
+ { name = "iniconfig" },
358
+ { name = "packaging" },
359
+ { name = "pluggy" },
360
+ { name = "pygments" },
361
+ ]
362
+ sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size = 1519618, upload-time = "2025-09-04T14:34:22.711Z" }
363
+ wheels = [
364
+ { url = "https://files.pythonhosted.org/packages/a8/a4/20da314d277121d6534b3a980b29035dcd51e6744bd79075a6ce8fa4eb8d/pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79", size = 365750, upload-time = "2025-09-04T14:34:20.226Z" },
365
+ ]
366
+
367
+ [[package]]
368
+ name = "pytest-json-report"
369
+ version = "1.5.0"
370
+ source = { registry = "https://pypi.org/simple" }
371
+ dependencies = [
372
+ { name = "pytest" },
373
+ { name = "pytest-metadata" },
374
+ ]
375
+ sdist = { url = "https://files.pythonhosted.org/packages/4f/d3/765dae9712fcd68d820338908c1337e077d5fdadccd5cacf95b9b0bea278/pytest-json-report-1.5.0.tar.gz", hash = "sha256:2dde3c647851a19b5f3700729e8310a6e66efb2077d674f27ddea3d34dc615de", size = 21241, upload-time = "2022-03-15T21:03:10.2Z" }
376
+ wheels = [
377
+ { url = "https://files.pythonhosted.org/packages/81/35/d07400c715bf8a88aa0c1ee9c9eb6050ca7fe5b39981f0eea773feeb0681/pytest_json_report-1.5.0-py3-none-any.whl", hash = "sha256:9897b68c910b12a2e48dd849f9a284b2c79a732a8a9cb398452ddd23d3c8c325", size = 13222, upload-time = "2022-03-15T21:03:08.65Z" },
378
+ ]
379
+
380
+ [[package]]
381
+ name = "pytest-metadata"
382
+ version = "3.1.1"
383
+ source = { registry = "https://pypi.org/simple" }
384
+ dependencies = [
385
+ { name = "pytest" },
386
+ ]
387
+ sdist = { url = "https://files.pythonhosted.org/packages/a6/85/8c969f8bec4e559f8f2b958a15229a35495f5b4ce499f6b865eac54b878d/pytest_metadata-3.1.1.tar.gz", hash = "sha256:d2a29b0355fbc03f168aa96d41ff88b1a3b44a3b02acbe491801c98a048017c8", size = 9952, upload-time = "2024-02-12T19:38:44.887Z" }
388
+ wheels = [
389
+ { url = "https://files.pythonhosted.org/packages/3e/43/7e7b2ec865caa92f67b8f0e9231a798d102724ca4c0e1f414316be1c1ef2/pytest_metadata-3.1.1-py3-none-any.whl", hash = "sha256:c8e0844db684ee1c798cfa38908d20d67d0463ecb6137c72e91f418558dd5f4b", size = 11428, upload-time = "2024-02-12T19:38:42.531Z" },
390
+ ]
391
+
392
+ [[package]]
393
+ name = "pytest-rerunfailures"
394
+ version = "15.1"
395
+ source = { registry = "https://pypi.org/simple" }
396
+ dependencies = [
397
+ { name = "packaging" },
398
+ { name = "pytest" },
399
+ ]
400
+ sdist = { url = "https://files.pythonhosted.org/packages/a0/78/e6e358545537a8e82c4dc91e72ec0d6f80546a3786dd27c76b06ca09db77/pytest_rerunfailures-15.1.tar.gz", hash = "sha256:c6040368abd7b8138c5b67288be17d6e5611b7368755ce0465dda0362c8ece80", size = 26981, upload-time = "2025-05-08T06:36:33.483Z" }
401
+ wheels = [
402
+ { url = "https://files.pythonhosted.org/packages/f3/30/11d836ff01c938969efa319b4ebe2374ed79d28043a12bfc908577aab9f3/pytest_rerunfailures-15.1-py3-none-any.whl", hash = "sha256:f674c3594845aba8b23c78e99b1ff8068556cc6a8b277f728071fdc4f4b0b355", size = 13274, upload-time = "2025-05-08T06:36:32.029Z" },
403
+ ]
404
+
405
+ [[package]]
406
+ name = "pytest-xdist"
407
+ version = "3.8.0"
408
+ source = { registry = "https://pypi.org/simple" }
409
+ dependencies = [
410
+ { name = "execnet" },
411
+ { name = "pytest" },
412
+ ]
413
+ sdist = { url = "https://files.pythonhosted.org/packages/78/b4/439b179d1ff526791eb921115fca8e44e596a13efeda518b9d845a619450/pytest_xdist-3.8.0.tar.gz", hash = "sha256:7e578125ec9bc6050861aa93f2d59f1d8d085595d6551c2c90b6f4fad8d3a9f1", size = 88069, upload-time = "2025-07-01T13:30:59.346Z" }
414
+ wheels = [
415
+ { url = "https://files.pythonhosted.org/packages/ca/31/d4e37e9e550c2b92a9cbc2e4d0b7420a27224968580b5a447f420847c975/pytest_xdist-3.8.0-py3-none-any.whl", hash = "sha256:202ca578cfeb7370784a8c33d6d05bc6e13b4f25b5053c30a152269fd10f0b88", size = 46396, upload-time = "2025-07-01T13:30:56.632Z" },
416
+ ]
417
+
418
+ [[package]]
419
+ name = "python-dateutil"
420
+ version = "2.9.0.post0"
421
+ source = { registry = "https://pypi.org/simple" }
422
+ dependencies = [
423
+ { name = "six" },
424
+ ]
425
+ sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" }
426
+ wheels = [
427
+ { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" },
428
+ ]
429
+
430
+ [[package]]
431
+ name = "pytorch-tokenizers"
432
+ version = "1.4.1"
433
+ source = { registry = "https://pypi.org/simple" }
434
+ dependencies = [
435
+ { name = "sentencepiece" },
436
+ { name = "tiktoken" },
437
+ { name = "tokenizers" },
438
+ ]
439
+ wheels = [
440
+ { url = "https://files.pythonhosted.org/packages/d6/cf/69d6d3c6fad65f0f1c63a8f0f0db85009a9db4e25fa50d573ead4e527cbb/pytorch_tokenizers-1.4.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:84ee954611ec869f875dd23618c66c15b718c2a4eed639fefb72e7806091ff76", size = 1451907, upload-time = "2026-08-05T19:37:41.622Z" },
441
+ ]
442
+
443
+ [[package]]
444
+ name = "pyyaml"
445
+ version = "6.0.3"
446
+ source = { registry = "https://pypi.org/simple" }
447
+ sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" }
448
+ wheels = [
449
+ { url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" },
450
+ { url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" },
451
+ ]
452
+
453
+ [[package]]
454
+ name = "regex"
455
+ version = "2026.7.19"
456
+ source = { registry = "https://pypi.org/simple" }
457
+ sdist = { url = "https://files.pythonhosted.org/packages/20/98/04b13f1ddfb63158025291c02e03eb42fbb7acb51d091d541050eb4e35e8/regex-2026.7.19.tar.gz", hash = "sha256:7e77b324909c1617cbb4c668677e2c6ae13f44d7c1de0d4f15f2e3c10f3315b5", size = 416440, upload-time = "2026-07-19T00:19:48.923Z" }
458
+ wheels = [
459
+ { url = "https://files.pythonhosted.org/packages/22/85/102a81b218298957d4ea7d2f084fae537a71add9d6ff93c8e67284c5f45e/regex-2026.7.19-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:93db40c8de0815baab96a06e08a984bac71f989d13bab789e382158c5d426797", size = 796708, upload-time = "2026-07-19T00:17:11.542Z" },
460
+ { url = "https://files.pythonhosted.org/packages/6f/69/03c9b3f058d66403e0ca2c938696e81d51cd4c6d47ec5265f02f96948d9a/regex-2026.7.19-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1d793a7988e04fcb1e2e135567443d82173225d657419ec09414a9b5a145b986", size = 784338, upload-time = "2026-07-19T00:17:21.057Z" },
461
+ ]
462
+
463
+ [[package]]
464
+ name = "requests"
465
+ version = "2.34.2"
466
+ source = { registry = "https://pypi.org/simple" }
467
+ dependencies = [
468
+ { name = "certifi" },
469
+ { name = "charset-normalizer" },
470
+ { name = "idna" },
471
+ { name = "urllib3" },
472
+ ]
473
+ sdist = { url = "https://files.pythonhosted.org/packages/ac/c3/e2a2b89f2d3e2179abd6d00ebd70bff6273f37fb3e0cc209f48b39d00cbf/requests-2.34.2.tar.gz", hash = "sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed", size = 142856, upload-time = "2026-05-14T19:25:27.735Z" }
474
+ wheels = [
475
+ { url = "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl", hash = "sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0", size = 73075, upload-time = "2026-05-14T19:25:26.443Z" },
476
+ ]
477
+
478
+ [[package]]
479
+ name = "ruamel-yaml"
480
+ version = "0.19.1"
481
+ source = { registry = "https://pypi.org/simple" }
482
+ sdist = { url = "https://files.pythonhosted.org/packages/c7/3b/ebda527b56beb90cb7652cb1c7e4f91f48649fbcd8d2eb2fb6e77cd3329b/ruamel_yaml-0.19.1.tar.gz", hash = "sha256:53eb66cd27849eff968ebf8f0bf61f46cdac2da1d1f3576dd4ccee9b25c31993", size = 142709, upload-time = "2026-01-02T16:50:31.84Z" }
483
+ wheels = [
484
+ { url = "https://files.pythonhosted.org/packages/b8/0c/51f6841f1d84f404f92463fc2b1ba0da357ca1e3db6b7fbda26956c3b82a/ruamel_yaml-0.19.1-py3-none-any.whl", hash = "sha256:27592957fedf6e0b62f281e96effd28043345e0e66001f97683aa9a40c667c93", size = 118102, upload-time = "2026-01-02T16:50:29.201Z" },
485
+ ]
486
+
487
+ [[package]]
488
+ name = "safetensors"
489
+ version = "0.8.0"
490
+ source = { registry = "https://pypi.org/simple" }
491
+ sdist = { url = "https://files.pythonhosted.org/packages/45/06/f955dbbb1859e3bd23c8ac6141af5106e7ad5fedec4a3a6e3d60f94b7001/safetensors-0.8.0.tar.gz", hash = "sha256:fabaf3e0f18a6618d9b36560682562157f77c2b71fcffc7b432be2baed9d753d", size = 325846, upload-time = "2026-06-09T07:52:25.563Z" }
492
+ wheels = [
493
+ { url = "https://files.pythonhosted.org/packages/09/7d/65a7de0af421317bb36a067241e4235fff194eed60b961ed6d3f59a3fc60/safetensors-0.8.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a46e5ff292c356d6991e60942ba7f79817682d3a2cef0702136448cb9c4d235", size = 502844, upload-time = "2026-06-09T07:52:07.624Z" },
494
+ { url = "https://files.pythonhosted.org/packages/2a/43/bf38443278eab4b1be1fce2931e2b012ad9cb7df52ada751d0aab8f7659a/safetensors-0.8.0-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:87eec7ffed2b809f05a398a8becb7d013f19f7837cd15d9748580d6cf30dbaf4", size = 678670, upload-time = "2026-06-09T07:52:20.032Z" },
495
+ ]
496
+
497
+ [[package]]
498
+ name = "scikit-learn"
499
+ version = "1.7.1"
500
+ source = { registry = "https://pypi.org/simple" }
501
+ dependencies = [
502
+ { name = "joblib" },
503
+ { name = "numpy" },
504
+ { name = "scipy" },
505
+ { name = "threadpoolctl" },
506
+ ]
507
+ sdist = { url = "https://files.pythonhosted.org/packages/41/84/5f4af978fff619706b8961accac84780a6d298d82a8873446f72edb4ead0/scikit_learn-1.7.1.tar.gz", hash = "sha256:24b3f1e976a4665aa74ee0fcaac2b8fccc6ae77c8e07ab25da3ba6d3292b9802", size = 7190445, upload-time = "2025-07-18T08:01:54.5Z" }
508
+ wheels = [
509
+ { url = "https://files.pythonhosted.org/packages/ad/09/a2aa0b4e644e5c4ede7006748f24e72863ba2ae71897fecfd832afea01b4/scikit_learn-1.7.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e3142f0abe1ad1d1c31a2ae987621e41f6b578144a911ff4ac94781a583adad7", size = 9290988, upload-time = "2025-07-18T08:01:28.938Z" },
510
+ ]
511
+
512
+ [[package]]
513
+ name = "scipy"
514
+ version = "1.18.1"
515
+ source = { registry = "https://pypi.org/simple" }
516
+ dependencies = [
517
+ { name = "numpy" },
518
+ ]
519
+ sdist = { url = "https://files.pythonhosted.org/packages/7e/74/66de6258867beb2ef08f35f9f2ac017a52cacd5081714d239ff1a442d458/scipy-1.18.1.tar.gz", hash = "sha256:52c4b7422442aba924d03ad4019852b08a92e64ea187b933135687bfe2747307", size = 30781235, upload-time = "2026-08-21T23:28:50.599Z" }
520
+ wheels = [
521
+ { url = "https://files.pythonhosted.org/packages/75/9a/2e71719f31eaefe0e3a1706c4a1ded94e664bfd95ffca2b219a671faee01/scipy-1.18.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3c085faa2cfa879c5141df483f836f4d691045a078224a670fa570fa01612d89", size = 34025113, upload-time = "2026-08-21T23:24:02.209Z" },
522
+ { url = "https://files.pythonhosted.org/packages/d3/af/c5538be1792f7034c12c7db6ee67cace58253c7b87b122d68253eaf5de89/scipy-1.18.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c35d74ce0e193ff740c2f2be2ac913ddc232fe6c1ff40b26cfecb9c670c63314", size = 35639587, upload-time = "2026-08-21T23:24:13.05Z" },
523
+ ]
524
+
525
+ [[package]]
526
+ name = "sentencepiece"
527
+ version = "0.2.2"
528
+ source = { registry = "https://pypi.org/simple" }
529
+ sdist = { url = "https://files.pythonhosted.org/packages/cc/33/ea3cb3839607eb175da835244a798f797f478c5ddf0e8ecdf57ea85a4c70/sentencepiece-0.2.2.tar.gz", hash = "sha256:3d2b5e824b5622038dc7b490897efe05ebbbb9e7350fc142f3ecc8789ef9bdf6", size = 8218435, upload-time = "2026-07-12T08:39:34.701Z" }
530
+ wheels = [
531
+ { url = "https://files.pythonhosted.org/packages/19/90/cd798935668cff71d309d8ff10385844ecf216b1fe454f1993ed8bf2cb91/sentencepiece-0.2.2-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cbce24284f51f71d10a42b7b9c964dcb9048b28f1c8e5db40bcbcb6f428cba6a", size = 1325200, upload-time = "2026-07-12T08:38:33.689Z" },
532
+ ]
533
+
534
+ [[package]]
535
+ name = "setuptools"
536
+ version = "84.0.0"
537
+ source = { registry = "https://pypi.org/simple" }
538
+ sdist = { url = "https://files.pythonhosted.org/packages/6d/44/f5da03a8ef95d369145c5bb53050e7877c9f3d312e128605fd9504829143/setuptools-84.0.0.tar.gz", hash = "sha256:f4695c21257f0d9b537ec2692c941d02ee143b7cc1276941349a546573b2ef73", size = 1168449, upload-time = "2026-08-08T18:27:58.365Z" }
539
+ wheels = [
540
+ { url = "https://files.pythonhosted.org/packages/95/9c/c510029fc6ef33a6275cd2c5d3cecd6613dfd6aa401d57c54f1c18852ccf/setuptools-84.0.0-py3-none-any.whl", hash = "sha256:51a52592b3b99e102b609654876bd65f19f999935166d1352678931132b0c670", size = 818216, upload-time = "2026-08-08T18:27:56.719Z" },
541
+ ]
542
+
543
+ [[package]]
544
+ name = "six"
545
+ version = "1.17.0"
546
+ source = { registry = "https://pypi.org/simple" }
547
+ sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" }
548
+ wheels = [
549
+ { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" },
550
+ ]
551
+
552
+ [[package]]
553
+ name = "sortedcontainers"
554
+ version = "2.4.0"
555
+ source = { registry = "https://pypi.org/simple" }
556
+ sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594, upload-time = "2021-05-16T22:03:42.897Z" }
557
+ wheels = [
558
+ { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575, upload-time = "2021-05-16T22:03:41.177Z" },
559
+ ]
560
+
561
+ [[package]]
562
+ name = "soundfile"
563
+ version = "0.13.1"
564
+ source = { registry = "https://pypi.org/simple" }
565
+ dependencies = [
566
+ { name = "cffi" },
567
+ { name = "numpy" },
568
+ ]
569
+ sdist = { url = "https://files.pythonhosted.org/packages/e1/41/9b873a8c055582859b239be17902a85339bec6a30ad162f98c9b0288a2cc/soundfile-0.13.1.tar.gz", hash = "sha256:b2c68dab1e30297317080a5b43df57e302584c49e2942defdde0acccc53f0e5b", size = 46156, upload-time = "2025-01-25T09:17:04.831Z" }
570
+ wheels = [
571
+ { url = "https://files.pythonhosted.org/packages/64/28/e2a36573ccbcf3d57c00626a21fe51989380636e821b341d36ccca0c1c3a/soundfile-0.13.1-py2.py3-none-any.whl", hash = "sha256:a23c717560da2cf4c7b5ae1142514e0fd82d6bbd9dfc93a50423447142f2c445", size = 25751, upload-time = "2025-01-25T09:16:44.235Z" },
572
+ { url = "https://files.pythonhosted.org/packages/58/ae/c0e4a53d77cf6e9a04179535766b3321b0b9ced5f70522e4caf9329f0046/soundfile-0.13.1-py2.py3-none-manylinux_2_28_aarch64.whl", hash = "sha256:9c9e855f5a4d06ce4213f31918653ab7de0c5a8d8107cd2427e44b42df547deb", size = 1235729, upload-time = "2025-01-25T09:16:53.018Z" },
573
+ ]
574
+
575
+ [[package]]
576
+ name = "sympy"
577
+ version = "1.14.0"
578
+ source = { registry = "https://pypi.org/simple" }
579
+ dependencies = [
580
+ { name = "mpmath" },
581
+ ]
582
+ sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921, upload-time = "2025-04-27T18:05:01.611Z" }
583
+ wheels = [
584
+ { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353, upload-time = "2025-04-27T18:04:59.103Z" },
585
+ ]
586
+
587
+ [[package]]
588
+ name = "tabulate"
589
+ version = "0.10.0"
590
+ source = { registry = "https://pypi.org/simple" }
591
+ sdist = { url = "https://files.pythonhosted.org/packages/46/58/8c37dea7bbf769b20d58e7ace7e5edfe65b849442b00ffcdd56be88697c6/tabulate-0.10.0.tar.gz", hash = "sha256:e2cfde8f79420f6deeffdeda9aaec3b6bc5abce947655d17ac662b126e48a60d", size = 91754, upload-time = "2026-03-04T18:55:34.402Z" }
592
+ wheels = [
593
+ { url = "https://files.pythonhosted.org/packages/99/55/db07de81b5c630da5cbf5c7df646580ca26dfaefa593667fc6f2fe016d2e/tabulate-0.10.0-py3-none-any.whl", hash = "sha256:f0b0622e567335c8fabaaa659f1b33bcb6ddfe2e496071b743aa113f8774f2d3", size = 39814, upload-time = "2026-03-04T18:55:31.284Z" },
594
+ ]
595
+
596
+ [[package]]
597
+ name = "threadpoolctl"
598
+ version = "3.6.0"
599
+ source = { registry = "https://pypi.org/simple" }
600
+ sdist = { url = "https://files.pythonhosted.org/packages/b7/4d/08c89e34946fce2aec4fbb45c9016efd5f4d7f24af8e5d93296e935631d8/threadpoolctl-3.6.0.tar.gz", hash = "sha256:8ab8b4aa3491d812b623328249fab5302a68d2d71745c8a4c719a2fcaba9f44e", size = 21274, upload-time = "2025-03-13T13:49:23.031Z" }
601
+ wheels = [
602
+ { url = "https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb", size = 18638, upload-time = "2025-03-13T13:49:21.846Z" },
603
+ ]
604
+
605
+ [[package]]
606
+ name = "tiktoken"
607
+ version = "0.14.0"
608
+ source = { registry = "https://pypi.org/simple" }
609
+ dependencies = [
610
+ { name = "regex" },
611
+ { name = "requests" },
612
+ ]
613
+ sdist = { url = "https://files.pythonhosted.org/packages/66/62/167a842aa0429d45f5e797354fd4343a96f6043d67d0513c675c7b8d36e6/tiktoken-0.14.0.tar.gz", hash = "sha256:231dec90efcdccf1b565a1416107736f1e09b1a08fe736ef9d6363e626d03874", size = 38898, upload-time = "2026-08-17T19:49:49.514Z" }
614
+ wheels = [
615
+ { url = "https://files.pythonhosted.org/packages/0b/35/e9f47647c9e163bd1de30fe1a491669b7248cfc67b7404c35c009a701e1a/tiktoken-0.14.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:7db45b98e94adf4173a5cd7422b150999a7ee11ff847783a14f6e1b80cc38cb6", size = 1186355, upload-time = "2026-08-17T19:48:51.93Z" },
616
+ { url = "https://files.pythonhosted.org/packages/d4/9c/7035b0bcfaa68d1ee4803fc5be5214ad865669b05bd20e7105ae8a18afc6/tiktoken-0.14.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b950248272f1b303dc32986396e2dccfa10cf6d1e83ec8f0bba1776660305482", size = 1250635, upload-time = "2026-08-17T19:48:54.392Z" },
617
+ ]
618
+
619
+ [[package]]
620
+ name = "tokenizers"
621
+ version = "0.22.2"
622
+ source = { registry = "https://pypi.org/simple" }
623
+ dependencies = [
624
+ { name = "huggingface-hub" },
625
+ ]
626
+ sdist = { url = "https://files.pythonhosted.org/packages/73/6f/f80cfef4a312e1fb34baf7d85c72d4411afde10978d4657f8cdd811d3ccc/tokenizers-0.22.2.tar.gz", hash = "sha256:473b83b915e547aa366d1eee11806deaf419e17be16310ac0a14077f1e28f917", size = 372115, upload-time = "2026-01-05T10:45:15.988Z" }
627
+ wheels = [
628
+ { url = "https://files.pythonhosted.org/packages/d6/84/7990e799f1309a8b87af6b948f31edaa12a3ed22d11b352eaf4f4b2e5753/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2249487018adec45d6e3554c71d46eb39fa8ea67156c640f7513eb26f318cec7", size = 3290736, upload-time = "2026-01-05T10:40:32.165Z" },
629
+ { url = "https://files.pythonhosted.org/packages/1d/28/5f9f5a4cc211b69e89420980e483831bcc29dade307955cc9dc858a40f01/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:29c30b83d8dcd061078b05ae0cb94d3c710555fbb44861139f9f83dcca3dc3e4", size = 9478245, upload-time = "2026-01-05T10:41:04.053Z" },
630
+ ]
631
+
632
+ [[package]]
633
+ name = "torch"
634
+ version = "2.10.0"
635
+ source = { registry = "https://pypi.org/simple" }
636
+ dependencies = [
637
+ { name = "filelock" },
638
+ { name = "fsspec" },
639
+ { name = "jinja2" },
640
+ { name = "networkx" },
641
+ { name = "setuptools" },
642
+ { name = "sympy" },
643
+ { name = "typing-extensions" },
644
+ ]
645
+ wheels = [
646
+ { url = "https://files.pythonhosted.org/packages/cc/af/758e242e9102e9988969b5e621d41f36b8f258bb4a099109b7a4b4b50ea4/torch-2.10.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:5fd4117d89ffd47e3dcc71e71a22efac24828ad781c7e46aaaf56bf7f2796acf", size = 145996088, upload-time = "2026-01-21T16:24:44.171Z" },
647
+ ]
648
+
649
+ [[package]]
650
+ name = "torchao"
651
+ version = "0.15.0"
652
+ source = { registry = "https://pypi.org/simple" }
653
+ wheels = [
654
+ { url = "https://files.pythonhosted.org/packages/f6/3b/6b9d5618720f63dbc2e2509cd6b57aae9c0d61b738d1d2172f4d5d9efaab/torchao-0.15.0-py3-none-any.whl", hash = "sha256:3f3812676048ef8a2a0e9d492d12d8971ba7a7ebb16f54aa56f690414e130d2c", size = 1080679, upload-time = "2025-12-18T23:14:43.807Z" },
655
+ ]
656
+
657
+ [[package]]
658
+ name = "tqdm"
659
+ version = "4.70.0"
660
+ source = { registry = "https://pypi.org/simple" }
661
+ sdist = { url = "https://files.pythonhosted.org/packages/21/3b/6c24bec5be5e743ffd99576daa5cc077722fc7d5bbc00bd133fa0c698dc6/tqdm-4.70.0.tar.gz", hash = "sha256:55b0b0dbd97462d06ebee91e4dac24ed4d4702be82b24f07e6c1d27e08cea220", size = 795438, upload-time = "2026-07-27T11:33:15.271Z" }
662
+ wheels = [
663
+ { url = "https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl", hash = "sha256:7f585706bfddbdebf89daac705b2dfcc16890130727d3197ca62c732b4310953", size = 80184, upload-time = "2026-07-27T11:33:13.167Z" },
664
+ ]
665
+
666
+ [[package]]
667
+ name = "transformers"
668
+ version = "4.57.1"
669
+ source = { registry = "https://pypi.org/simple" }
670
+ dependencies = [
671
+ { name = "filelock" },
672
+ { name = "huggingface-hub" },
673
+ { name = "numpy" },
674
+ { name = "packaging" },
675
+ { name = "pyyaml" },
676
+ { name = "regex" },
677
+ { name = "requests" },
678
+ { name = "safetensors" },
679
+ { name = "tokenizers" },
680
+ { name = "tqdm" },
681
+ ]
682
+ sdist = { url = "https://files.pythonhosted.org/packages/d6/68/a39307bcc4116a30b2106f2e689130a48de8bd8a1e635b5e1030e46fcd9e/transformers-4.57.1.tar.gz", hash = "sha256:f06c837959196c75039809636cd964b959f6604b75b8eeec6fdfc0440b89cc55", size = 10142511, upload-time = "2025-10-14T15:39:26.18Z" }
683
+ wheels = [
684
+ { url = "https://files.pythonhosted.org/packages/71/d3/c16c3b3cf7655a67db1144da94b021c200ac1303f82428f2beef6c2e72bb/transformers-4.57.1-py3-none-any.whl", hash = "sha256:b10d05da8fa67dc41644dbbf9bc45a44cb86ae33da6f9295f5fbf5b7890bd267", size = 11990925, upload-time = "2025-10-14T15:39:23.085Z" },
685
+ ]
686
+
687
+ [[package]]
688
+ name = "typing-extensions"
689
+ version = "4.16.0"
690
+ source = { registry = "https://pypi.org/simple" }
691
+ sdist = { url = "https://files.pythonhosted.org/packages/f6/cc/6253133b5bb138fc3306cebfbda2c520f545d36b5be2c7255cc528bb45d6/typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5", size = 113555, upload-time = "2026-07-02T08:40:05.92Z" }
692
+ wheels = [
693
+ { url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571, upload-time = "2026-07-02T08:40:04.659Z" },
694
+ ]
695
+
696
+ [[package]]
697
+ name = "urllib3"
698
+ version = "2.7.0"
699
+ source = { registry = "https://pypi.org/simple" }
700
+ sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" }
701
+ wheels = [
702
+ { url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" },
703
+ ]
704
+
705
+ [[package]]
706
+ name = "whisper-small-int8-xnnpack-executorch-runtime"
707
+ version = "0.1.0"
708
+ source = { virtual = "." }
709
+ dependencies = [
710
+ { name = "executorch" },
711
+ { name = "numpy" },
712
+ { name = "soundfile" },
713
+ { name = "torch" },
714
+ { name = "transformers" },
715
+ ]
716
+
717
+ [package.metadata]
718
+ requires-dist = [
719
+ { name = "executorch", specifier = "==1.1.0" },
720
+ { name = "numpy", specifier = "==2.5.2" },
721
+ { name = "soundfile", specifier = "==0.13.1" },
722
+ { name = "torch", specifier = "==2.10.0" },
723
+ { name = "transformers", specifier = "==4.57.1" },
724
+ ]