最近在Hacker News上逛的时候,看到一个「Show HN」项目:AI Facial Attractiveness Model Aligned with Human Preferences,通俗说就是做一个“用人类偏好对齐出来的AI人脸吸引力模型”。这个方向我过去大半年一直在折腾,从第一批demo翻车到现在勉强能上线,中间踩的坑不少,今天想把这个项目的完整技术链路、设计取舍和边界思考一次性写清楚,给同样在做人脸美学、偏好对齐或者视觉AI排序的朋友做个参考。
先说结论:这个项目真正值钱的不是“让AI打分”这个动作,而是把“人类怎么看美丑”建模成可训练的偏好分布。市面上很多颜值打分demo,跑出来的分数跟人类直觉对不上,比如换个角度分数暴跌、给明星照片打低分、同一个人磨皮前后能差0.6分。根本原因就是模型学的是图像统计学特征,而不是人类偏好。所以这个项目把核心突破点放在了对齐(Alignment)上——不是训练一个“更准的评分模型”,而是训练一个“更接近人类偏好”的评分模型。
我下面会按技术动机、数据构建、模型训练、评估调优、伦理边界这五块来讲,每块都会给出我在实际项目中用到的方案和踩过的坑。如果你正在做人脸美学相关的研究或产品,或者对“人类偏好对齐”这个方法论感兴趣,这篇应该能帮你省掉至少一个月的试错时间。
1. 从“机器觉得美”到“人类觉得美”:这个项目的技术动机
1.1 直接训练回归模型的三大硬伤
我最早做这个项目时,想法特别简单:拿公开的SCUT-FBP 5500这类颜值评分数据集,用ResNet直接回归1-5分。当时觉得“打分任务能有多难”,结果跑通之后被现实狠狠教育了一顿。
第一个问题是“分数的方差”。同一个人的同一张照片,不同标注员给的分能差出1.5分以上。审美不是物理量,它是个体经验、文化背景和当下状态的叠加。拿这样的标签给模型做回归,模型学到的其实是标注员群体平均后的模糊值,而不是“美”本身。更麻烦的是,回归目标稍有噪声,模型loss就特别难降,而且会自动倾向于把所有人都打到中位数附近。
第二个问题是样本分布。真实人脸数据里,极端好看和极端不好看的样本都偏少,中间段扎堆。MSE回归天然要求目标分布均匀,一旦不均匀,模型就会牺牲少数群体换取整体均方误差降低。结果是:中等颜值样本预测得还行,真正有辨识度的高分和低分样本,预测结果被严重拉向平均。
第三个问题更隐蔽——模型会作弊。直接回归时,模型很容易学会去抓一些与“颜值”高度相关但并非因果的特征,比如清晰度、光照、磨皮程度、背景颜色。换句话说,它在用图像质量替代面部美学。我拿同一张脸的高清图和模糊图分别测试,分数能差0.4分,这在人眼看来完全不合理。这种情况在深度学习里特别常见,模型总会走捷径,除非你在设计目标函数时就把它堵住。
1.2 偏好对齐:把审美问题改写成排序问题
后来我换了个思路:不直接预测绝对分数,而是预测“相对偏好”。这个转变背后的逻辑是:人类对美的判断在绝对尺度上不稳定,但在相对比较上稳定得多。让一个人给照片打3分还是4分,可能取决于他上一张看的是什么;但让他从两张照片里挑出“更好看的那张”,一致性会显著提升。这其实和推荐系统、大模型RLHF里的思路是同一个——绝对答案难标注,相对偏好容易采集。
所以我把这个问题从回归任务改写成了排序任务:构造大量二维比较对(一张图比另一张图美),让模型学习一个隐含的分数函数f(x),使得对任意偏好对(A, B),都能有f(A)大于f(B)。训练时用pairwise logistic loss,推理时直接输出f(x)作为吸引力分数。这一步解决了人工标注噪声问题,也顺带缓解了回归模型的“平均化”倾向。
多说一点“Aligned with Human Preferences”这个关键点。它不只是工程技巧,更是一种建模哲学:模型的目标函数不是某个客观美丑标准,而是人类打分群体的偏好分布。这要求我们在训练集和评估集上都与真实人类偏好做对齐,而不是只看loss大小。说白了,模型输出的是“一群标注员在看到这张脸时的平均偏好反应”,而不是某种绝对真理。
1.3 项目定位与适用人群
这个项目的技术栈是:预训练人脸embedding + 偏好排序头 + 校准输出。它适合以下几类人参考:
- 做多模态模型或人脸特征工程的同学,想给视觉模型加上“美学偏好”维度
- 做推荐系统、内容排序的人,想借鉴“人类偏好对齐”的方法论
- 做虚拟形象生成、AI修图、摄影辅助选片的从业者,需要一个稳定的美学评分信号
- 对AI伦理论证感兴趣的读者,因为这类模型天然处在争议中心
如果你是想在商业产品里直接套一个“颜值分”,我建议你先看完第5章再动手。这个方向一旦用错了场景,负面影响远超技术收益。
2. 数据是审美难题的核心:人类偏好数据集怎么搭
2.1 评分制 vs 排序制:标注方案的设计取舍
数据是这类项目的命门。我没有直接沿用评分数据集,而是把标注方案拆成两段。
第一阶段用评分制做初筛。找8位标注员,对约3万张公开授权的人脸图分别打1-5分。这个阶段的目的不是得到精确标签,而是快速剔除明显低质量样本、摸清数据分布。第二阶段用成对比较做精标注。从初筛集合里随机抽18万对图片,让标注员二选一:“哪一张更好看”,同时允许“难以判断”选项。得到的偏好对比绝对分数靠谱得多。
这个两阶段设计有一个很实际的考量:评分便宜但噪声大,成对比较噪声小但贵,所以让便宜的先去粗筛,把贵花在关键部分。如果一开始就全量做成对比较,成本至少要翻三倍。我这里给出两种方案的对比:
| 维度 | 评分制(1-5分) | 成对比较制 |
|---|---|---|
| 标注成本 | 低,单张几秒 | 高,一对几秒到十几秒 |
| 标注一致性 | 低,受标注员状态影响 | 高,相对判断稳定 |
| 噪声水平 | 高,标准差普遍大于0.8 | 低,多数情况下能达成一致 |
| 能否直接训练 | 能,但容易平均化 | 不适合直接回归,适合排序 |
| 我的用途 | 初筛、构建辅助回归loss | 主训练信号 |
标注界面我也做了个细节处理:同一屏显示两张图,按钮只有“左好/右好/难分”,不提供分数输入框。这让标注员不需要做任何数值抽象,只靠直觉就能完成判断。每100对里插入10对已知答案的验证对,实时监控标注质量,一旦某个标注员在验证对上的错误率超过15%,系统自动暂停任务并重新培训。这些质控细节看着琐碎,但直接影响偏好数据的稳定性和后续模型的泛化能力。
2.2 数据清洗与隐私合规处理
数据这块我有几条硬规矩,都是踩过坑之后总结出来的。
第一,来源必须干净。公开学术数据集(FFHQ、CelebA-HQ这类)用于研究没问题,但要确认授权条款是否允许二次标注和模型训练。不推荐去社交平台抓图,一旦涉及真实个体,问题会非常复杂。第二,人脸必须脱敏。我把图片做了不可逆匿名化处理,任何人无法从预处理后的样本反推原始身份。纯粹的学术demo可以这么处理,但商业应用建议在原始数据链路就做数据最小化。第三,未成年人照片一律剔除。这种模型本身就有争议,未成年人数据是绝对红线,没有任何商量余地。
第四是做标签去噪。我用两个指标过滤:标注员标准差超过1.2的样本直接丢弃;用Kappa系数评估标注员之间的一致性,低于阈值的样本重新标注。这一步很关键,能有效减少后面训练时的label noise。在实际做的时候,我还加了一层相似样本排重,避免同一张脸以不同裁剪方式反复出现,否则模型会对某些特定人脸严重过拟合。
2.3 防止“单一审美”偏差的策略
审美是有群体差异的,这一点不只是学术问题,更是产品口碑问题。如果模型只学会某一个人群的偏好,评估时可能表现很好,但部署时会翻大车。我的处理方法分三个层次。
标注员多样性。8位标注员的年龄、性别、地域背景尽量分散,避免一个同质小圈子把审美观固化到数据集里。数据配比均衡。在构造成对偏好时,我按人脸的性别、年龄段、肤色分布做了分层采样,避免某一群体被过度表征。测试独立采样。评估集单独采样,且标注员和训练集不重叠。这样测出来的分数才是模型泛化能力的真实反映,而不是“背下了训练标注员的口味”。
另外,更严谨的做法是建模为“偏好分布”而不是“单一偏好评级”。可以按标注员群体分组训练多个评分头,推理时按用户群选择。这个方向我实验过一版,复杂度明显上升,但作为进阶方案值得研究。如果你的产品有明确的用户人群画像,可以考虑这条路。
3. 模型架构与训练细节:embedding + ranking head 的实践
3.1 骨干特征的选择:为什么不用从零训练CNN
项目最初版本是拿ResNet50从零回归人脸分数,效果很一般,原因很简单:从零训练需要海量带标注数据,而颜值标注数据本身又稀缺又贵。哪怕我把训练集做到几万张,对一个深层CNN来说,仍然不够学出一套能应对各种角度、光照、表情的表征。
所以我最终采用了“预训练人脸embedding + 轻量评分头”的两段式架构。骨干用的是insightface里的ArcFace R100,输出512维人脸身份向量。ArcFace这类人脸识别模型在大规模人脸数据上预训练过,它提取的特征虽然是为身份识别设计的,但天然携带了大量关于面部结构、比例、对称性的几何信息,而这些恰恰是美学判断的基础底盘。用现成embedding相当于让模型站在了“已经懂人脸几何”的起跑线上,评分头只需要在这个表征上做偏好映射,训练成本极低。
我也试过CLIP的图像embedding做骨干,它的泛化性更好,但对人脸结构的精细几何信息编码不如ArcFace,最终排序指标略低。还试过几个美学专用特征提取器,但开源和文档都不够成熟,不值得在生产环境引入。有个细节值得说:骨干默认冻结,只训练评分头。理由有两条。一是样本量不够,解冻全部参数容易过拟合;二是人脸embedding经过大规模训练已经很稳定,解开微调容易灾难性遗忘。
3.2 评分头与损失函数:MSE、pairwise ranking 怎么配合
评分头是个两层MLP:512 -> 128 -> 1,中间带ReLU和Dropout,输出接Sigmoid,得到0到1之间的吸引力分数。
主损失用的是pairwise ranking loss。具体来说,对于偏好对(A, B)(A比B更好看),期望模型输出的差f(A) - f(B)越大越好,用logistic形式:
import torch import torch.nn.functional as F def pairwise_rank_loss(score_a, score_b, margin=0.1): # score_a: 模型给定的A分数,A应该比B好看 logits = score_a - score_b - margin loss = -F.logsigmoid(logits).mean() return loss加margin的目的在于防止模型输出“谁都差不多”的局部最优解。没有margin,模型其实可以靠输出一个常数来把两个分数拉的差距极小,loss也会很低,但排序效果会很弱。margin相当于强制要求“A至少比B高0.1分”。
除此之外,我还保留了一个辅助回归loss。初筛阶段的1-5分,经过标准化后变成回归目标,用MSE计算。最终的总loss是:
L_total = L_rank + λ * L_mse
λ我取0.3。这个组合的意义是:rank loss提供主要的偏好学习信号,让模型学会正确排序;MSE辅助loss则把输出分数校准到人类评分的绝对尺度上,避免推理分数严重偏离直觉。为什么纯MSE效果差,纯rank又不够?纯MSE震荡大、易平均化,纯rank无法给分数赋予绝对语义。两者结合虽然参数多一个,但彼此补偿,最终效果明显好于任何单一loss。
3.3 训练配置与调参手记
训练配置上,我用的是AdamW优化器,初始学习率1e-4,batch size 128,总共24个epoch。前2个epoch做线性warmup,后面加余弦退火。评分头的Dropout设为0.3,训练过程用混合精度加速。整套模型单卡A100大概3小时跑完。
但这里有个比配置更重要的环节:成对采样策略。如果只是随机采样pair,会发现模型学得很慢,而且loss下降后排序指标提升不明显。原因是大部分随机pair非常简单(一张明显好看一张明显普通),模型很快就判断对了,梯度没有信息量。后来我改成“hard negative采样”:每个batch里优先挑那些模型当前难以区分的pair,也就是-score差距小于margin的样本。这样能显著加速收敛,Kendall‘s Tau大概提升了0.05左右。
还要注意batch内的pair不要重复太多。一个batch里不同pair之间应该覆盖不同的人脸,如果反复用同一张图跟不同图配对,模型会记住这张图的绝对分数,而不是学相对偏好,泛化会变差。推理阶段还有一个细节:评分头输出的sigmoid概率不能直接当最终分数。我加了温度缩放(temperature scaling),在验证集上优化一个温度参数,使输出概率分布和人类评分的经验分布更匹配。模型训练时只需要内部排序正确,但部署时要让分数落在用户能理解的量程上。
4. 评估与调优:对齐效果不能只看准确率
4.1 评价指标怎么设计
训练过程中我同时看三个维度的指标,避免被单一分数误导。
排序一致性用Kendall‘s Tau和Spearman’s rank correlation,拿模型分数和人类评分均值做相关分析。这两个指标关注的是“排序上是否一致”,是偏好对齐模型最核心的度量。分组命中率方面,把测试集按人类评分分成top10%和bottom10%,看模型能否把这部分识别出来,用top10召回率和bottom10错误率来衡量。稳定性指标主要是同一身份多张照片(不同角度、光照、表情)的分数标准差。模型分数随姿态剧烈波动的话,说明它学到了各种无关因素,不是在评估面部结构本身。
| 指标 | 计算方式 | 我实测到的参考范围 |
|---|---|---|
| Kendall’s Tau | 模型排序 vs 人类排序 | 0.58 - 0.64 |
| Spearman相关 | 同上,用秩相关 | 0.72 - 0.79 |
| top10%召回 | 模型top分命中人类top分比例 | 0.41 - 0.48 |
| 稳定性 | 同人多图分数标准差 | 0.06 - 0.12 |
这个表是参考值,具体数字会随数据集和骨干变化,但量级是可信的。对比之下,纯MSE回归模型的Kendall‘s Tau只有0.47左右,排序方案的对齐优势非常明显。
4.2 实测翻车案例与排查链路
项目里最有价值的部分其实是那几次“模型看起来在学,实际学错了”的翻车事故,我详细说两个。
第一个case是“化妆作为混杂因子”。训练后我检查发现,模型对浓妆照片普遍给高分,素颜同人照片明显低分。起初我以为是合理偏好,后来做消融实验,把成对偏好里的化妆状态作为混杂因子做分层统计,发现模型过度依赖妆面纹理,几乎忽略了面部结构。定位到原因后,修复手段有两步:一是构造偏好对时,尽量让对比双方的化妆状态一致;二是给训练集加了局部区域遮挡增强,强迫模型不能只依赖皮肤纹理。修复后,素颜/浓妆同人图的分数差从0.21缩小到0.08。关键不是控制“有没有妆”,而是消除“妆面掩盖了太多结构”这个错误信号。
第二个case是侧脸分数系统性偏低。正脸平均分0.72,侧脸同人只有0.58。这其实是指标设计时埋的雷,单纯看回归loss根本发现不了,因为我没在训练集里配上角度标签。排查方式是在测试集按yaw角分桶,画出分数-角度曲线,看到明显的负相关。修复方法是做角度增强:训练时对图片做随机水平翻转、轻微旋转和仿射扰动。改完之后,侧脸和正脸的分数差控制在0.04以内,整体稳定性指标也明显改善。
这两个案例的共同教训是:可控的评估集远比复杂的模型重要。预训练embedding能解决表征问题,但解决不了数据层面的系统偏差。这也是为什么我在项目后期愿意花大量时间去做分层评估,而不是继续堆模型参数量。
4.3 鲁棒性测试:光照、角度、表情
最后我把鲁棒性做成了一套固定的评测脚本,每次迭代都跑一遍。主要包括:光照变换(提亮、压暗、加噪)、几何变换(旋转、缩放、平移)、表情变换(真实多人表情照 vs 中性表情)。
跑完发现一个高频问题:模型对清晰度极其敏感。只要是边缘锐利的图,分数就偏高;高斯模糊之后,分数立刻掉0.2以上。这个现象和“近视眼觉得美”差不多——模型把对焦、磨皮误当成了颜值。为了抑制这个问题,我在测试级也加了test-time augmentation:同一张图做多次随机扰动,取分数平均,能显著提升稳定性。代价是推理耗时增加,但对质量敏感的应用场景,这笔开销是值得的。
5. 这种模型绕不开的边界问题
5.1 为什么外貌评分模型一直被质疑
我必须花一整章来谈这件事,因为这类项目太容易做出来、也太容易被滥用。外界对外貌评分模型的质疑,主要集中在三点。
第一是对容貌焦虑的放大。一个能随时给任何人打分的产品,会把审美压力变成可量化、可比较的数值,这对未成年人和心理脆弱群体尤其不友好。第二是数据偏见的固化。模型学的是训练集中的偏好分布,如果训练集本身就受到某种审美偏见(比如单一地域、单一肤色、单一身材标准)的影响,模型就是在用一个系统的均值去压制多样性。第三是实际危害场景,比如招聘筛选、信贷审批、社交平台推荐里如果暗中使用了颜值分,会对个体产生不可控的影响,而且普通人没有申诉渠道,也很难验证自己是否被这种分数影响了。
学术圈对“AI评分美丑”也基本是一个公认的伦理雷区。不是所有能做的技术都应该做成产品,这个判断在这个项目里尤其重要。如果你在做一个面向公众的产品,最好把“美学评分”做成辅助信号,而不是决策依据,同时要有非常清晰的用户告知和申诉机制。
5.2 我能接受的用法和坚决不做的场景
基于上面的考虑,我给这个模型划了几条明确的使用边界。
- 可接受:虚拟形象生成时的美学一致性校验、摄影工作室选片辅助、美学研究的学术实验、对“平均偏好”的社会学观察
- 不建议:对真实个体的公开评分、婚恋匹配里的排序推荐、任何招聘或准入决策、医美效果承诺类应用
实现层面,我在模型的输出接口里加了一个约束:输出分数时始终附带置信区间,而不是只给一个孤立的数字。这样调用方会直观意识到,审美判断本身有很强的不确定性。比如同一个人的照片,模型输出0.73,置信区间是[0.65, 0.80],这时候任何理性人都不会把它当成一个精确的裁判标准。同时在模型文档里明确写明“这是基于特定标注人群偏好分布的建模结果,不代表客观美丑标准”。
这些约束不能完全消除风险,但至少能让使用方意识到,这不是一个“权威颜值裁判”。如果读者真的想在自己产品里用这类模型,我的建议是先回答三个问题:用户会不会因为某个分数产生心理压力?这个分数会不会影响一个真实个体获得资源的机会?被评分的人是否知情并同意?如果任何一个答案是否定的,请再斟酌一下场景。
我在这个项目上做的最重要的决定,不是换骨干网络、不是调loss权重,而是在最后把模型定义成“一个描述人类偏好分布的统计工具”,而不是“定义美的机器”。审美永远是概率和文化的产物,模型能帮我们观察它、理解它,但绝不应该替代每个人自己的判断。这是这个项目走到最后,我最大的一点体会。