IP-Adapter FaceID:用面部特征向量做身份保持,和纯文本描述人脸有什么本质区别

我最早试 AI 写真的时候,有个问题特别困扰我:我在提示词里写了我的五官、发型、甚至具体到“左眼角有颗痣”,但跑出来的四张图,四张脸,每一张都“有点像”但没一张是“我”。后来我换了个工具,它让我上传一张照片,再给一段提示词,出来的结果身份稳得吓人。同一个姿势换三套衣服,脸还是那张脸。这中间到底发生了什么?

AI technology illustration

不是那个工具用了什么黑魔法,而是它把“描述人”换成了“锚定人”——用一个 512 位的向量把你这个人钉死在了生成空间里。这个向量就是本文的主角:面部特征向量(face embedding)。而 IP-Adapter FaceID 是让它能在 Stable Diffusion 里工作的关键机制。

“大眼睛高鼻梁”和“这个人”之间隔着什么

我们先看纯文本描述人脸时,模型到底拿到了什么。你的提示词会先被分词器切成 token,再通过文本编码器(通常是 CLIP 的 text encoder)变成一串 token embedding。这一串向量虽然也有 77 个(CLIP 的固定长度),但内容是高度语义化的:它知道你说了“国字脸”,但它不知道你的脸宽具体是多少厘米、颧骨和下颌线之间是什么夹角。

也就是说,文本描述是一个离散符号的压缩包,它只保留人类语言能表达的粗粒度特征,并且总会丢失那个把你和路人区分开的信息。我在知乎上看到很多人问“为什么 AI 画的人总是一张网红脸”——因为“网红脸”在文本空间里恰好是这些粗粒度特征的统计中心,模型生成时自然往那个中心挤。

而面部特征向量走的是另一条路。它由人脸识别模型(比如 ArcFace)在数百万人的照片上训练出来的。ArcFace 做的事情是:把一张人脸图像映射到一个 512 维的单位球面上,让同一个人不同照片的向量靠近,不同人的向量远离。这个向量不是“描述”,而是身份坐标系里的一个坐标点。坐标的每一维都不是“眼睛大小”这种语义,而是某种组合后的判别特征——可能是颅骨结构、眼距比例、五官之间的相对位置等数值。

IP-Adapter 到底在做什么

IP-Adapter 是腾讯 ARC 实验室 2023 年 8 月提出的一种给扩散模型加图像条件的方法,论文标题很直白:IP-Adapter: Text Compatible Image Prompt Adapter for Text-to-Image Diffusion Models。它的核心改动在交叉注意力层。

原始 Stable Diffusion 里,生成图像时每个像素(其实是每个 latent 位置)都会去和 77 个文本 token 做交叉注意力,决定“这里应该响应用户提示词的哪个部分”。IP-Adapter 做了一个解耦交叉注意力:保留原来的文本分支,在旁边额外加一个图像分支。图像分支也生成 query、key、value,但是 key 和 value 来自你输入图像的 embedding。两个分支的结果相加后再进入后续网络。

说人话:以前模型只有一根天线去接收“你想画什么”的信息,现在有两根了——一根继续听文字,另一根直接看图。这样你可以在保留原版模型文本控制能力的同时,用一张参考图去控制“像谁”或者“什么风格”。

FaceID:把参考图换成一张脸的坐标

IP-Adapter 原始版本用的是 CLIP 的图像编码器,它提取的是整张图的语义,包含场景、物体、风格,也包含人脸的粗略信息,但不够专门。如果你把参考图换成一个人的脸部照片,CLIP embedding 虽然也记住了“这是某个人”,但身份信息被压缩得不够狠,生成结果经常跟你亲妈都认不出来。

于是后来 InstantX 团队(和腾讯合作)发布了 IP-Adapter-FaceID。它的思路非常直接:告诉 CLIP 你歇会儿,这次我们用人脸识别模型 ArcFace 来提取向量。具体操作是:

  1. 把输入的人脸照片喂给 ArcFace,得到 512 维的 face embedding。
  2. 用一个可训练的投影层(一个全连接层)把这个向量映射到 IP-Adapter 图像分支需要的维度。
  3. 这个投影后的向量作为 cross-attention 里的 key 和 value,注入到生成过程的每一层。

就这么简单。但这里有个很微妙的点:face embedding 和 text embedding 维度不一样,而且它只有一个向量(不像文本有 77 个 token)。IP-Adapter 一般的实现里图像分支输入的是从参考图特征里提取出来的多个 token,而 FaceID 只给了一个全局身份向量。这意味着你放弃了参考图的所有像素细节,只保留了“这是谁”这一个信息

