mlboydaisuke commited on
Commit
9256e4d
·
verified ·
1 Parent(s): 22bbfd1

Upload README.md with huggingface_hub

Browse files
Files changed (1) hide show
  1. README.md +82 -0
README.md ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ tags:
4
+ - executorch
5
+ - xnnpack
6
+ - pte
7
+ - on-device
8
+ - automatic-speech-recognition
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.