mlboydaisuke commited on
Commit
2b3ec4d
Β·
verified Β·
1 Parent(s): e4c7702

Upload README.md with huggingface_hub

Browse files
Files changed (1) hide show
  1. README.md +41 -59
README.md CHANGED
@@ -9,84 +9,66 @@ tags:
9
  base_model:
10
  - openai/whisper-tiny
11
  ---
12
- # Whisper-tiny β€” ExecuTorch XNNPACK (encoder + decoder)
13
 
14
- Speech recognition in two `.pte` files: the encoder runs once per 30-second window,
15
- the decoder once per generated token.
 
16
 
17
- | graph | precision | file | size (MB) | corr vs fp32 eager |
18
- |-------|-----------|------|-----------|--------------------|
19
- | encoder | fp32 | `whisper_tiny_encoder_xnnpack_fp32.pte` | 32.9 | 1.000000 |
20
- | encoder | fp16 | `whisper_tiny_encoder_xnnpack_fp16.pte` | 17.6 | 0.999999 |
21
- | encoder | int8 | `whisper_tiny_encoder_xnnpack_int8.pte` | 11.7 | 0.999454 |
22
- | decoder | fp32 | `whisper_tiny_decoder_xnnpack_fp32.pte` | 198.0 | 1.000000 |
23
- | decoder | fp16 | `whisper_tiny_decoder_xnnpack_fp16.pte` | 99.1 | 0.999988 |
 
 
24
 
25
- Every file takes and returns fp32 tensors (token ids stay int64), so any encoder
26
- pairs with any decoder. The lightest working pair is 110.8 MB.
27
 