这反而是个优点:因为身份信息被压缩成一个很干净的向量,表情、光照、角度等噪声全部被丢掉了,模型在生成时可以自由发挥这些非身份属性。你给它戴眼镜,它就给你戴眼镜;你让它笑,它就笑——但脸部的骨架和五官比例被那个向量牢牢锁住。

到底有什么本质区别

你现在应该能理解为什么文本描述做不到身份保持:语言没有足够的分辨率。比如“鹰钩鼻”——这个描述在人类语义里是一个区间,覆盖了成千上万个不同弧度。但 ArcFace 向量给的是精确到小数点后六位的一组坐标,在这个空间里,你和跟你长得像的人之间的距离可能是 0.3,而大模型生成时哪怕误差只有 0.1,换个人你就认不出来了。

我用一个表格总结一下二者的全维度对比:

维度 纯文本描述 面部特征向量(IP-Adapter FaceID)
信息来源 自然语言,离散符号 真实人脸图像,连续像素
编码器 CLIP text encoder ArcFace 等识别模型
输出形态 77 个 token 的语义序列 单个 512 维向量
信息粒度 粗粒度、可描述、可编辑 细粒度、判别性、不可描述
身份保持能力 弱,容易漂移 强,锚定稳定
表情/姿态可控性 高(能直接写) 高(向量不含这些信息)
可解释性 高(知道每个词是什么意思) 低(512 维不可读)

注意最后一行:face embedding 是个黑盒。你没法反推“这个维度的值变大了,鼻子就会变挺”。这也是 FaceID 的一大痛点——你想要微调长相,只能改提示词加形容词,或者用别的 LoRA,但向量本身是不可编辑的。这跟文本描述恰好互补:文本擅长修改属性,向量擅长锁定身份。

我踩过的坑:用 CLIP embedding 冒充 face embedding

我第一次实现 IP-Adapter 的时候,手头没有现成的 FaceID 权重,就自作聪明地用了 CLIP image encoder 提取人脸,再喂给 IP-Adapter。结果生成的图人物是“稳定”了——稳定地像十个人拼在一起。我一度以为是 IP-Adapter 不好使,后来翻回论文看到一张示意图,才知道问题出在特征空间上。

CLIP 的训练目标是“图片描述对匹配”,它学到的空间里,两个人即使长得像,只要身份不同,向量距离也没有按人的相似度排列。ArcFace 专门用人脸 ID 做分类训练,它的空间里同一个人不同照片的距离被拉得非常近,而不同人被强制推开。用错编码器,等于你想定位一个人的“身份坐标”,却给了你一张“世界地图”,坐标精度差了几个数量级。

后来我换用官方权重(它内置了 ArcFace 提取器),效果立竿见影。这件事让我明白:IP-Adapter 只是个“管道”,管道里流什么向量,决定了下游效果的天花板。FaceID 最聪明的地方不是发明了新架构,而是发现了“该用什么液体流过这条管道”。

FaceID 的边界在哪里

当然,FaceID 不是万能的。它有一个先天缺陷:ArcFace 向量只保证“身份接近”,不保证“脸型像素级相似”。你拿一张正面照做参考,如果参考图只有 100 像素的脸,提取出的身份向量照样能保持“像”,但生成出来的可能更像“和这个人长得很像的另一个人”——因为向量里丢掉了一些细节,比如特定伤疤、眉形尾端的细微上挑。

何况 ArcFace 本身也有偏见,训练数据里白种人脸占比高,亚洲人、非洲人的身份向量区分度会略差。我看过一些测试,用同样的参数跑不同人种,保持度有明显差异。这个问题至今没有完全解决,FaceID-PlusV2 试图引入 CLIP 局部特征来弥补,但变复杂了,也更容易让模型过拟合参考图。

另外,FaceID 和文本描述不是二选一,实际工作流里两者是配合的——文中已有的文本分支负责写“穿西装坐在办公室里”,FaceID 分支负责“使他是我”。如果你只靠 face embedding 不写提示词,模型能生成一百万张风格各异但长得跟你很像的人,场景和光线全乱飘。反过来,只靠文本描述,你得到的是“一千个人眼里的一千个大眼睛高鼻梁”。

所以当你想让 AI 稳定地复现一个人的脸时,别再用形容词堆砌了。去找一张够清晰、够正面的照片,让 ArcFace 替你把它变成坐标,剩下的交给 IP-Adapter。你会突然理解:语言的极限,恰好是数字的开始

原创文章,作者:guanweilu,如若转载,请注明出处:https://guanweilu.cn/article/669.html

(0)
上一篇 10小时前
下一篇 10小时前

相关推荐