PhotoMaker:单张照片就能生成一致性人物图像,它是怎么提取和保持身份特征的

你肯定见过这种生成图:一个 AI 画出来的美女,五官精致、光影完美,但你总感觉哪里不对——她不是你想生成的那个人。这种 "脸崩" 问题困扰了扩散模型很长时间。我最早以为换一个更强的基座模型就能解决,后来才意识到,问题不在画质,而在身份信息根本没有被正确表达。

AI technology illustration

2023 年底,腾讯 ARC 实验室发表了 PhotoMaker,声称只用一张照片,就能在不同场景里生成同一个人的图像,而且不需要像 DreamBooth 那样微调。我当时的反应是:又一个大饼?直到我读完 论文,发现它的思路确实绕开了微调这条路,而且绕得很聪明。

脸是怎么在扩散模型里丢掉的?

扩散模型的核心是文本引导。你给出一句话,模型在去噪过程中通过 cross-attention 把文本信息注入图像。关键问题是,文本描述一个具体的人时,粒度太粗了。"一个短发亚洲男性" 这句话信息量很大,但它不足以在像素级别还原一张具体的脸。

所以,当你用普通的 Stable Diffusion 生成 "一个像我的人" 时,模型只能根据文本联想起一个 "平均脸"。这个平均值,往往谁都不像。

早期解决办法是 DreamBooth:给模型出示几张你的照片,然后微调整个模型,让它把你这张脸记住。有效,但每个新身份都要重新训练,而且训练过程常常让人等得心焦。

PhotoMaker 换了一条路:不让模型记住你,而是让它现场看到你。

把一张脸变成提示词的一部分

PhotoMaker 最核心的操作,是把你的照片也变成提示词的一部分。具体流程可以分四步:

  1. 用 CLIP 图像编码器把你的照片分解成一组特征向量。
  2. 用一个轻量投影层,把这组向量映射到文本嵌入空间。
  3. 把这些向量当作特殊 token,拼在文本 token 序列的最前面。
  4. 拼接后的序列一起送入文本编码器,最后进入扩散模型的 cross-attention。

这里值得停下来细品的,是第三步里的 "特殊 token" 不是单个向量,而是整组向量。也就是说,你的照片被拆成了很多 patch,每个 patch 都有自己的 token。这些 token 按照顺序堆叠起来,论文里叫 Stacked ID Embedding

为什么堆叠比平均好?因为人脸身份信息高度分散在五官边缘、纹理、骨相等多个部位。如果只取一个全局向量,相当于把整张脸压缩成一个词,信息损失太大。

堆叠之后的 token 序列,会跟着文本一起通过 CLIP 文本编码器。身份 token 和文本 token 在编码器里进行注意力交互。你可能会问,为什么不直接像 IP-Adapter 那样把图像特征送进 UNet?PhotoMaker 的作者发现,把身份信息放在文本编码器里,让它先跟文本语义交互一遍,生成时对身份的把握会更自然。这也是它跟 IP-Adapter 的本质区别:一个是把图像特征作为独立通道,一个是把图像特征融进文本上下文。

模型是怎么学会"认脸"的?

你到这里可能还有个疑问:加入一堆图像 token 就能保持身份,这是怎么训练出来的?答案不在模型结构,而在数据构建。

PhotoMaker 的训练数据构建了一个 以身份为中心的生成任务

  • 用现成的人脸识别模型,从海量无标注数据中挖掘出同一个人的多张照片;
  • 用图像描述模型(类似 BLIP)为每张照片写一段提示词;
  • 随机抽出同一人的 1 到 N 张 照片作为条件,让模型生成这个人的另一张照片。
  • 训练时随机改变姿势、表情、服装甚至年龄相关描述,迫使模型区分"身份特征"和"非身份特征"。

这个策略的巧妙之处在于,模型需要学到的不是一个固定的人的 embeddings,而是一种能力:从照片里提取身份,并根据文本改写其他属性。因为训练时输入照片的数量是随机的,所以推理时只给一张也能工作——大不了少堆几个 token。

