File size: 21,485 Bytes
305fc2a
80c945e
dfe210b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
305fc2a
 
dfe210b
305fc2a
80c945e
 
305fc2a
dfe210b
 
 
80c945e
 
 
dfe210b
 
 
 
 
 
80c945e
 
dfe210b
 
 
 
80c945e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
305fc2a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80c945e
dfe210b
 
 
 
 
 
 
 
305fc2a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80c945e
 
 
 
 
 
 
 
 
 
 
 
dfe210b
80c945e
 
 
dfe210b
305fc2a
 
 
 
 
 
 
 
dfe210b
 
 
 
 
 
 
 
 
 
 
 
 
305fc2a
 
dfe210b
 
 
80c945e
 
 
 
 
305fc2a
 
 
 
 
 
80c945e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
EmbeddingGemma-2-CoreAI v1.2
============================

This package contains a derivative of the EmbeddingGemma 2 model.

    EmbeddingGemma 2
    Authors: Google DeepMind (as stated on the model card)
    https://huggingface.co/google/embeddinggemma-2
    License as linked by the model card: Apache 2.0, https://ai.google.dev/gemma/docs/gemma_4_license
    Licensed under the Apache License, Version 2.0 (the "License"); you may not use these files except in
    compliance with the License. A copy of the License is in the file LICENSE and at
    http://www.apache.org/licenses/LICENSE-2.0.
    Unless required by applicable law or agreed to in writing, software distributed under the License is
    distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

The model card of google/embeddinggemma-2 asks that deployments adhere to the Gemma Prohibited Use Policy:
https://ai.google.dev/gemma/prohibited_use_policy. Please read it before using this model in a product.

The tokenizer files in model/tokenizer/ (tokenizer.json, tokenizer_config.json) are copied unchanged from
google/embeddinggemma-2 and are covered by the same license and attribution.


MODIFICATIONS (Apache License, Section 4(b))
--------------------------------------------

Changes made to google/embeddinggemma-2, 11-12 October 2026, to produce model/embeddinggemma-2-text-mm.aimodel,
model/embeddinggemma-2-vision.aimodel and model/embeddinggemma-2-audio.aimodel.

Text encoder (v1.0, unchanged in v1.1 and v1.2 except where noted):

  2026-10-11  The audio encoder of the multimodal checkpoint was dropped (v1.0 also dropped the vision
              encoder; v1.1 adds the vision encoder back and v1.2 the audio encoder, see below).
  2026-10-11  The encoder architecture (24 bidirectional Gemma 4 layers, per-layer embeddings, RMSNorm with
              max-abs rescaling, RoPE, GQA/MQA attention, GELU-tanh MLP, final RMSNorm, 512->768 projection,
              masked mean pooling, L2 normalization) was re-authored in plain PyTorch for the Core AI
              converter. The weights are the original ones rounded from bfloat16 to float16, except that the
              sqrt(512) token-embedding scale and the 512^-0.5 per-layer-embedding scale are folded into the
              tables.
  2026-10-11  fp16 handling for the Neural Engine: every RMSNorm and the final L2 normalization divide the row
              by its max-abs value before squaring (activations reach ~2000, whose square overflows fp16);
              in the model code every division is expressed as rsqrt(x)*rsqrt(x); the additive attention-mask
              value is -10000. (The model card advises against float16; this rescaling is what makes fp16
              safe here, see the parity figures in README.md.)
  2026-10-11  Pooling, projection and normalization run inside the graph; the output is the final embedding.
  2026-10-11  Fixed sequence buckets, one function per bucket. Input longer than 2048 tokens is not supported
              by this build (the original accepts 8192).
  2026-10-12  Attention of the four global (full-attention, single key/value head) layers rewritten from a
              5-D grouped matmul to an equivalent plain 4-D matmul with the key/value tensors broadcast over
              the four query heads, so that the Neural Engine compiler accepts the whole graph. Mathematically
              identical to the reference (fp32 max abs diff 3e-7).