28
  - **Source**: [openai/whisper-tiny](https://huggingface.co/openai/whisper-tiny)
29
  - **License**: Apache-2.0
30
- - **Encoder input**: log-mel spectrogram `[1,80,3000]` β€” 30 s at 16 kHz, 80 mel bins,
31
- hop 160, window 400. This is exactly what `WhisperFeatureExtractor` produces; pad
32
- or trim audio to 30 s as it does.
33
- - **Encoder output**: `encoder_hidden_states [1,1500,384]`
34
- - **Decoder input**: the encoder output plus `decoder_input_ids [1,128]` int64,
35
- left-aligned and padded. Start the sequence with
36
- `<|startoftranscript|>`, a language token, `<|transcribe|>`, `<|notimestamps|>`.
37
- - **Decoder output**: `logits [1,128,51865]`
38
 
39
  ## Decoding
40
 
41
- There is no KV cache. The decoder is a static graph over a fixed 128-token window,
42
- so a greedy step is: take `argmax` of row `len-1`, append it, run again. Stop at
43
- `<|endoftext|>` (50257). 128 tokens covers a 30-second window of ordinary speech
44
- with room to spare; for longer audio, start a new window.
45
 
46
- That costs a full 128-position forward pass per token. On a 37M-parameter model
47
- this is cheap enough to be practical, and it keeps the graph static β€” which is what
48
- lets the same file run unchanged across runtimes and precisions.
49
 
50
  ## Verification (Mac arm64, executorch 1.4.0, torch 2.13.0)
51
 
52
- The two wrappers compose back to `WhisperForConditionalGeneration` exactly
53
- (max_abs_diff 0.000e+00), and every graph matches torch fp32 eager at the
54
- correlations in the table above.
55
-
56
- Median over 5 runs, Mac arm64 single process β€” a relative reference, not a device
57
- number: encoder 54.5 ms (torch eager 20.5 ms), decoder 18.1 ms (eager 12.1 ms).
58
 
59
  ## Two things worth knowing about the sizes
60
 
61
- **The decoder .pte is larger than the decoder's weights.** Its parameters come to
62
- 118 MB, and the file is 198 MB. Whisper ties `proj_out.weight` to
63
- `decoder.embed_tokens.weight` β€” one 19.9M-parameter tensor β€” but the two uses need
64
- different representations in the `.pte`: an embedding table the portable kernels
65
- index into, and the same values packed into the XNNPACK delegate's blob for the
66
- output matmul. Tying them in PyTorch does not tie them here, and referencing the
67
- embedding weight directly through `F.linear` does not either.
68
-
69
- **The decoder has no int8 build.** PT2E puts an observer on the int64
70
- `decoder_input_ids` feeding the token embedding, and the lookup then refuses a float
71
- index (`tensors used as indices must be long, int, byte or bool`). The encoder takes
72
- float mel input and quantizes without complaint, which is where the size is worth
73
- taking anyway.
74
-
75
- ## Conversion
76
 
77
- torch.export β†’ to_edge_transform_and_lower(XnnpackPartitioner) β†’ .pte
78
- (conversion script: [executorch-models](https://github.com/john-rocky/executorch-models))
79
 
80
- The ExecuTorch tree ships a single-graph Whisper example under
81
- `examples/models/whisper`. This is that model with the halves separated, because a
82
- combined graph re-encodes the audio on every decoded token.
83
 
84
- <!-- funnel:v1 -->
85
-
86
- ---
87
 
88
- **More models in this format:** [ExecuTorch Model Zoo](https://huggingface.co/collections/mlboydaisuke/executorch-model-zoo-6a7ff328390b63075ffeae5e) β€” 31 models, each with the recipe that produced it.
 
 
89
 
90
- **Want a different model on-device?** [Open a request](https://github.com/john-rocky/on-device-requests) β€” free, open weights only; the export and its measured numbers get published publicly.
 
91
 
92
- <!-- /funnel:v1 -->
 
9
  base_model:
10
  - openai/whisper-tiny
11
  ---
12
+ # Whisper-tiny β€” ExecuTorch (encoder + decoder)
13
 
14
+ Speech recognition in two `.pte` files: the encoder runs once per 30-second window, the
15
+ decoder once per generated token. Putting them in one graph would re-encode the audio on
16
+ every step.
17
 
18
+ | graph | build | file | size (MB) | corr vs fp32 eager | ms | eager ms |
19
+ |---|---|---|---|---|---|---|
20
+ | encoder | XNNPACK fp32 | `whisper_tiny_encoder_xnnpack_fp32.pte` | 32.9 | 1.000000 | 60.2 | 22.1 |
21
+ | encoder | XNNPACK fp16 | `whisper_tiny_encoder_xnnpack_fp16.pte` | 17.6 | 1.000000 | 110.5 | 22.8 |
22
+ | encoder | XNNPACK int8 | `whisper_tiny_encoder_xnnpack_int8.pte` | 11.7 | 0.999439 | 58.9 | 22.0 |
23
+ | encoder | Core ML | `whisper_tiny_encoder_coreml_all.pte` | 16.6 | 0.999992 | 13.5 | 22.3 |
24
+ | decoder | XNNPACK fp32 | `whisper_tiny_decoder_xnnpack_fp32.pte` | 198.0 | 1.000000 | 20.6 | 11.9 |
25
+ | decoder | XNNPACK fp16 | `whisper_tiny_decoder_xnnpack_fp16.pte` | 99.1 | 0.999991 | 48.7 | 12.1 |
26
+ | decoder | Core ML | `whisper_tiny_decoder_coreml_all.pte` | 59.3 | 0.999892 | 3.0 | 11.8 |
27
 
28
+ Every file takes and returns fp32 tensors (token ids stay int64), so any encoder pairs with
29
+ any decoder. The lightest working pair is 71.0 MB.
30
 
31
  - **Source**: [openai/whisper-tiny](https://huggingface.co/openai/whisper-tiny)
32
  - **License**: Apache-2.0
33
+ - **Encoder input**: log-mel spectrogram `[1, 80, 3000]` β€” 30 s at 16 kHz, 80 mel bins, hop
34
+ 160, window 400, exactly what `WhisperFeatureExtractor` produces
35
+ - **Decoder input**: the encoder output plus `decoder_input_ids [1, 128]` int64,
36
+ left-aligned and padded. Start with `<|startoftranscript|>`, a language token,
37
+ `<|transcribe|>`, `<|notimestamps|>`.
 
 
 
38
 
39
  ## Decoding
40
 
41
+ No KV cache: the decoder is a static graph over a fixed 128-token window, so a greedy step
42
+ is take `argmax` of row `len-1`, append it, run again. Stop at `<|endoftext|>` (50257). 128
43
+ tokens covers a 30-second window of ordinary speech; past that, start a new window.
 
44
 
45
+ That costs a full 128-position forward pass per token, which is the price of a static graph
46
+ that runs unchanged across runtimes and precisions.
 
47
 
48
  ## Verification (Mac arm64, executorch 1.4.0, torch 2.13.0)
49
 
50
+ The two wrappers compose back to `WhisperForConditionalGeneration` exactly β€” max_abs_diff
51
+ **0.000e+00** β€” and every graph matches torch fp32 eager at the correlations above. Timings
52
+ are medians over 5 runs in one process: a relative reference, not a device number.
 
 
 
53
 
54
  ## Two things worth knowing about the sizes
55
 
56
+ **The decoder `.pte` is larger than the decoder's weights.** Whisper ties `proj_out.weight`
57
+ to `decoder.embed_tokens.weight`, but the two uses need different representations: an
58
+ embedding table the portable kernels index into, and the same values packed into the XNNPACK
59
+ delegate's blob for the output matmul. Tying them in PyTorch does not tie them here.
60
+ Referencing the weight through `F.linear` instead of the `proj_out` module does not either β€”
61
+ exported both ways, whisper-tiny's decoder comes out at 198.0 MB exactly.
 
 
 
 
 
 
 
 
 
62
 
 
 
63
 
 
 
 
64
 
65
+ ## Conversion
 
 
66
 
67
+ ```bash
68
+ python convert/export_whisper.py tiny
69
+ ```
70
 
71
+ The ExecuTorch tree ships a single-graph Whisper example under `examples/models/whisper`;
72
+ this is that model with the halves separated.
73
 
74
+ (conversion scripts: [executorch-models](https://github.com/john-rocky/executorch-models))