alexwengg commited on
Commit
7438a5b
·
verified ·
1 Parent(s): 70fcf18

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
- | `config.json` | shapes, function list, token ids, task prefixes |
 
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": "text",
 
 
 
5
  "precision": "fp16",
6
  "hidden_size": 512,
7
  "embedding_dim": 768,
8
- "matryoshka_dims": [768, 512, 256, 128],
 
 
 
 
 
9
  "embed_scale": 22.627417,
10
- "token_table": {"file": "embeddings.bf16", "dtype": "bfloat16", "shape": [262144, 512]},
 
 
 
 
 
 
 
11
  "functions": {
12
- "embed_32": {"tokens": 32}, "embed_48": {"tokens": 48}, "embed_64": {"tokens": 64}, "embed_128": {"tokens": 128},
13
- "embed_256": {"tokens": 256}, "embed_512": {"tokens": 512},
14
- "pack_256": {"tokens": 256, "slots": 8}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  },
16
- "bos_token_id": 2, "eos_token_id": 1, "pad_token_id": 0,
 
 
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
+ }