Added in v1.1:

  2026-10-12  Text: one input mix at the start of the graph, x = embed(input_ids) * (1 - mm_mask) +
              mm_embeds * mm_mask, so that externally computed image soft tokens replace the <|image|>
              placeholder embeddings. Soft tokens are not scaled; everything after the mix is the v1.0 text
              graph, and with zero soft tokens the outputs are bit-identical to v1.0. The functions are now
              mm_<S> for S in 32, 64, 128, 288, 512, 1024, 2048 (288 replaces 256 so that one image sequence of
              at most 284 tokens fits). This asset replaces v1.0's model/embeddinggemma-2-text.aimodel.
  2026-10-12  Vision encoder (Gemma 4 vision model: patch embedder, 16 bidirectional encoder layers with axial
              2-D RoPE, 3x3 average pooling) and the vision embedder (RMSNorm + 768->512 projection) re-authored
              in plain PyTorch for the Core AI converter. The weights are the original ones rounded from
              bfloat16 to float16, with the scale fold and table cut described in the next entries (the 2/255
              input scale folded into the patch-embedding projection, the position tables cut to 840 rows).
  2026-10-12  Vision: one fixed shape, the default budget of 280 soft tokens (2520 patches of 16x16 px). The
              patches are fed in "cell-major" order (the 9 patches of each 3x3 pooling cell contiguous, cells
              row-major, padding last) so that the pooling is a reshape and a mean instead of a one-hot matmul.
              Attention is permutation-equivariant, so the result is identical.
  2026-10-12  Vision: the pooler's multiplication by sqrt(768) (computed in float32 upstream because it exceeds
              the float16 range) is dropped and the vision embedder's RMSNorm uses eps/768 instead of eps:
              RMSNorm(x*s, eps) == RMSNorm(x, eps/s^2) exactly.
  2026-10-12  Vision: the 2-D position-embedding tables (2 x 10240 x 768) are cut to the 840 rows that an image
              of this budget can address; the axial-RoPE cos/sin tables and the key mask are inputs computed by
              the host instead of being computed in the graph.
  2026-10-12  Vision fp16 handling for the Neural Engine: every RMSNorm divides the row by its max-abs value
              before squaring (the vision residual reaches ~1400), divisions are expressed as rsqrt(x)*rsqrt(x),
              the additive key-mask value is -10000, the 3x3 mean is a sum times 1/9. The attention queries are
              processed in 12 blocks (same result, lower Neural Engine latency).
  2026-10-12  Vision input scaling: the model takes integer pixel values 0..255 (exact in float16) instead of
              pixel/255. The graph computes P - 127.5 and the 2/255 factor is folded into the weights of the
              patch-embedding projection, which equals upstream's projection of 2*(P/255) - 1 without rounding
              the inputs to float16 (that rounding cost heavily upscaled tiny images up to 0.004 of cosine).
  2026-10-12  Image preprocessing (host side, not part of the model): the upstream image processor's
              aspect-preserving size rule and its antialiased bicubic resize on 8-bit pixels (the ATen uint8
              kernel used by torchvision) re-implemented in numpy and in Swift so that the pixels fed to the
              model are identical to the reference pipeline.

