良率模型上线3个月偷偷变傻:我用PSI+KS把模型漂移提前两周抓了出来
良率模型上线3个月偷偷变傻:我用PSI+KS把模型漂移提前两周抓了出来
【摘要】我上线了一个XGBoost良率预测模型,前两个月RMSE只有2.1%,老板很满意。结果第3个月发现预测越来越离谱--模型说良率85%以上,实际只有76%,两批高价值晶圆没及时拦截,损失约60万。查了一周才定位:工艺窗口调整后新批次特征分布漂移了,模型没见过这种分布。这篇文章讲我怎么用PSI、KS检验和在线监控,把模型"偷偷变差"提前两周发现,并建了一套retrain触发机制。
────────────────────────────────────────────────
一、背景:模型上线后悄悄变傻的噩梦
2023年我们FAB上线了第一个XGBoost良率预测模型,用历史18个月数据训练,验证集RMSE 2.1%,上线第一个月实际RMSE 2.3%,表现稳定,厂长在周会上还点名表扬了我们数据组。那时候我觉得,AI落地也就那么回事,跑通数据管线就稳了。
可到了第3个月,产线开始反馈预测越来越不准。明明模型说这批良率85%以上,实际只有76%;模型说某批风险低可以放行,结果后段测试报废了一大片。最严重的一次,两批高价值晶圆没被及时拦截,流到后段才发现不良,直接损失约60万。我被质量总监叫去问话,要求三天内给说法。
我查了一整周才定位问题。根因很典型:第2个月末工艺工程部调了CVD腔室的温度窗口(从850±15°C调到860±10°C),新批次的特征分布整体右移了。而我训练时用的参考分布还是老数据,模型没见过这种分布,预测自然失真。这就是模型漂移(Model Drift),几乎所有上线模型迟早都会遇到,只是早晚和程度不同。
更坑的是,这种漂移是渐进的。单看某一天RMSE只涨了一点点(2.3%→2.5%),没人会注意。等累积到肉眼可见(2.3%→4.2%),已经坑了一批晶圆。从那以后我立下规矩:任何上线模型必须配在线监控,漂移要在影响业务前两周就被告警,而不是等损失发生后再救火。
这件事给我的教训很深:模型上线不是终点,而是另一段责任的开始。训练集上95%的准确率,在产线分布一变就可能掉到60%。工程界有句话叫"模型上线即开始衰减",我算是真真切切地挨了一刀。
二、技术原理:漂移检测到底在测什么
模型漂移分两类:数据漂移(特征分布变)和概念漂移(输入到输出的映射关系变)。半导体场景里数据漂移最常见--工艺窗口调整、换料、新机台导入、季节性温湿度变化,都会让特征分布偏移。概念漂移相对少,多见于工艺原理性变更(比如换了刻蚀化学配方)。
检测数据漂移最实用的指标是PSI(总体稳定性指数,Population Stability Index)。它比较两个时间点特征分布的差异:PSI<0.1 分布基本稳定;0.1~0.25 中度漂移,要关注;>0.25 严重漂移,必须处理。公式是PSI=Σ(实际占比-预期占比)×ln(实际占比/预期占比),按分箱计算后求和,每个特征算一个值。
另一个常用的是KS检验(Kolmogorov-Smirnov),它直接比较新旧样本是否来自同一分布,给出p值(p<0.05说明分布显著不同)。PSI适合做日常例行监控(算一个数值就行),KS适合在重大工艺变更时做一次性的统计确认。我个人习惯两者结合:PSI做每日监控,KS做变更确认。
为什么不直接看RMSE?因为RMSE是结果指标,等你看到RMSE涨了,损失已经发生了。PSI看的是输入分布--漂移先发生在输入,再传导到输出,所以PSI能提前预警。这是"治未病"的思路,而不是"治已病"。打个比方:RMSE是体温计,PSI是免疫监视,前者发现你发烧了,后者在病毒刚入侵时就报警。
另外要区分"真漂移"和"噪声"。产线数据每天都有随机波动,PSI单日微涨可能是噪声。所以我用"连续N天超阈值"或"滚动均值超阈值"来判断,避免被单日抖动误报。这是监控系统的关键设计点,后面实战会讲。
三、实战:我搭的漂移监控闭环

