Identity Preservation
身份保持可确保特定人物或物体在生成的图像、视频帧和跟踪 ID 中始终能被识别为同一个体。
身份保持是指模型在其输出中持续将特定主体呈现为同一个体的能力:一组生成肖像中的同一张脸、生成视频从第一帧到最后一帧中的同一个角色,或行人走到巴士后面再出现时仍保持相同的跟踪 ID。两个领域都使用这个术语。在生成式 AI中,它指将真实人物或产品融入新场景而不改变其身份或特征的个性化方法。在多目标跟踪(MOT)中,它指在遮挡、交叉和摄像头切换期间保持每个物体的 ID 稳定。两个领域都会使用身份嵌入来衡量身份保持能力:同一个体的特征向量彼此接近,不同个体的特征向量彼此远离。
图像与视频生成中的身份保持#
文生图模型知道“一位女士”或“一只狗”是什么样子,却不知道某位特定女士或某只特定狗的样子,因此个性化方法会补充这方面的信息。微调方法通过少量照片学习主体特征。Google 的 DreamBooth(2022)会使用与稀有 token 绑定的主体三到五张图像,对整个扩散模型进行微调,并加入特定类别的先验保持损失,使模型仍能正常生成其他狗;LoRA 适配器则让相同思路的训练成本低到足以针对每个人进行训练。
基于编码器的方法无需针对每个主体单独训练。Tencent 的 IP-Adapter(2023)通过单独的交叉注意力层将图像嵌入输入扩散模型;InstantID(2024 年 1 月)则通过结合人脸识别网络生成的嵌入与 IdentityNet,从单张照片保持人脸身份。IdentityNet 是一个由五个人脸关键点提供条件的 ControlNet。更强的身份条件会让输出更像参考图,也会复制更多姿势、表情和光照特征,因此这些工具提供了强度设置,用于权衡相似度与提示改变场景的幅度。
生成的人脸通过参考照片和输出图像的 ArcFace 嵌入之间的余弦相似度进行评分。ArcFace 由 Jiankang Deng 及其同事在 CVPR 2019 上提出,它通过角度间隔训练人脸嵌入,使不同身份在超球面上清晰分离。视频还增加了第二项要求:在不同帧之间保持主体一致性;VBench 会比较帧间的 DINO 特征,并将其作为主体一致性指标。在视频生成中,如果角色的脸在几秒内逐渐变化,即使每一帧单独看起来都很逼真,也无法通过这项测试。
跟踪中的身份保持#
跟踪器通过将每帧中的检测结果与现有轨迹进行匹配来分配 ID。仅依靠运动信息——使用 Kalman 滤波器预测每个边界框的位置,再通过交并比(IoU)进行匹配——在两个人交叉或其中一人消失在障碍物后面之前都能正常工作;之后跟踪器就可能交换他们的 ID 或创建新的 ID,这种错误称为身份切换。外观特征可以修正其中许多问题。Nicolai Wojke、Alex Bewley 和 Dietrich Paulus 提出的 DeepSORT(2017)为仅依赖运动信息的 SORT 跟踪器加入了由人物重识别数据集训练的网络生成的嵌入,将身份切换减少了 45%。Ergys Ristani 及其同事于 2016 年提出的 IDF1 指标则直接衡量身份保持能力,即检测结果中被分配正确身份的比例。
Ultralytics YOLO 跟踪默认使用 TrackTrack(Shim 等人,CVPR 2025),它会让丢失的轨迹保持 30 帧 (track_buffer),以便重新出现的物体能够找回自己的 ID,并且会在创建新 ID 前抑制重复的新 ID。在跟踪器 YAML 中设置 with_reid: True 会启用外观匹配,默认使用检测器自身的特征,也可以选择专用编码器,例如拥有 280 万参数的 YOLO26n-reid 模型。下面的代码片段使用示例视频跟踪人物,分别启用和禁用 ReID,并统计每次运行分配的不同 ID 数量:
from ultralytics import YOLO
from ultralytics.utils import ROOT, YAML
# Copy the default TrackTrack config and turn on appearance re-identification
cfg = YAML.load(ROOT / "cfg/trackers/tracktrack.yaml")
cfg.update(with_reid=True, model="yolo26n-reid.onnx")
YAML.save("tracktrack_reid.yaml", cfg)
video = "https://github.com/ultralytics/assets/releases/download/v0.0.0/decelera_portrait_min.mov"
for tracker in ["tracktrack.yaml", "tracktrack_reid.yaml"]:
model = YOLO("yolo26n.pt") # fresh model so each run starts with no tracks
ids = set()
for result in model.track(video, tracker=tracker, classes=[0], stream=True, verbose=False):
if result.boxes.is_track:
ids.update(result.boxes.id.int().tolist())
print(f"{tracker}: {len(ids)} person IDs")在这段较短的视频中,两次运行都为人物分配了 3 个 ID,因此外观匹配在这里没有改变结果;但对于人物离开画面后又重新出现的较长视频,外观匹配就很重要。对于同一批人物,不同 ID 的数量越少,身份切换就越少,而下游计数依赖的正是这一点:客流计数系统若给返回的顾客分配新 ID,就会把这位顾客计算两次。