Added in v1.2:

  2026-10-12  Audio encoder (Gemma 4 audio model: two stride-2 subsampling convolutions with channel LayerNorm,
              a 1024->1024 projection, 12 conformer layers of half-step feed-forward, local causal attention with
              relative-position bias, light depthwise convolution, half-step feed-forward and RMSNorm, the
              1024->1536 output projection) and the audio embedder (RMSNorm without scale + 1536->512 projection)
              re-authored in plain PyTorch for the Core AI converter. The weights are the original ones rounded
              from bfloat16 to float16, with the scale folds listed below.
  2026-10-12  Audio attention written in its banded form: the upstream chunked local attention (chunks of 12,
              13 of left context, pad / unfold / rel-shift) lets every token see itself and the 11 previous
              tokens; the port computes exactly those 12 logits per token, logit[t, d] = q_t . (k_{t-d} +
              relk_d), where relk_d = relative_k_proj(sinusoid(d)) is precomputed per layer as a constant. The
              query scale (128^-0.5 / ln 2 times softplus(per_dim_scale)) and the key scale (ln(1 + e) / ln 2)
              are folded into q_proj / k_proj and their output clip bounds. The masked_fill(-1e9) of padded keys
              is an additive -10000; the gradient-clipping clamps (+-1e10, no-ops in inference) are dropped; the
              120 clipped linears keep their clip bounds. Mathematically identical to the reference (fp32
              soft-token cosine >= 0.99999998 on 213 clips, max abs diff 8e-4).
  2026-10-12  Audio fp16 handling for the Neural Engine: every RMSNorm (including the scale-free one of the
              audio embedder) divides the row by its max-abs value before squaring (the residual stream reaches
              ~412), divisions are expressed as rsqrt(x)*rsqrt(x), the logit softcap is tanh(x/50)*50.
  2026-10-12  Audio: fixed frame buckets 192, 384, 1024, 1536 and 3000 frames of 10 ms (functions audio_<Tb>);
              inputs longer than 30 s are truncated by the host, as upstream does by default. The three masks
              (frames, after the first convolution, tokens) are host inputs. The bucket set is limited to the
              sizes validated on the Neural Engine.
  2026-10-12  Audio preprocessing (host side, not part of the model): the upstream feature extractor's log-mel
              computation (30 s truncation, 160-sample left pad, 320-sample periodic Hann frames every 160
              samples, 512-point magnitude FFT, 128 HTK mel bands 0-8000 Hz without normalization, ln(mel +
              0.001), frame validity rule) re-implemented in numpy and in Swift; the mono mix (mean of the
              channels) as librosa does it; resampling to 16 kHz with a Kaiser-windowed sinc low-pass of our own
              (pass band 0.913 and stop band 1.0 of the lower Nyquist, 125 dB) instead of the libsoxr "HQ"
              resampler that librosa.load uses upstream (the only intended deviation from upstream in the audio
              pipeline; README gives the measured difference).

  2026-10-11/12  Converted with coreai-torch 0.4.3 / coreai-core 1.0.0b3 on torch 2.9.0 to the Core AI
              .aimodel format (macOS 27).

The exporter in export/ reproduces these changes from the original checkpoint.


THIRD-PARTY ATTRIBUTIONS
------------------------

HF transformers (Apache-2.0; Copyright 2026 The HuggingFace Team for the modeling, configuration and image-processing
files named below, Copyright 2026 Google LLC for feature_extraction_gemma4.py, Copyright 2023 The HuggingFace Inc.
team and the librosa & torchaudio authors for audio_utils.py). export/eg2_text.py re-authors the
architecture described by modeling_embedding_gemma2.py / configuration_embedding_gemma2.py, export/eg2_vision.py
the vision model and vision embedder, and export/eg2_audio.py the audio model (Gemma4AudioModel) and audio
embedder, all described by modeling_gemma4.py / modeling_embedding_gemma2.py, from transformers 5.19. The
host-side image preprocessing (python/eg2_image.py, swift/Sources/EmbeddingGemma2CoreAI/ImagePreprocessor.swift)
ports the logic of image_processing_gemma4.py, including its aspect-preserving size rule
(`get_aspect_ratio_preserving_size`); the host-side audio front end (python/eg2_audio_frontend.py,
swift/Sources/EmbeddingGemma2CoreAI/AudioFrontend.swift) re-implements the log-mel feature extraction described by
feature_extraction_gemma4.py with the defaults sentence-transformers uses for this model, and the HTK mel filter
bank formula (as in librosa / torchaudio) of transformers' audio_utils.py (HTK scale, no normalization). No
transformers source files are included in this package; the re-authored and ported modules carry their own
Apache-2.0 header and credit transformers.

