为什么同样的16GB显卡,有人跑EmbeddingGemma 2顺顺当当,有人索引出来的结果却悄悄变差?答案不在显卡型号,而在三个设置。
![]()
EmbeddingGemma 2是Google DeepMind在10月6日以Apache 2.0协议发布的嵌入模型。嵌入模型把输入变成一串数字(这里是768个),语义相近的内容对应相近的数列,检索就变成"找最近的数列"。这个模型把文本、图像、视频和音频映射进同一个空间,下载包1.5 GB,参数量7.4亿。
有人把它部署在一块16 GB的NVIDIA RTX 2000 Ada上。加载本身不难,难的是三个设置——它们决定了向量是否正确、延迟是否合理。写索引任务之前,先把这三件事定下来。
一、数字格式选错,不报错但结果变差
GPU可以用紧凑的16位格式存数字,float16和bfloat16,把显存占用减半。但随权重一起发布的模型卡只允许bfloat16或float32。模型卡明确写道:在float16下,网络内部有些数值大到无法表示,结果是NaN或者悄悄退化的嵌入,而且不抛异常。放进检索索引里,就是程序不崩,排名变差。
模型卡给出的一行选型逻辑是:能用bfloat16就用bfloat16,否则退回float32,永远不用float16。在没有原生bfloat16支持的GPU上,float32回退需要两倍显存。所有实际运行都用了安全格式,所以float16的失败是Google的警告,不是复现出来的结果——那项测试还排在下一步。至少先确认你的技术栈实际加载的是哪种dtype。
二、容器只分到7核,PyTorch却开了64个线程
第一个后端处理图片比应有速度慢了两到五倍。性能分析显示,每张图GPU计算约72毫秒,CPU预处理却要0.33到0.44秒。容器的CPU配额(通过Linux cgroups设定的可用处理器份额)大约是7核,但PyTorch数到了宿主机的64核,于是起了64个线程去抢这7核。
把线程数限制到配额之后,单张图从531毫秒降到111毫秒,八张图从4333毫秒降到867毫秒,一段6秒视频从754毫秒降到307毫秒。文本和音频几乎没变化,所以只测文本的基准根本暴露不了这个问题。示例后端从cgroup配额推导线程数;没有配额时就得手动设。这个结论只在一个容器上验证过,建议按输入类型分别计时CPU预处理和GPU编码。
三、释放的显存不会还给系统
完整模型占用1.4 GB显存,只加载文本部分时是0.5 GB。单条请求峰值2.6 GB。批处理才是增长点:一次请求里放八份约6000 token的文档,峰值接近10 GB。
意外出现在请求结束之后。PyTorch会缓存已释放的显存以便复用,进程一直占着11.6 GB,直到重启。在超大请求之后调用torch.cuda.empty_cache()可以解决:同样一批数据跑完,进程占用回落到1.6 GB。做批量索引时,按你最大的批次来规划显存。
截短向量:速度不变,质量有代价
模型用Matryoshka表示学习训练,所以每个向量的前512、256或128个数字可以当作更小的嵌入使用。截短并没有更快——各种尺寸下每次查询都是34到35毫秒,省下的只有存储和传输体积。
质量损失取决于输入类型。模型卡称256维接近无损;到128维,文本还能撑住,图像和视频检索下降近四分之一,所以模型卡把128维留给文本。截短后要重新归一化(把向量缩放回长度1),并且查询和文档必须用同一尺寸嵌入。
这套测试证明了什么,没证明什么
测试索引里有十二个文件、零文本:照片、短视频和语音录音。六个英文查询各自把正确文件排在第一。"How to knead bread dough"匹配到一段西班牙语的面包食谱录音。十二个文件全部是生成的,所以这只能确认跨模态流程端到端跑通,不能说明模型与其他模型的优劣对比。
服务层面还有个坑:开源推理服务器vLLM在0.31.0版本时还不支持这个模型,连文本都不行,于是后端改用sentence-transformers写了个小的Python服务。Google的发布文章点名支持vLLM、SGLang、Ollama和llama.cpp,用之前先查当前版本。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.