说白了,这种训练让模型学到的是"如何把身份特征从照片里抽出来,再根据文本把其他属性填回去",而不是记住某一个人的脸。

和同类方法放在一张桌上

方法 是否需要微调 身份信息如何进入模型 单张照片表现 主要短板
DreamBooth 需要,每个身份重新训练 更新模型权重 勉强 训练慢,容易降低文本可控性
LoRA 需要 低秩增量矩阵 先训练再使用 每身份一套权重,不便部署
IP-Adapter 不需要 图像特征单独进入 UNet 可以 图-文特征分离,文本遵从性弱
PhotoMaker 不需要 图像特征进入文本编码器 可以 极端角度、遮挡下身份崩坏

这个表不是想说 PhotoMaker 碾压一切。它是在告诉你,PhotoMaker 选择了零样本和文本交互这条路线,代价是对人脸细节的刻画精度不如专门的人脸识别特征。

实际用起来长得什么样

在 Diffusers 里,PhotoMaker 已经变成了一个现成的 pipeline(Hugging Face 模型)。简化后的调用大概是这样:

from diffusers import PhotoMakerStableDiffusionXLPipeline
import torch
from PIL import Image

pipe = PhotoMakerStableDiffusionXLPipeline.from_pretrained(
    'TencentARC/PhotoMaker',
    torch_dtype=torch.float16,
).to('cuda')

face = Image.open('me.jpg')
prompt = 'a woman with the same face, wearing a suit, photorealistic'

images = pipe(
    prompt=prompt,
    image=[face],
    num_images_per_prompt=1,
).images
images[0].save('output.png')

核心只有两个输入:照片和提示词。照片负责 "你是谁",提示词负责 "你在哪儿、穿什么、什么风格"。

它哪里还没做好?

PhotoMaker 不是万能钥匙。我拿它测过一些极端情况:侧脸超过 60 度、人脸占比很小、或者照片本身模糊。结果身份一致性会明显打折扣。原因在于 CLIP 图像编码器是在图文对齐任务上预训练的,它擅长捕捉 "这个人大概长什么样",但对像素级的细粒度人脸特征不敏感。

另外还有一个隐藏问题:身份 token 和文本 token 在同一个注意力上下文里,意味着当你试图描述某种夸张的新造型时,文本语义会 "污染"身份特征。论文里展示了它能改年龄、改风格,但假如提示词里写 "外星人",那张脸就很难保证了。

最后一点是数据隐私。构造训练数据时用的是大规模网络图像,其中很可能包含真实人物的照片。PhotoMaker 本身不对这一点做额外保护,使用时需要自己注意合规。

为什么效果不如人脸识别模型?

因为 CLIP 的目标是图像和文本对齐,不是人脸识别。人脸识别模型(比如 FaceNet)会在监督下强制把同一个人的特征拉近,而 CLIP 更关注语义类别。PhotoMaker 用 CLIP 是因为它天生和文本空间兼容;如果你要对同一人的身份进行高精度保留,需要换一种特征来源——这也是后来 InstantID 走的路。

是不是多给几张照片一定更好?

不一定。堆叠 2~3 张不同角度、表情的照片通常会提升稳定性,但如果几张照片光线差异过大,反而可能互相干扰。单张高质量正脸照往往已经能获得不错的结果。

回过头来看,PhotoMaker 最让我佩服的一点,是把身份从 需要微调的权重 变成了 可以直接输入的 token。这一小步,省去了大量计算成本,也让后续 Identity 相关方案有了一个新起点。如果你现在让我推荐身份保持方案,我会说:单图、快速、愿意和文本属性一起表达身份,PhotoMaker 是那个最顺手的选择;如果你的核心诉求是 "必须一毛一样",那多看看基于人脸识别特征的方法会更靠谱。

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

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

相关推荐