Add audio: EmbeddingGemma2Audio (USM conformer, log-mel in-graph, GPU fp16, 617x real time)
Browse files
EmbeddingGemma2Audio.mlpackage/Data/com.apple.CoreML/model.mlmodel
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:d40896e5c88d62b02d15cc975f27e254c28a5774a1702e09bf5483071623548d
|
| 3 |
+
size 1059089
|
EmbeddingGemma2Audio.mlpackage/Data/com.apple.CoreML/weights/weight.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:41d7b552caabe376e377dcbe1c8c5f9879853bc4f384a161bb1f886f19e84b56
|
| 3 |
+
size 586817408
|
EmbeddingGemma2Audio.mlpackage/Manifest.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"fileFormatVersion": "1.0.0",
|
| 3 |
+
"itemInfoEntries": {
|
| 4 |
+
"33C920C7-8DF5-410F-BC71-B016FF1BDAB6": {
|
| 5 |
+
"author": "com.apple.CoreML",
|
| 6 |
+
"description": "CoreML Model Weights",
|
| 7 |
+
"name": "weights",
|
| 8 |
+
"path": "com.apple.CoreML/weights"
|
| 9 |
+
},
|
| 10 |
+
"53956E94-BB15-4BE5-A123-E22EABB7D9A9": {
|
| 11 |
+
"author": "com.apple.CoreML",
|
| 12 |
+
"description": "CoreML Model Specification",
|
| 13 |
+
"name": "model.mlmodel",
|
| 14 |
+
"path": "com.apple.CoreML/model.mlmodel"
|
| 15 |
+
}
|
| 16 |
+
},
|
| 17 |
+
"rootModelIdentifier": "53956E94-BB15-4BE5-A123-E22EABB7D9A9"
|
| 18 |
+
}
|
README.md
CHANGED
|
@@ -24,6 +24,9 @@ Output: the same 768-d, L2-normalized embedding as `SentenceTransformer("google/
|
|
| 24 |
(mean pooling over tokens, then normalization). Matryoshka truncation to 512/256/128 works as in the original: keep
|
| 25 |
the first N values and re-normalize.
|
| 26 |
|
|
|
|
|
|
|
|
|
|
| 27 |
## Files
|
| 28 |
|
| 29 |
| File | What |
|
|
@@ -31,7 +34,8 @@ the first N values and re-normalize.
|
|
| 31 |
| `EmbeddingGemma2Text.mlpackage` | ML Program, fp16, 7 functions sharing one set of weights (271 MB) |
|
| 32 |
| `embeddings.bf16` | token embedding table, 262,144 × 512 raw bfloat16 (256 MB); look up rows, multiply by √512 |
|
| 33 |
| `tokenizer.json` | the original Gemma tokenizer, unchanged |
|
| 34 |
-
| `
|
|
|
|
| 35 |
|
| 36 |
## Functions
|
| 37 |
|
|
@@ -50,6 +54,25 @@ mask is all the model needs.
|
|
| 50 |
`pack_256` runs up to eight short texts in one call. Short calls are bound by streaming the weights from memory, so
|
| 51 |
one 256-token call with eight texts costs about the same as two single calls.
|
| 52 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 53 |
## Use
|
| 54 |
|
| 55 |
1. Prepend the task prefix (e.g. `title: none | text: ` for documents, `task: search result | query: ` for queries;
|
|
|
|
| 24 |
(mean pooling over tokens, then normalization). Matryoshka truncation to 512/256/128 works as in the original: keep
|
| 25 |
the first N values and re-normalize.
|
| 26 |
|
| 27 |
+
**Audio** (added): `EmbeddingGemma2Audio.mlpackage` turns 10 s of 16 kHz audio into 250 tokens in the text model's
|
| 28 |
+
space; the text functions then embed them, so audio and text share one space (search audio with a text query).
|
| 29 |
+
|
| 30 |
## Files
|
| 31 |
|
| 32 |
| File | What |
|
|
|
|
| 34 |
| `EmbeddingGemma2Text.mlpackage` | ML Program, fp16, 7 functions sharing one set of weights (271 MB) |
|
| 35 |
| `embeddings.bf16` | token embedding table, 262,144 × 512 raw bfloat16 (256 MB); look up rows, multiply by √512 |
|
| 36 |
| `tokenizer.json` | the original Gemma tokenizer, unchanged |
|
| 37 |
+
| `EmbeddingGemma2Audio.mlpackage` | audio encoder (Gemma 4 USM conformer, 12 layers) + projection, fp16, log-mel in-graph (561 MB) |
|
| 38 |
+
| `config.json` | shapes, function list, token ids, task prefixes, audio window layout |
|
| 39 |
|
| 40 |
## Functions
|
| 41 |
|
|
|
|
| 54 |
`pack_256` runs up to eight short texts in one call. Short calls are bound by streaming the weights from memory, so
|
| 55 |
one 256-token call with eight texts costs about the same as two single calls.
|
| 56 |
|
| 57 |
+
## Audio
|
| 58 |
+
|
| 59 |
+
`EmbeddingGemma2Audio.mlpackage`: `waveform` [1, 160160] fp32 (160 zero samples, then up to 10 s of 16 kHz mono,
|
| 60 |
+
zero-padded) and `frame_mask` [1, 1000] (frame i valid when `i*160 + 321 <= 160 + samples`) → `audio_tokens`
|
| 61 |
+
[1, 250, 512]; token k is valid when `frame_mask[4k]` is. Build `<bos> <|audio> tokens <audio|> <eos>` (special
|
| 62 |
+
tokens from `embeddings.bf16` × √512, audio tokens as they are) and run `embed_256`. Log-mel (Gemma 4 feature
|
| 63 |
+
extractor: 20 ms Hann frames, 10 ms hop, 128 HTK mel bins, log(mag + 1e-3)) is computed inside the model.
|
| 64 |
+
|
| 65 |
+
Run it on the **GPU** (`cpuAndGPU`): the chunked local attention's 5-D blocks fall back to the CPU on the Neural
|
| 66 |
+
Engine (46 ms per window there vs 13.6 ms on the GPU). fp16 drifts from fp32 on a few quiet tokens (window embedding
|
| 67 |
+
cos ≥ 0.977, mean 0.9993); on a 1-hour earnings-call index, the top hit matched fp32 for 15/15 text queries and the
|
| 68 |
+
top-5 overlap was 95%.
|
| 69 |
+
|
| 70 |
+
| 1 hour of audio, M5 Pro | Time |
|
| 71 |
+
|---|---|
|
| 72 |
+
| audio model (GPU, fp16) | 5.8 s (617× real time) |
|
| 73 |
+
| audio model + text model, one window after another | 10.2 s (353×) |
|
| 74 |
+
| fp32 audio model (exact to PyTorch, token cos 1.0000) | 13.2 s (272×) |
|
| 75 |
+
|
| 76 |
## Use
|
| 77 |
|
| 78 |
1. Prepend the task prefix (e.g. `title: none | text: ` for documents, `task: search result | query: ` for queries;
|
config.json
CHANGED
|
@@ -1,19 +1,55 @@
|
|
| 1 |
{
|
| 2 |
"base_model": "google/embeddinggemma-2",
|
| 3 |
"format": "coreml",
|
| 4 |
-
"modality":
|
|
|
|
|
|
|
|
|
|
| 5 |
"precision": "fp16",
|
| 6 |
"hidden_size": 512,
|
| 7 |
"embedding_dim": 768,
|
| 8 |
-
"matryoshka_dims": [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
"embed_scale": 22.627417,
|
| 10 |
-
"token_table": {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
"functions": {
|
| 12 |
-
"embed_32": {
|
| 13 |
-
|
| 14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
},
|
| 16 |
-
"bos_token_id": 2,
|
|
|
|
|
|
|
| 17 |
"prompts": {
|
| 18 |
"document": "title: none | text: ",
|
| 19 |
"search_query": "task: search result | query: ",
|
|
@@ -23,5 +59,21 @@
|
|
| 23 |
"classification": "task: classification | query: ",
|
| 24 |
"clustering": "task: clustering | query: ",
|
| 25 |
"sentence_similarity": "task: sentence similarity | query: "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
}
|
| 27 |
-
}
|
|
|
|
| 1 |
{
|
| 2 |
"base_model": "google/embeddinggemma-2",
|
| 3 |
"format": "coreml",
|
| 4 |
+
"modality": [
|
| 5 |
+
"text",
|
| 6 |
+
"audio"
|
| 7 |
+
],
|
| 8 |
"precision": "fp16",
|
| 9 |
"hidden_size": 512,
|
| 10 |
"embedding_dim": 768,
|
| 11 |
+
"matryoshka_dims": [
|
| 12 |
+
768,
|
| 13 |
+
512,
|
| 14 |
+
256,
|
| 15 |
+
128
|
| 16 |
+
],
|
| 17 |
"embed_scale": 22.627417,
|
| 18 |
+
"token_table": {
|
| 19 |
+
"file": "embeddings.bf16",
|
| 20 |
+
"dtype": "bfloat16",
|
| 21 |
+
"shape": [
|
| 22 |
+
262144,
|
| 23 |
+
512
|
| 24 |
+
]
|
| 25 |
+
},
|
| 26 |
"functions": {
|
| 27 |
+
"embed_32": {
|
| 28 |
+
"tokens": 32
|
| 29 |
+
},
|
| 30 |
+
"embed_48": {
|
| 31 |
+
"tokens": 48
|
| 32 |
+
},
|
| 33 |
+
"embed_64": {
|
| 34 |
+
"tokens": 64
|
| 35 |
+
},
|
| 36 |
+
"embed_128": {
|
| 37 |
+
"tokens": 128
|
| 38 |
+
},
|
| 39 |
+
"embed_256": {
|
| 40 |
+
"tokens": 256
|
| 41 |
+
},
|
| 42 |
+
"embed_512": {
|
| 43 |
+
"tokens": 512
|
| 44 |
+
},
|
| 45 |
+
"pack_256": {
|
| 46 |
+
"tokens": 256,
|
| 47 |
+
"slots": 8
|
| 48 |
+
}
|
| 49 |
},
|
| 50 |
+
"bos_token_id": 2,
|
| 51 |
+
"eos_token_id": 1,
|
| 52 |
+
"pad_token_id": 0,
|
| 53 |
"prompts": {
|
| 54 |
"document": "title: none | text: ",
|
| 55 |
"search_query": "task: search result | query: ",
|
|
|
|
| 59 |
"classification": "task: classification | query: ",
|
| 60 |
"clustering": "task: clustering | query: ",
|
| 61 |
"sentence_similarity": "task: sentence similarity | query: "
|
| 62 |
+
},
|
| 63 |
+
"audio": {
|
| 64 |
+
"package": "EmbeddingGemma2Audio.mlpackage",
|
| 65 |
+
"compute_units": "cpuAndGPU",
|
| 66 |
+
"precision": "fp16",
|
| 67 |
+
"sample_rate": 16000,
|
| 68 |
+
"window_seconds": 10,
|
| 69 |
+
"waveform_samples": 160160,
|
| 70 |
+
"left_pad_samples": 160,
|
| 71 |
+
"frames": 1000,
|
| 72 |
+
"frame_valid_if": "i * 160 + 321 <= 160 + audio_samples",
|
| 73 |
+
"tokens_per_window": 250,
|
| 74 |
+
"token_ms": 40,
|
| 75 |
+
"boa_token_id": 256000,
|
| 76 |
+
"eoa_token_id": 258883,
|
| 77 |
+
"text_sequence": "<bos> <|audio> [audio tokens] <audio|> <eos> -> embed_256"
|
| 78 |
}
|
| 79 |
+
}
|