跳到主要内容
图和字,凭什么落在同一张地图上

图和字,凭什么落在同一张地图上

画唠
画唠

· 阅读约 5 分钟

EmbeddingGemma 2,这个月六号发的。7.4 亿参数,Apache 2.0,设备端多模态嵌入。初代下载量过了 2000 万,做端侧搜索和隐私 RAG 的人基本人手一个。

参数、基准、跑分,这些网上已经有了。我想画开的是发布说明里一带而过的那几个字——同一个空间。

看着像句废话。但整个多模态嵌入里真正难的,就这一处。

第一版我画错了

第一版我把多模态嵌入画成这样:

  文本 ──► 文本编码器 ──► 向量 A ─┐
                                 ├──► 比较??
  图像 ──► 视觉编码器 ──► 向量 B ─┘

画完我盯着看了半天,越看越不对。

画的时候脑子里只有"文本一个、图像一个"这两样东西,压根没想过它们各自住在哪儿。图看着挺对称,问题就藏在那个对称里。

那个"比较"——向量 A 和向量 B 是两个编码器各自吐出来的,压根不在同一个坐标系里。这就像拿一把量衣服的软尺去量体重,两个数你都拿到了,但你没法比。

我还给这个错找了个挺像回事的理由:反正都是向量,算个余弦相似度不就行了。

不行。两个不同空间里训出来的向量,连长度的含义都不一样,余弦值算出来是多少纯属运气。我盯着那两个箭头看了半天,脑内只有羊叫。

重来

正确的画法是这样:

  文本 ──┐
         │
  图像 ──┼──► 共享的编码过程 ──►  ┌─── 一张地图 ───┐
         │                        │   · 猫的照片    │
  音频 ──┤                        │   · "cat"      │
         │                        │   · 一声喵      │
  视频 ──┘                        └────────────────┘

这个版本看着没第一版对称,但它才是对的。

"同一个空间"就是字面意思:这些点真的被放在同一张地图上,位置挨着。猫的照片、"cat"、一声喵叫,落点很近——所以你能拿一句文本去检索几小时的音频。✨

咔哒一下扣上了。这玩意儿真的挺酷——费劲的从来不是"能编码图像",加个编码器就行;费劲的是让图像的坐标和文本的坐标可比。这一步得在整个训练过程里一路拧过去,不是最后拼一下就有了。

(我第一版真的以为它是最后拼一下就有了。不然呢,两个编码器都训好了,接根线不就完了。)

顺手把那 7.4 亿拆开:纯文本 2.7 亿,视觉编码器 1.7 亿,音频编码器 3 亿。三个模块加一块,换的就是这张共享地图。

等等,先别急。我一开始以为这三个数是"必须全加载"的意思。不是。模块化的好处恰恰是纯文本场景只跑那 2.7 亿——你手机上的相册搜索,不需要先把音频编码器读进内存。

这张地图能塞进手机,靠的是把地址写短

768 维的向量,一条 float32 大概 3KB。几万条就上 G 了。

EmbeddingGemma 2 用了 Matryoshka 表示学习,官方说法是输出向量能从 768 维动态截到 512、256、128,本地向量库和内存占用最多缩到六分之一。

这个我第一版也想岔了。我以为"截断"等于"降精度丢信息",跟把照片压成低分辨率差不多。

换个比方你立刻明白:向量维度的截断更像写地址。

  128 维 ──► 广东省深圳市南山区
  256 维 ──► 广东省深圳市南山区科技园
  768 维 ──► 广东省深圳市南山区科技园科苑路 15 号 B 座 302

你只想找"同一个城市的人",写城市就够了,后面几十个字不写也能比。截断不是把尾巴砍掉让它不可读,是你本来就不需要那么精细。

这个比喻漏风的地方得标出来:真实地址的层级是人为规定的行政划分,跟信息量没关系;而 MRL 里"前面几维更重要"不是天然的,是被训练目标显式逼出来的。模型学完之后,前 128 维才真的扛得住。

也就是说,这是训练换来的,不是向量自带的属性。它叫 Matryoshka 也是这个意思——套娃一层包一层,剥掉外层,里面那层还在。

8K 上下文,跟你想的不是一回事

上下文窗口支持 8K token,初代的 4 倍。官方给了几个换算:约 5.5 分钟音频、29 张图像、58 个视频帧,或者它们的交错组合。

这几个数看着平常,但对着 LLM 的 context window 一照就有意思了。

LLM 那个上下文是摊在桌上让你读的,读多少用多少。嵌入模型的 8K 完全不是这回事——它要被压进一个向量里。5.5 分钟音频,最后压成 768 个数。整个过程是有损压缩。

这里我卡了一会儿:同样叫 8K,为什么一个能逐句翻,一个不能。想通的点是"读"和"压"是两个动作——摊在桌上的,你随时能回头重读任意一行;压成一个向量的,回头已经没有那一行了。

所以别指望它去做"整段会议纪要逐句索引",做不到。它给你的是一个整体语义的坐标,不是句级索引。想逐句检索还是得分段编码——这个坑我猜不少人在第一次拿嵌入做检索的时候就踩过。

Pixel 11 Pro 上,量化后纯文本权重大约占 191MB 活动内存,全多模态大约 567MB。前者大概是 App 缓存级别的存在。

想直接上手摸一下这东西是什么感觉,Google AI Edge Gallery 里有现成的:Instant Media Search 用文字或者图片在你的媒体库里按语义挑最接近的,Video Moments Finder 用一句话定位视频里的某一刻。装上跑一遍,比我在这儿画一百张图都直观。

哦对,MTEB Code 上它从 68.76 涨到 78.68。一个多模态模型,代码检索比纯文本前辈高了将近 10 分。这事我到现在也没完全想明白。

自检

现在回头看"同一个空间"这五个字,你能不能用一句话给同行讲清楚它难在哪?如果讲到"两个编码器各出各的向量"就卡住——那你跟我第一版犯的是同一个错。

下期想画开哪个?我手里有个正在绕的:音频编码器要 3 亿参数,视觉编码器只要 1.7 亿。按直觉图像比声音复杂得多,这个比例我一直觉得不对劲。先放这儿,等我真画明白了再画给你看。

画唠
画唠

把被讲玄的概念用图 + 比喻 + 动手实验拆到咔哒扣明白,错的也保留。

查看主页 →