落地分三步,全部用Python+定时任务实现,不依赖重型MLOps平台,小团队完全能扛:
第一步,固定参考分布(baseline)。模型上线时,把训练集的特征分箱占比存成baseline JSON(每个关键特征20个分箱的占比)。这是"正常"的锚点。注意:baseline必须选"健康期"数据,不能用包含设备异常、停机的脏数据,否则正常也会被报异常--我踩过这个坑。
第二步,每日计算PSI。每天凌晨用当天新批次数据,按相同分箱算占比,和baseline比PSI。我把阈值设成:单特征PSI>0.1 黄色预警,>0.25 红色告警;任一特征红色就触发钉钉机器人推送。关键是告警必须推到人,光写日志没人看等于没监控。
第三步,retrain触发机制。我设了规则:连续3天有≥2个关键特征PSI>0.1,或任意特征PSI>0.25,自动拉一个新的训练任务(用最近6个月数据重训),训练完自动A/B对比新旧模型RMSE,新模型更好才替换上线,否则保持旧模型并升级告警级别。
上线这套后,第2次工艺调整(刻蚀功率窗口变更)时,PSI在第3天就报黄,我们第5天就完成了retrain,比上次提前了整整两周发现问题。那批晶圆良率保住了,质量总监这次反过来在会上夸了数据组。从"背锅"到"立功",就差一套监控。
还有个细节:retrain用滑动窗口(最近6个月),让模型跟上工艺演进,但保留少量历史数据防灾难性遗忘。纯用最新数据训练,模型会过拟合到短期波动,遇到偶发异常反而更脆弱。
四、为什么这样写代码
这段代码核心是PSI计算。分箱用分位数(qcut)而不是等宽(cut),因为工艺参数常是长尾分布,等宽分箱会导致多数样本挤在少数箱里,PSI对漂移不敏感。分位数分箱保证每箱样本量均衡,漂移更灵敏。
加了eps防止除零--实际数据里常有某个分箱在新数据里占比为0(比如某温度区间新批次根本没出现),直接除会NaN,eps这个小量保底,同时避免ln(0)无穷大。
阈值0.1/0.25是行业经验值,不是拍脑袋。0.1对应约"10%的样本落到了原分布之外的箱",已经值得关注;0.25意味着分布明显位移,必须处理。不同业务可调,但半导体良率场景这两个值我用下来最稳。
五、效果对比:有监控和没监控是两种命
有监控和没监控的区别是本质的。没监控时,漂移要等RMSE肉眼可见才被发现,平均滞后3-4周,期间损失的晶圆按我们厂规模每月约50-80万,一年就是600-900万的风险敞口。
上线PSI监控后,平均提前14天预警,retrain把RMSE拉回2.3%以内。光是我经历的那两次工艺调整,就避免了至少3次大的良率事故,保守估计止损200万以上。而监控本身零成本--就是每天跑个脚本,服务器还是原来的。ROI极高,几乎是白捡的钱。
更深一层,监控带来的是"信任"。业务方敢用模型了,因为知道有人在盯着它。之前模型翻车时质量总监一度不让模型碰良率数据,监控上线后他主动让我做良率根因分析。工具的价值,一半在算法,一半在让人敢用。
六、实施建议:别一上来就搞自动retrain
1. 先监控再优化:不要一上来就搞自动retrain,先把PSI监控跑起来,观察1-2个月,搞清楚你的产线漂移频率和幅度,再决定retrain策略。盲目自动retrain可能引入更糟的模型。
2. baseline要选"健康期"数据:不要用包含设备异常、停机的脏数据做baseline,否则正常也会被报异常。我踩过这个坑,排查了一周才发现baseline本身就脏。

3. 关键特征优先:FAB特征几十上百个,先监控对良率影响最大的10-15个(用模型特征重要性排序),其余可以后补。全量监控既慢又容易误报淹没真信号。
4. retrain用滑动窗口:不要永远用最初数据,用最近6个月,让模型跟上工艺演进。但保留少量历史数据防灾难性遗忘,纯最新数据易过拟合短期波动。
5. 告警必须接人:PSI告警推钉钉/企微给具体负责人,光写日志没人看等于没监控。我设了"黄色提醒、红色电话"的分级响应。
6. 监控自己也要被监控:PSI脚本挂了怎么办?加一个"今日PSI未更新"的兜底告警,防止监控失效你还以为太平。
七、进阶方向:从单变量到多变量
PSI是单变量方法,只能抓单个特征的分布变化,抓不到特征间关系的变化(比如温度和压力的联合分布漂移)。下一步可以上多变量漂移检测,比如PCA投影距离(把高维特征投影到低维,看投影分布漂移)或对抗验证(训练一个分类器区分新老数据,AUC高说明分布差异大)。
更前沿的是在线学习(online learning),模型实时用新数据微调,不需要等retrain周期。但半导体数据有强工艺相关性,在线学习容易过拟合到短期波动,落地要谨慎,建议先在小流量A/B验证。
头部FAB已经在做MLOps平台统一管理模型生命周期,漂移监控是标配能力。对中小厂,先用Python脚本把监控跑起来,比等重型平台现实得多--我们就是这样从0到1的。
效果对比
完整代码
import numpy as np, pandas as pd def calc_psi(expected, actual, bins=20, eps=1e-6): # 用分位数分箱,保证每箱样本均衡 cut = pd.qcut(expected, bins, duplicates='drop') exp_bins = pd.cut(expected, cut.cat.categories, include_lowest=True) act_bins = pd.cut(actual, cut.cat.categories, include_lowest=True) exp_ratio = exp_bins.value_counts(normalize=True) + eps act_ratio = act_bins.value_counts(normalize=True) + eps psi = ((act_ratio - exp_ratio) * np.log(act_ratio / exp_ratio)).sum() return psi # 模拟:老分布 vs 工艺调整后新分布(整体右移) base = np.random.normal(850, 15, 5000) new = np.random.normal(860, 14, 800) # 温度窗口调整 psi = calc_psi(base, new) print(f"PSI = {psi:.3f} -> {'严重漂移,需retrain' if psi>0.25 else '关注' if psi>0.1 else '稳定'}")
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📝 发布后复制到评论区:
你在FAB里遇到过模型上线后悄悄变差的情况吗?或者有哪些数据质量的坑?欢迎在评论区聊聊你的真实经历,我会一一回复。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
💎 本文配套VIP资源:相关工具已打包上传CSDN资源区(关注后可直接下载)。更多半导体AI实战工具,关注我持续更新。
👉 关注我,持续分享半导体智能制造一线实战。