librosa (ISC) and libsoxr (LGPL-2.1+) are what upstream uses to load and resample audio files; neither is included,
and no librosa or libsoxr code is ported; the HTK mel filter formula above is the one librosa and torchaudio also
implement (credited through transformers' audio_utils.py). The resampler in this package is our own design (a
Kaiser-windowed sinc, see MODIFICATIONS); the decode-mono-resample order and the output-length rule follow what
librosa.load does, re-implemented from its documented behaviour.

PyTorch / ATen (BSD-3-Clause, notice below). The integer antialiased bicubic resize in python/eg2_image.py and
swift/Sources/EmbeddingGemma2CoreAI/ImageResampler.swift is ported from the logic of ATen's uint8
`_upsample_bicubic2d_aa` kernel (aten/src/ATen/native/cpu/UpSampleKernel.cpp: the tap-index and weight helpers
`_compute_indices_min_size_weights_aa` / `_compute_index_ranges_int16_weights`, the dynamic int16 precision and
the separable uint8 passes), which torchvision uses for `resize(..., BICUBIC, antialias=True)`. No PyTorch
source file is included; the port is translated to numpy and Swift.

Pillow (MIT-CMU / HPND, notice below). The ATen kernel above is itself modelled on Pillow's Resample.c, and
the CMYK -> RGB conversion in swift/Sources/EmbeddingGemma2CoreAI/ImageDecoder.swift is ported from Pillow's
conversion formula so that CMYK files embed like the reference. No Pillow source file is included. The Python
runner uses Pillow to decode images; it is not redistributed.

