File size: 6,598 Bytes
32cf15e c539d8f 32cf15e c539d8f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | ---
language:
- en
- multilingual
license: apache-2.0
library_name: codon
pipeline_tag: feature-extraction
tags:
- audio
- speech
- whisper
- encoder
- feature-extraction
- safetensors
---
# Whisper-Tiny Audio Encoder (codon format)
Encoder-only weights of [openai/whisper-tiny](https://huggingface.co/openai/whisper-tiny),
re-keyed into the naming convention used by the
[codon](https://github.com/CodonProject/codon-model) library so they can be loaded into
`codon.block.model.WhisperTinyAudioEncoder` with a single call.
This is a **feature extractor**, not a speech-to-text model: the decoder and the
tokenizer are intentionally **not** included, so it cannot transcribe audio on its own.
## Files
| File | Size | Tensors | Description |
|---|---|---|---|
| `whisper_tiny_encoder.safetensors` | 15.7 MB | 67 | Encoder weights, **fp16**, codon key convention |
## Model details
| | |
|---|---|
| Architecture | Whisper encoder (pre-LN Transformer, bidirectional self-attention) |
| Parameters | 8,208,384 (8.21M) |
| `d_model` | 384 |
| Encoder layers | 4 |
| Attention heads | 6 (head dim 64) |
| FFN dim | 1536, GELU |
| Mel bins | 80 |
| Max positions | 1500 |
| Output | `[B, T/2, 384]` for input mel `[B, 80, T]` |
| Precision | fp16 (upcast to fp32 on load for fp32 execution) |
| License | Apache-2.0 |
## Requirements
```bash
pip install codon-model==0.0.7b8
```
Source: [CodonProject/codon-model](https://github.com/CodonProject/codon-model)
## Usage
```python
import torch
from codon.block.model import WhisperTinyAudioEncoder
encoder = WhisperTinyAudioEncoder(pool_stride=1)
encoder.load('whisper_tiny_encoder.safetensors', strict=True)
encoder = encoder.float() # weights are fp16; upcast for fp32 execution
encoder.eval()
mel = torch.randn(1, 80, 3000) # 30 s of log-mel @ 100 Hz
with torch.no_grad():
hidden, _ = encoder(mel)
print(hidden.shape) # torch.Size([1, 1500, 384])
```
Half-precision execution is also supported — just call `.half()` and feed a
half-precision mel instead (expect a larger numerical drift, ~6e-2, since the
arithmetic itself runs in fp16):
Loading straight from this repository:
```python
encoder = WhisperTinyAudioEncoder().from_remote()
```
### Downsampling for LLM consumption
The raw encoder emits one token per 20 ms (50 tokens/s), which is usually far too
dense for a language model. `pool_stride` appends a non-overlapping average pool
after the encoder (weights are unaffected):
```python
encoder = WhisperTinyAudioEncoder(pool_stride=8)
encoder = encoder.float()
with torch.no_grad():
hidden, _ = encoder(torch.randn(1, 80, 3000))
print(hidden.shape) # torch.Size([1, 187, 384]) -> 6.25 tokens/s
```
## Tensor naming
Keys follow the codon convention (`proj_*` for projections). The full layout:
```
conv1.weight (384, 80, 3)
conv1.bias (384,)
conv2.weight (384, 384, 3)
conv2.bias (384,)
embed_positions.weight (1500, 384)
layers.{0..3}.attn_norm.weight (384,)
layers.{0..3}.attn_norm.bias (384,)
layers.{0..3}.attn.proj_q.weight (384, 384)
layers.{0..3}.attn.proj_q.bias (384,)
layers.{0..3}.attn.proj_k.weight (384, 384) # no bias
layers.{0..3}.attn.proj_v.weight (384, 384)
layers.{0..3}.attn.proj_v.bias (384,)
layers.{0..3}.attn.proj_o.weight (384, 384)
layers.{0..3}.attn.proj_o.bias (384,)
layers.{0..3}.fn_norm.weight (384,)
layers.{0..3}.fn_norm.bias (384,)
layers.{0..3}.mlp.proj_fc1.weight (1536, 384)
layers.{0..3}.mlp.proj_fc1.bias (1536,)
layers.{0..3}.mlp.proj_fc2.weight (384, 1536)
layers.{0..3}.mlp.proj_fc2.bias (384,)
norm.weight (384,)
norm.bias (384,)
```
Note that `proj_k` has **no bias** — this mirrors the original Whisper design
(its `k_proj` is the only projection without a bias in both the encoder and the
decoder). The positional table uses Whisper's own layout: `weight[:, :192]` holds
sine values and `weight[:, 192:]` holds cosine values for
`inv_freq = exp(-log(10000) * arange(192) / 192)`.
## Provenance and verification
Weights are copied from `openai/whisper-tiny` (`model.encoder.*`), renamed, and
saved as fp16. No values were modified: converting the fp32 export to fp16 and back
to fp32 is bit-exact element-wise, i.e. the source values already only carried fp16
precision (max absolute weight magnitude is ~16, well inside fp16 range).
The codon implementation was verified against the official `transformers`
implementation (`WhisperModel(...).encoder`) with both models loading the same
checkpoint (upcast to fp32) and consuming the same input:
| mel length | output shape | max abs difference |
|---|---|---|
| 3000 | `[2, 1500, 384]` | 5.9e-05 |
| 1000 (padded) | `[2, 500, 384]` | 3.9e-05 |
| 512 (padded) | `[2, 256, 384]` | 2.2e-05 |
Differences are at fp32 rounding level, not implementation differences.
## Limitations
- **Encoder only.** No decoder, no vocabulary, no tokenizer — cannot produce text.
- **Fixed 30 s input.** Whisper pads every input to 3000 mel frames. Short clips
must be zero-padded to 3000 and the padded output frames discarded; the padded
region does influence the valid region through convolution and LayerNorm, so it
is not equivalent to running the encoder on a shorter input.
- **Not causal / not streaming.** The encoder is bidirectional and stateless, so it
cannot be used for incremental streaming without recomputing a full window.
- **Precision.** Tensors are stored as fp16. The fp32 -> fp16 -> fp32 round trip is
element-wise exact, so no information was lost relative to the source export, and
running the model in fp32 after upcasting reproduces the fp32 reference exactly.
Native fp16 execution (`model.half()`) is supported but introduces the usual
half-precision drift (~6e-2 on this model).
## Citation
If you use these weights, please cite the original work:
```bibtex
@misc{radford2022whisper,
doi = {10.48550/ARXIV.2212.04356},
url = {https://arxiv.org/abs/2212.04356},
author = {Radford, Alec and Kim, Jong Wook and Xu, Tao and Brockman, Greg and McLeavey, Christine and Sutskever, Ilya},
title = {Robust Speech Recognition via Large-Scale Weak Supervision},
publisher = {arXiv},
year = {2022},
copyright = {arXiv.org perpetual, non-exclusive license}
}
```
## Acknowledgements
Original model by OpenAI. This repository only re-keys the encoder weights for use
with [codon](https://github.com/CodonProject/codon-model).
|