专业书籍精读 · ML System Design Interview · 第 3 章
Machine Learning System Design Interview · Ch 3 · Ali Aminian & Alex Xu · 2023
街景车开过你家门口,顺手把整条街拍了下来。照片里有路过的行人,有停在路边的车牌,还有你自己。这些照片要发到网上给全世界看,发之前得把人脸和车牌全糊掉。这一章讲的就是:怎么让机器自动找出该糊的地方,然后糊掉它。
你大概以为,做这种系统的人追求的是「糊得又准又不多糊」。恰恰相反。他们会故意把机器调成一个神经过敏的状态——宁可把不是人脸的东西也糊掉,也绝不肯漏掉一张真人脸。明知道会糊错,还就是要这么调。
第一难是量。照片按十亿张算,哪怕一个人扫一眼只花 5 秒,也要 50 亿秒——相当于 158 个人全职干一年,而街景车明天还在拍。
第二难更隐蔽:机器说「这张照片里有人脸」根本没用。你要糊的是那一小块像素,所以必须知道脸在哪、有多大。「看出有」和「指出在哪」是两件难度完全不同的事。
四件事,一件比一件关键。
糊多了以后,街景里会出现一些莫名其妙被抹掉的招牌、广告牌人像和路边涂鸦,而且模糊是破坏性的——一旦糊上,那块画面基本就回不来了。
当两种错误的代价差着好几个数量级时,「调到最准」就是错的目标——正确的做法是明知故犯地往代价小的那一边偏,然后专门花一道工序,去收拾偏过头带来的麻烦。
想进到具体机制、记号和示意图? → 切到精读版
这一章表面在教目标检测(object detection),真正教的是代价不对称时怎么定操作点:漏糊一张人脸是不可逆的隐私事故,多糊一块招牌只是一张难看的照片——于是正确答案不是精确率与召回率平衡的那个点,而是故意偏向高召回、低精确率,再靠一级专杀假阳性的后处理和一条人工举报回路把偏过头的部分收回来。
《ML System Design Interview》Part II 十道真题的第二道。输入还是图像,任务从 Ch2 的「编码成向量 + 检索」换成了「定位 + 分类」;它也是全书唯一一道业务目标是合规、不是体验的题。下启 Ch5(有害内容检测)——同样是低底率、阈值、人工复审三件套。现实对应 Google 街景与 Apple Look Around 的脱敏管道,以及自动驾驶路采数据在 GDPR 下的匿名化作业。
街景车在几十个国家的公共道路上拍照,照片里必然有没被征询过意见的路人和车牌。隐私法规(欧盟 GDPR 及各地法律)要求发布前去标识化,街景项目本身也在多个国家引发过隐私争议与监管审查。
难点不在「能不能检测人脸」,在量级与后果:
5×10⁹ 秒 ≈ 158 人年,而采集车每天仍在增量拍摄。纯人工不是贵,是不存在。所以真正的题面不是「把 mAP 做到多少」,而是「在业务能容忍的误糊水平下,把召回率顶到多高」。当成普通精度优化题做,方案第一轮就偏了。
图像分类只回答「这张图里有没有人脸」。但你要模糊的是那一块像素,没有坐标就无从下手——所以任务必须是目标检测,输出一组 (框, 类别, 置信度),类别两个:人脸、车牌。
一个容易被跳过的推论:这是多类别检测,而两类目标难度并不相等。人脸朝向、遮挡、尺度多变(远处的脸只有十几个像素高);车牌形状规整、有文字先验,但会反光、透视变形,海报与玩具上的假车牌还会骗过模型。两个类别就该有两个独立阈值,共用一个是把两道题当一道做(§6 的开源实证正是这么设计的)。
两段式(two-stage,代表 Faster R-CNN):骨干网络先把整图压成特征图 → 区域候选网络以锚框为模板粗筛出几百到几千个「这里可能有东西」的框 → 第二段只对这些候选框做分类并精修坐标。先圈后认。
一段式(one-stage,代表 SSD、YOLO):一次前向,在特征图每个位置上直接输出「有没有目标 + 是什么 + 框偏多少」,没有候选阶段。
权衡的根子在算力花在哪:两段式把「哪里可能有」和「那是什么」拆开,重算力只花在少量候选上,精度通常更高、对小目标尤其明显;代价是流程长、单图耗时高。一段式省掉候选阶段,同代硬件上往往快数倍,代价是历史上对小而密集的目标偏弱(后来 focal loss 之类把差距缩小了不少)。
书里把两条路摆开,结论跟着前提走:街景脱敏是离线批处理,没有在线延迟预算,那就按准确率(尤其召回)优先,选两段式。这个结论必须连着前提一起背——换成采集端实时脱敏,答案立刻变成一段式。面试里只说「选两段式,因为更准」,就丢掉了得分点。
检测的监督信号天然是两件事:框画得准不准(回归,比较预测坐标与真值坐标)、类别判得对不对(分类,交叉熵)。合成一个多任务损失 L = L_cls + λ·L_box——λ 是权重旋钮,调大则模型更在意框贴得紧,调小则更在意别判错类。
本题有个好用的特性:框大一圈几乎无害(糊宽点没人投诉),漏掉才要命——所以工程上常把检测出的框按固定比例外扩再模糊,用余量吃掉定位的小误差。
数据这一侧,标注是一框一框画出来的,很贵;书里靠数据增强(data augmentation)放大数据量:水平翻转、随机裁剪、旋转、调亮度 / 饱和度、转灰度。离线增强预先生成变体存盘,训练快但占存储;在线增强训练时现场变换,省存储但拖慢每一步。一句领域判断:街景重力方向固定,垂直翻转出来的样本现实中不存在,属于白费。
检测器会在相邻位置、不同锚框上对同一张脸各报一个框,一张街景图轻易冒出几十上百个互相重叠的框。NMS 的做法朴素得像常识:按置信度从高到低排队,取最高的那个留下,把与它 IoU 超过某个值(常用 0.5)的其余框全部丢掉,然后在剩下的框里重复。
为什么这一章必须讲它:没有 NMS,召回率和精确率都是错的。同一张脸的 12 个框会被统计成 12 个检测,误糊面积也算不准——而这一章的所有决策都建立在这两个数字上。
置信度阈值是一个单旋钮:调低 → 报出更多框 → 召回率上去、精确率下来(误糊变多);调高 → 反过来。绝大多数 ML 题的默认答案是「取 F1 最高那点」,这道题的正确答案是明确地不取那一点。
理由一行就够:记漏检一张脸的代价为 C_fn、误糊一块招牌为 C_fp,这里 C_fn / C_fp 大到几个数量级(一边是不可逆的隐私事故与监管风险,一边是画质),所以期望损失最小的操作点落在高召回那一侧。
但高召回不是免费的。阈值一路往下压,召回每多一个点,误糊会陡增:街景里开始出现被抹掉的商铺招牌、广告牌人像、玩具车牌。正确的解法不是在一条曲线上找妥协,而是加一级结构:检测器就待在高召回、低精确率的操作点,后面接一道专杀假阳性的后处理——用检测器看不到的领域信息否决明显不可能的框,比如尺寸配不上所在景深、整个框落在天空里、同一位置在相邻几帧里完全不一致。好处是两种错误各归各治,而不是让一个阈值同时背两件事。
离线指标的地基是 IoU 定「对上没对上」,再算 AP / mAP。但 mAP 是把两类错误揉成一个数的综合分,隐私场景拍板要的是分开的两个数:在能接受的假阳性水平下召回率是多少(即 PR 曲线上指定精确率处的召回)。拿一个综合分向法务解释「我们漏了多少」,解释不通。
还有一条更容易漏的:必须分层报。整体召回 95% 能轻松掩盖「正脸 99%、侧脸 70%、远处小脸 40%」,而漏检偏偏集中在后两类。按地域、光照、人群分层看,是唯一能防自欺的动作。
在线指标回到运营:每百万张图的补糊举报数、举报中确认为真漏检的比例、误糊的抽样复核率。
表 1 · 一段式还是两段式(由延迟预算决定,不由精度偏好决定)
| 骨架 | 机制一句话 | 换来什么 / 代价 | 什么场景选它 |
|---|---|---|---|
| 两段式 Faster R-CNN | 先用区域候选网络粗筛几百~几千个框,再逐框分类并精修 | 精度高、小目标更稳;单图耗时高、流程长、部署重 | 本题:离线批处理、无在线延迟预算、召回优先 |
| 一段式 SSD / YOLO | 一次前向在每个位置直接出类别与框偏移 | 同代硬件常快数倍、易上端侧;历史上小而密集目标偏弱 | 采集端实时脱敏、车载、直播画面遮挡 |
表 2 · 操作点选哪个:这道题唯一真正的设计决策
| 操作点 | 后果 | 适用前提 |
|---|---|---|
| 高精确率 阈值拧高 | 街景干净、几乎不误糊;但真人脸会漏出去——一张就是一次不可逆的隐私事故 | 只在「误报代价 ≥ 漏报代价」时成立,本题不成立 |
| F1 最优 平衡点 | 两类错误都不算多,看着最「专业」 | 默认答案,但隐含假设两类错误等价——这道题的核心就是它们不等价 |
| 高召回 拧低 + 后处理 | 漏检压到最低;误糊显著增多,靠第二级后处理杀掉大部分 | 本题选这个:C_fn / C_fp 差几个数量级,误糊只损画质 |
表 3 · 指标怎么报(隐私系统不能只报一个综合分)
| 指标 | 在看什么 | 适合 / 不适合 |
|---|---|---|
| AP / mAP | 各类别、各 IoU 松紧度下的平均精确率 | 学术标准、便于比模型;把漏检与误糊揉成一个数,不能用来拍隐私决策 |
| 指定精确率处的召回 | 在能接受的误糊水平下,漏了几成 | 本题的主指标,直接回答「还有多少人脸露在外面」 |
| 分层召回 | 按正脸 / 侧脸 / 小脸、地域、人群分开看 | 唯一能防自欺的报法;整体 95% 常掩盖某一层只有 40% |
| 线上举报率 | 每百万张图的补糊请求数及确认率 | 真实世界的漏检代理指标,也是合规必备记录 |
三张表指向同一句话:这道题的技术选择几乎都不是「哪个更强」,而是「代价怎么定」。把代价说清楚,选型是推论;说不清楚,任何选型都站不住。
落地形态是批处理管道,不是在线服务:新采集的图片按地理分片进队列 → GPU / TPU 集群跑检测 → NMS 与后处理 → 模糊服务把框外扩后做高斯模糊 → 落对象存储再上线。两个约束必须一开始就设计进去:一是模糊破坏性且不可逆,原图的保留期限与访问权限得按隐私政策卡死;二是管道必须能按新版本模型重跑历史图,否则改进只作用于新照片,历史库里的漏检永远留在那里。
另一半是人工回路:任何人可举报「这是我的脸 / 我家门牌,请糊掉」,人工复核后补糊——这些样本恰好是模型最缺的难例,回灌训练集就是天然的主动学习(active learning)。它的意义不只是补救:合规要求的是存在可用的救济渠道,而不是模型 100% 准确。把人工兜底当成技术不足的遮羞布,是对这一章的误读。
换个类别就能复用:路采数据匿名化、医疗影像去标识、会议录像白板打码、直播实时遮挡。只要「必须遮住某类东西、漏一个就出事」,答案就是这一章。
① 核心命题:当两类错误代价差几个数量级时,「调到最准」是错的目标——街景脱敏的正确操作点是故意偏向高召回、低精确率。
② 必须建成目标检测而非分类:要糊的是那一块像素,没坐标无从下手;输出 (框, 类别, 置信度),人脸与车牌两类各自一个阈值。
③ 两段式(区域候选网络粗筛 + 逐框分类精修)vs 一段式(一次前向出结果);本题选两段式的理由是「离线批处理没有延迟预算」,前提一换答案就换。
④ 训练信号是多任务损失 L = L_cls + λ·L_box:定位加分类;框大一圈无害、漏掉才要命,所以实践中常把框外扩再糊。
⑤ NMS 不是细节:不压掉同一目标上的重叠框,召回率、精确率、误糊面积三个数字全是错的。
⑥ 正解不是在一条曲线上找妥协,而是两级结构:检测器待在高召回操作点,后处理用领域信息专杀假阳性。Google 的街景论文自述用的就是这个结构,全自动系统糊掉了超过 89% 的人脸、94–96% 的车牌。
⑦ 指标要分开报、分层报:mAP 用来比模型,拍板看「指定精确率处的召回」;整体 95% 常掩盖侧脸与小脸只有四五成,而漏检不均等就是隐私保护不均等。
⑧ 架构是批处理管道 + 人工举报回路:模糊不可逆,原图保留要按策略卡死、管道要能按新模型重跑历史;人工兜底不是遮羞布,合规要的本来就是一条可用的救济渠道。