FluidInference Core ML port of EmbeddingGemma 2 (Apache-2.0, https://huggingface.co/FluidInference). The idea of
dividing each RMSNorm row by its max-abs value to keep fp16 in range was taken from the README of that port and
re-derived independently; no code was copied from it. Nothing else in this package derives from it.

Apple Core AI (coreai-torch, coreai-core, the CoreAI framework), ImageIO, Core Graphics, AVFoundation / AudioToolbox
(audio decoding) and Accelerate (vDSP FFT and dot products): used as tools and runtime, not redistributed. Hugging
Face tokenizers (Apache-2.0): used by the Python runner and to generate the test fixtures; not redistributed.
python-soundfile / libsndfile (BSD-3-Clause / LGPL-2.1+): audio decoder of the Python runner (installed by
python/requirements.txt, not redistributed) and the decoder of the audio reference fixtures; not redistributed.
eSpeak NG (GPL-3.0-or-later): used as a tool to synthesize the spoken test clips (tests/make_test_audio.py); no part
of it is included. FFmpeg with libmp3lame (LGPL / GPL): used as a tool to encode the MP3 test clips and to decode
AAC for the reference fixtures; not included.


TRADEMARKS
----------

Gemma and EmbeddingGemma are trademarks of Google LLC. Apple, Core AI, Apple silicon and Neural Engine are
trademarks of Apple Inc. This port is not affiliated with, sponsored by or endorsed by Google or Apple.


OUR OWN CODE
------------

Everything in this package that is not the model weights or the tokenizer files, i.e. the exporter
(export/), the Python runner (python/), the Swift library and command-line tool (swift/), the tests, test
images and test audio clips (tests/) and the documentation, is

    Copyright 2026 Everpaper
    Licensed under the Apache License, Version 2.0 (LICENSE).

The parts ported from transformers, PyTorch and Pillow (see THIRD-PARTY ATTRIBUTIONS) also remain subject to
those projects' licenses: Apache-2.0 for transformers (LICENSE), and the PyTorch and Pillow notices reproduced
below.

The test texts, test images and test audio clips are written, rendered or synthesized from code (tests/make_*.py).
The people, companies, products, numbers and events in them are invented; a few real place names and common
words that are also brand names (for example in the chart and invoice test images) appear only as fictional
content, with no reference to any real business. The spoken clips are invented sentences synthesized with the
eSpeak NG formant synthesizer, which generates speech from rules and formant parameters rather than from voice
recordings; no recording of a person is included or was used.


THIRD-PARTY LICENSE NOTICES
---------------------------

Reproduced as their licenses require, for the ported logic described under THIRD-PARTY ATTRIBUTIONS.

PyTorch (BSD-3-Clause), from the LICENSE file of PyTorch 2.9.0:

    From PyTorch:

    Copyright (c) 2016-     Facebook, Inc            (Adam Paszke)
    Copyright (c) 2014-     Facebook, Inc            (Soumith Chintala)
    Copyright (c) 2011-2014 Idiap Research Institute (Ronan Collobert)
    Copyright (c) 2012-2014 Deepmind Technologies    (Koray Kavukcuoglu)
    Copyright (c) 2011-2012 NEC Laboratories America (Koray Kavukcuoglu)
    Copyright (c) 2011-2013 NYU                      (Clement Farabet)
    Copyright (c) 2006-2010 NEC Laboratories America (Ronan Collobert, Leon Bottou, Iain Melvin, Jason Weston)
    Copyright (c) 2006      Idiap Research Institute (Samy Bengio)
    Copyright (c) 2001-2004 Idiap Research Institute (Ronan Collobert, Samy Bengio, Johnny Mariethoz)

    From Caffe2:

    Copyright (c) 2016-present, Facebook Inc. All rights reserved.

    All contributions by Facebook:
    Copyright (c) 2016 Facebook Inc.

    All contributions by Google:
    Copyright (c) 2015 Google Inc.
    All rights reserved.

    All contributions by Yangqing Jia:
    Copyright (c) 2015 Yangqing Jia
    All rights reserved.

    All contributions by Kakao Brain:
    Copyright 2019-2020 Kakao Brain

    All contributions by Cruise LLC:
    Copyright (c) 2022 Cruise LLC.
    All rights reserved.

    All contributions by Tri Dao:
    Copyright (c) 2024 Tri Dao.
    All rights reserved.

    All contributions by Arm:
    Copyright (c) 2021, 2023-2024 Arm Limited and/or its affiliates

    All contributions from Caffe:
    Copyright(c) 2013, 2014, 2015, the respective contributors
    All rights reserved.

    All other contributions:
    Copyright(c) 2015, 2016 the respective contributors
    All rights reserved.

    Caffe2 uses a copyright model similar to Caffe: each contributor holds
    copyright over their contributions to Caffe2. The project versioning records
    all such contribution and copyright details. If a contributor wants to further
    mark their specific copyright on a particular contribution, they should
    indicate their copyright solely in the commit message of the change when it is
    committed.

    All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright
       notice, this list of conditions and the following disclaimer.

    2. Redistributions in binary form must reproduce the above copyright
       notice, this list of conditions and the following disclaimer in the
       documentation and/or other materials provided with the distribution.

    3. Neither the names of Facebook, Deepmind Technologies, NYU, NEC Laboratories America
       and IDIAP Research Institute nor the names of its contributors may be
       used to endorse or promote products derived from this software without
       specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGE.


Pillow (MIT-CMU / HPND), from the LICENSE file of Pillow 12.3.0:

    The Python Imaging Library (PIL) is

        Copyright © 1997-2011 by Secret Labs AB
        Copyright © 1995-2011 by Fredrik Lundh and contributors

    Pillow is the friendly PIL fork. It is

        Copyright © 2010 by Jeffrey 'Alex' Clark and contributors

    Like PIL, Pillow is licensed under the open source MIT-CMU License:

    By obtaining, using, and/or copying this software and/or its associated
    documentation, you agree that you have read, understood, and will comply
    with the following terms and conditions:

    Permission to use, copy, modify and distribute this software and its
    documentation for any purpose and without fee is hereby granted,
    provided that the above copyright notice appears in all copies, and that
    both that copyright notice and this permission notice appear in supporting
    documentation, and that the name of Secret Labs AB or the author not be
    used in advertising or publicity pertaining to distribution of the software
    without specific, written prior permission.

    SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
    SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
    IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR BE LIABLE FOR ANY SPECIAL,
    INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
    LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
    OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
    PERFORMANCE OF THIS SOFTWARE.