监督学习
监督学习是今天工业界用得最多的机器学习方法——你给它"数据 + 标准答案",它学"输入 → 输出"的映射。它占所有 ML 应用的 80% 以上。
先把术语翻译成人话
这一节的术语听着玄,其实说白了都是生活里天天在干的事。先把它们一次性翻译成人话,后面看正文就顺了。
| 术语 | 换成大白话 | 生活里对应什么 |
|---|---|---|
| 监督学习(Supervised Learning) | 给你一本带答案的练习册,做完立刻对答案改错 | 学校发的作业本,后面附着标准答案 |
| 特征 x(Feature) | 题面上给你的那些已知条件 | 去医院挂号时填的身高、体重、血压那几栏 |
| 标签 y(Label) | 这道题的标准答案,是人写上去的 | 作业本最后一页的答案页 |
| 分类(Classification) | 判断题——是这个还是那个 | 超市决定一样货该摆到哪个货架上 |
| 回归(Regression) | 填空题——报一个具体数字 | 估一估这个快递还要几天到 |
| 损失(Loss) | 这次答得离答案差多远,也就是扣了几分 | 考试卷子上那栏扣分记录 |
| 训练(Training) | 照着扣分记录一点点改,改到不怎么扣分为止 | 错题抄进笔记本,反复看到不再错 |
| 泛化(Generalization) | 没见过的新题也能做对 | 期末考试换了题目照样及格 |
| 过拟合(Overfitting) | 只把练习册背下来了,换个数字就傻眼 | 死记硬背的学生,一换题型就崩 |
想象一个 5 岁小孩学认字。
老师指着图片"苹果"——小孩说"梨";老师摇头:"这是苹果。"
老师指着下一张图"梨"——小孩说"苹果";老师摇头:"这是梨。"
这样反复教 100 次——小孩慢慢就能自己看图说出"苹果"和"梨"。
关键是:每次小孩答题,老师都立刻告诉他对不对——这就是"监督"的含义。
监督学习的输入与输出
监督学习的数据集,每一份样本都是一对 (x, y)——x 是输入(特征),y 是答案(标签)。模型要学的就是从 x 到 y 的映射。
"映射"这个词听着玄,换成大白话就是"查对照表":给一个 x,吐一个 y。打个比方,这好比医院的挂号窗口——你报出症状(x),窗口给你指一个科室(y)。窗口后面那位大姐干的活儿,就是脑子里存了一张"症状 → 科室"的对照表,见得多了越指越准。监督学习要做的,本质上就是让机器把这张对照表自己长出来,而不是让人一条条写死。
| 场景 | 输入 x(特征) | 输出 y(标签) |
|---|---|---|
| 垃圾邮件识别 | 邮件内容、发件人、关键词 | 垃圾 / 正常 |
| 房价预测 | 面积、地段、楼层、学区 | 价格(万元) |
| 猫狗识别 | 图片的像素 | 猫 / 狗 |
| 信用评分 | 收入、年龄、还款记录 | 该放贷吗(0~1) |
| 医学影像 | CT 图像 | 良性 / 恶性 |
这张表里藏着一个容易被忽略的事实:x 和 y 的形状千差万别,但训练的机制完全一样。不管 x 是一封邮件的三千个词、一张 CT 的五十万个像素,还是一行只有八个字段的贷款申请表,只要你能把它变成一串数字(向量),再给出对应的 y,监督学习的那套引擎——前向计算、算损失、反向传播、更新参数——就一字不改地能跑。这种"输入输出可以千变万化、内核纹丝不动"的通用性,是监督学习能在四十年里横扫无数行业的根本原因。
还要强调一句关于"标签"的严肃提醒:y 不是自然存在的,y 是人定义出来的。"这封邮件是垃圾邮件"不是宇宙真理,而是某个产品经理写了一份判定规则、某几百个标注员按这份规则打的标。如果规则本身有偏见——比如把所有营销邮件都算垃圾,而某个正规商家的促销信恰好被误判——那么模型就会忠实地把这个偏见学下来并放大。监督学习最大的风险从来不在算法,而在"标签定义"这个最不被重视的环节。
用一个具体的形式化写法把上面的意思落成代码,你会发现监督学习的骨架简单到有点让人失望:
# 监督学习的最小骨架(伪代码)
# 数据集 D = {(x1,y1), (x2,y2), ..., (xn,yn)}
model = init_model() # 一个带参数 θ 的函数 f(x; θ)
for epoch in range(EPOCHS):
for x, y in D:
y_hat = model.forward(x) # ① 前向:用当前参数预测
loss = L(y_hat, y) # ② 算损失:预测和答案差多少
grad = backward(loss) # ③ 反向:损失对每个参数的偏导
model.update(grad, lr) # ④ 更新:往损失下降的方向挪一小步
# 训练完成后,对没见过的 x_new:
y_pred = model.forward(x_new) # 泛化
# 注意:整套流程里唯一"人类知识"的入口,就是那些 y
两大类任务 · 分类 vs 回归
监督学习做的事,根据"y 是什么样"分两种:
这两个名字都不直观,尤其"回归"这个词,第一次听完全猜不到意思。简单说:分类是"从几个筐里挑一个筐",回归是"报一个数字"。就像你在菜市场——摊主问"要排骨还是要五花?"这是分类;问"要几斤?"这就是回归。
分类 · Classification
y 是离散的类别——猫/狗、垃圾/正常、是/否。
例:判断一封邮件是不是垃圾邮件。
输出:概率("95% 是垃圾")。
回归 · Regression
y 是连续的数值——价格、温度、销量、股价。
例:预测一套房的价格。
输出:具体数字("约 412 万")。
分类 = 判断题——"这是猫吗?" 只有是/否;
回归 = 填空题——"这套房多少钱?" 答案是任意数字。
两类问题的算法、损失函数都不同,但训练套路一样。
把分类和回归的差别摊开讲,最实质的分歧在损失函数上。回归用均方误差(MSE):把每个样本的"预测值减真实值"平方后求平均。平方这一下很关键——它让大误差被放大得极其严重(差 10 万的惩罚是差 1 万的一百倍),所以 MSE 训出来的模型特别怕离群点。如果你的房价数据里混进了一套一亿的顶级豪宅,整条回归线都会被它拽偏。这时候可以换成平均绝对误差(MAE)或折中的 Huber Loss:误差小的时候像 MSE 那样平滑好优化,误差大的时候像 MAE 那样不放大离群点。
三个缩写一次性交代清楚:MSE(Mean Squared Error,均方误差——差多少先平方再平均,重罚大错)、MAE(Mean Absolute Error,平均绝对误差——差多少就算多少,不加码)、Huber Loss(胡贝尔损失——小错按 MSE 算、大错按 MAE 算的折中方案)。打个比方:停车场收费,MSE 好比"超时越久罚款按平方涨",MAE 好比"超一分钟收一块钱、超一百分钟收一百块"。前者能把偶尔忘了取车的人罚到破产,后者温和得多。
分类用交叉熵(Cross-Entropy),它衡量的是"模型输出的概率分布和真实答案的分布差多远"。它有一个非常符合直觉的性质:如果模型对着正确答案给出了 0.99 的概率,损失几乎为零;如果它自信地给出 0.01 的概率,损失会趋于无穷大。也就是说,交叉熵不仅惩罚"答错",还额外重罚"答错还很自信"。这正是我们想要的——一个说"我不太确定"的错误判断,比一个斩钉截铁的错误判断危害小得多。
| 维度 | 分类 Classification | 回归 Regression |
|---|---|---|
| 输出类型 | 离散类别(可带概率) | 连续实数 |
| 常用损失 | 交叉熵 Cross-Entropy | MSE / MAE / Huber |
| 输出层激活 | Sigmoid(二分类)/ Softmax(多分类) | 不加激活,直接输出 |
| 核心指标 | 准确率、精确率、召回率、F1、AUC | RMSE、MAE、R²、MAPE |
| 典型翻车方式 | 类别不平衡导致"高准确率无用" | 离群点把回归线拽偏 |
| 业务例子 | 风控是否放贷、评论情感正负 | 房价、销量、到达时间 |
还有两种"介于两者之间"的任务值得知道。序数回归(Ordinal Regression):预测评分 1–5 星,类别是离散的但有大小顺序,把 5 星预测成 1 星比预测成 4 星错得更严重——这时候纯分类会丢掉顺序信息,纯回归又会输出 3.7 星这种不存在的值。排序学习(Learning to Rank):搜索引擎不需要知道每个网页的绝对分数,只需要知道谁该排在谁前面,所以它的损失函数直接建在"两两先后关系"上——这是搜索和推荐系统的主战场,Google 的 RankNet、LambdaMART 都属于这一支。
类别不平衡:准确率 99% 的骗局
这是监督学习落地时最常见、也最容易让新手交学费的坑。假设你在做信用卡欺诈检测,一百万笔交易里有 400 笔欺诈,欺诈占比 0.04%。你训了个模型,测试集准确率 99.96%,兴冲冲拿去汇报。风控总监问一句:"那 400 笔抓到几笔?"答案是——零笔。因为模型发现了一个偷懒的最优解:对所有交易一律预测"正常",准确率自动就是 99.96%。
0.04% 这个数字太抽象,换算一下就有画面了:想象一下一个超市门口的保安,每天有 2500 人进店,其中恰好有 1 个小偷。他要是干脆宣布"今天没小偷",一年三百多天里他有三百多天说得对——考核表上"判断正确率 99.96%",实际上一个贼没抓着。这就是准确率骗人的全部机制。
这类问题在现实中比比皆是,而且不平衡比例往往极其夸张:广告点击率预估里正样本占比常在 0.1%–2%;工厂质检里不良品可能只有千分之几;罕见病筛查里患者可能是十万分之一。所有这些场景,准确率(Accuracy)这个指标本身是有毒的——它会系统性地奖励"忽略少数类"的懒惰模型。
应对不平衡有一整套工具箱,按代价从低到高排:
- ① 换指标最便宜也最重要的一步。不要看准确率,看精确率/召回率/F1,或者看 AUC 和 PR-AUC。在极度不平衡时 PR 曲线(Precision-Recall)比 ROC 曲线更敏感,因为 ROC 的横轴假正例率被巨量负样本稀释了,看起来会过于乐观。
- ② 调阈值分类模型输出的是概率,是你自己选了 0.5 当分界线。把阈值降到 0.1,召回率立刻上升、精确率下降。阈值不是模型的一部分,是业务决策——查癌症要高召回(宁可多叫几个人来复查),推荐要高精确(别拿垃圾内容烦用户)。
- ③ 加权损失告诉损失函数"漏掉一个欺诈的代价是误报一次的 100 倍"。绝大多数框架都支持
class_weight参数,一行代码的事,效果通常立竿见影。 - ④ 重采样对多数类下采样(丢掉一部分正常样本)或对少数类上采样(复制欺诈样本)。更聪明的做法是 2002 年提出的 SMOTE:在两个相近的少数类样本之间做插值,"合成"出新的少数类样本,而不是简单复制——避免了简单复制带来的过拟合。
- ⑤ 改问题形态当少数类实在太少(比如只有 10 个样本),干脆放弃分类,改用异常检测思路:只学"正常长什么样",偏离就报警。这就跨到无监督的地盘去了(§ 4.2)。
评估指标:混淆矩阵和它长出的一切
要看懂精确率召回率,必须先能默画混淆矩阵。它就是一张 2×2 的表,把"模型说什么"和"真相是什么"两两交叉:
想象一下你是医院门口分诊台的护士,一天下来排队的人被你分成四堆:
真正例 TP——真有急症、你也放进急诊科室了(干对了);
假正例 FP——只是着凉,你却按急症收了(虚惊一场,浪费一张床);
假负例 FN——真有急症,你让他去普通门诊挂号排队(这是要命的那一格);
真负例 TN——没大事,你也让他去普通门诊(干对了)。
于是:精确率说白了就是"我判成急症的这些人里,真急的占几成";召回率说白了就是"今天所有真急的人里,我拦住了几成"。换成大白话——精确率管的是"别冤枉人",召回率管的是"别漏了人",这两件事天生互相拆台:想一个不漏,就得多冤枉几个;想一个不冤枉,就必然漏掉几个。
真相:欺诈 真相:正常
模型预测:欺诈 TP 真正例(抓对了) FP 假正例(误报/冤枉)
模型预测:正常 FN 假负例(漏抓) TN 真负例(正确放行)
准确率 Accuracy = (TP+TN) / (TP+FP+FN+TN) ← 全部判断里对了几成
精确率 Precision = TP / (TP+FP) ← 我报警的里面,几成是真的
召回率 Recall = TP / (TP+FN) ← 真的坏人里,我抓到了几成
F1 Score = 2·P·R / (P+R) ← 精确率和召回率的调和平均
为什么 F1 用调和平均而不是算术平均?因为调和平均会被两个数里较小的那个狠狠拖住。精确率 1.0、召回率 0.0 的模型(只报一次警且报对了),算术平均是 0.5 看起来还行,F1 却是 0——这正确地反映了它毫无用处。所以 F1 高,意味着两项都不能太差,这也是它成为最常用单一指标的原因。
AUC(ROC 曲线下面积)是另一个必须理解的指标,它的直观含义非常漂亮:随机抽一个正样本和一个负样本,模型给正样本打的分高于负样本的概率。AUC = 0.5 说明模型的排序能力等于瞎猜;AUC = 1.0 说明它能完美地把所有正样本排在负样本前面。AUC 的最大优点是与阈值无关——它衡量的是排序能力,所以在业务阈值还没定下来的探索阶段特别有用。风控行业还有个衍生指标 KS 值(正负样本累积分布的最大差值),也是同一族思路。
| 场景 | 该优先看什么 | 为什么 |
|---|---|---|
| 癌症筛查 | 召回率 | 漏诊代价是人命;误报只是多做一次复查 |
| 垃圾邮件过滤 | 精确率 | 把老板的重要邮件误判成垃圾比漏掉几封广告严重得多 |
| 推荐系统首屏 | Precision@K | 用户只看前 10 条,第 500 条准不准无所谓 |
| 风控评分卡 | AUC / KS | 要的是排序能力,阈值由风险偏好后定 |
| 搜索引擎 | NDCG | 不仅要相关,还要把最相关的排最前面 |
| 类别极度不平衡 | PR-AUC | ROC 被巨量负样本稀释,会过于乐观 |
主流算法速览
监督学习经过几十年沉淀,攒下一批"经典选手",今天仍在大量使用:
看这张表之前先摆个态度:这些算法名字都挺凶,但它们干的活儿都能用一句人话讲完。好比厨房里的锅——炒锅、蒸锅、高压锅,听着都是专业器具,说白了就是"火大快炒的""靠水汽焖的""靠压力压熟的"三种路子,选哪个看你今天做什么菜。
| 算法 | 擅长 | 一句话理解 |
|---|---|---|
| 线性回归 | 简单预测(回归) | 画一条直线"穿过"所有数据点 |
| 逻辑回归 | 简单分类 | 把直线弯成 S 形,输出 0~1 概率 |
| 决策树 | 可解释分类 | 一层一层"如果是 X 就走这边" |
| 随机森林 | 稳定分类 | 很多决策树投票,少数服从多数 |
| SVM 支持向量机 | 中等规模分类 | 找一条"最宽的边界"分开两类 |
| KNN 近邻 | 小数据集 | "离我最近的 K 个邻居属于啥我就属于啥" |
| XGBoost / LightGBM | 结构化数据王者 | 一棵一棵地种决策树,每棵纠正前一棵的错误 |
| 神经网络 | 复杂模式(图像/语音/文本) | 层层抽象,最深最强大但最难解释 |
五个经典算法的来历与脾气
表格能背,性格得讲。下面这几位是监督学习史上真正打过硬仗的选手,知道它们的出身年份和适用边界,选模型时你就不会靠感觉乱试。
先用五句大白话给它们各配一张名片,读下面的细节就不会晕:逻辑回归——算个总分再看够不够线,相当于银行给你打信用分;决策树——一层层问"是不是",好比分诊台的问诊单;随机森林——找几百个人投票,相当于科室开会会诊;SVM——在两拨人之间划一条尽可能宽的过道,就像教室里中间那条走道;XGBoost——一个人先干、后面的人专补前面没干完的,好比车间里的流水线返工工位。
逻辑回归(Logistic Regression)的名字有点误导——它做的是分类,不是回归。它的思路是先算一个线性得分 z = w1·x1 + w2·x2 + ... + b,再用 Sigmoid 函数把 z 压到 0–1 之间当概率。Sigmoid 这个 S 形函数的历史比机器学习老得多,1838 年比利时数学家 Verhulst 用它描述人口增长;1958 年统计学家 David Cox 把它系统化成今天的逻辑回归。它至今是银行信用评分卡的事实标准,原因不是精度高,而是每个系数都能翻译成一句人话——"月收入每增加五千元,违约概率的对数几率下降 0.31",这种话监管机构能审、法务能签字。任何监督学习项目都应该先跑一个逻辑回归当基线,如果复杂模型只比它高一两个点,说明瓶颈在数据不在模型。
决策树的现代形态来自 1986 年 Quinlan 的 ID3 算法和它的后继 C4.5,以及 1984 年 Breiman 等人的 CART。它的做法是每次挑一个特征、挑一个切分点,把数据切成两半,让切完之后两边"纯度"最高——纯度用信息增益(基于熵)或基尼不纯度来量化。它的两个优点非常实用:不需要做特征缩放(因为它只关心"大于还是小于",不关心数值量级),而且能自然处理类别特征和缺失值。缺点也很致命:一棵不加限制的树能一直分裂到每个叶子只剩一个样本,那就等于把训练集抄了一遍,纯粹的过拟合。所以实践中必须限制 max_depth、min_samples_leaf 这些超参数,或者做剪枝。
随机森林是 Breiman 在 2001 年正式提出的,它用两层随机性来治单棵树的过拟合:行随机(每棵树只用有放回抽样得到的一份数据,叫 Bagging)+ 列随机(每次分裂只从随机抽的一部分特征里挑)。两层随机让几百棵树彼此犯的错不一样,投票时误差相互抵消。它的口碑来自"几乎不用调参就能出成绩",还顺带给你一份特征重要性排名,非常适合项目早期快速摸清哪些特征有用。
SVM由 Vapnik 和 Cortes 在 1995 年推向成熟,核心思想是几何的:在两类点之间画一条"间隔最宽"的分界线,只有贴着边界的少数几个样本(支持向量)决定这条线的位置,其余样本挪动都不影响结果。它最漂亮的一招是核技巧(Kernel Trick)——通过把内积替换成核函数,等价于把数据映射到极高维空间再切开,而完全不用真的算出高维坐标。1990 年代到 2000 年代初,SVM 在文本分类、手写识别上是绝对霸主。它的硬伤是计算复杂度大约随样本数的平方增长,样本上到十万级就吃不消了,所以今天主要活在中小数据集和某些特殊核(比如生物序列)场景里。
XGBoost由陈天奇在 2014 年发布,属于梯度提升树家族。它和随机森林的根本区别是串行纠错而非并行投票:第一棵树粗略预测,第二棵树专门去拟合第一棵树留下的残差,第三棵树拟合前两棵合起来还没解决的残差……一层层把误差啃掉。XGBoost 在工程上做了三件关键改进:把二阶导数(Hessian)也用上让收敛更快、在目标函数里内置了对树复杂度的正则项、以及高度优化的并行分裂点查找。它上线后迅速统治了 Kaggle 表格类比赛——2015 年该平台上取得优胜的方案里有大量都用了它。2017 年微软的 LightGBM 用直方图算法和 leaf-wise 生长让速度又快了一个量级,这两个至今仍是结构化表格数据上的默认答案。
| 算法 | 提出年份 | 关键人物 | 要不要缩放特征 | 可解释性 |
|---|---|---|---|---|
| 逻辑回归 | 1958(Cox 系统化) | David Cox | 要 | 极高(系数可读) |
| 决策树 CART | 1984 / 1986 | Breiman / Quinlan | 不要 | 高(可画成图) |
| SVM | 1995 | Vapnik、Cortes | 要(很敏感) | 低(核函数后不可读) |
| 随机森林 | 2001 | Leo Breiman | 不要 | 中(有特征重要性) |
| XGBoost | 2014 | 陈天奇 | 不要 | 中(配 SHAP 可解释) |
| 神经网络 | 1986 反向传播普及 | Rumelhart、Hinton | 要 | 低(黑箱) |
最后给一条选型的实操顺序,这几乎是行业共识:表格数据先上 LightGBM/XGBoost,需要向监管解释就上逻辑回归,图像语音文本直接上预训练神经网络,样本少于一千条老实用简单模型加交叉验证。把神经网络硬套到只有八百行的表格数据上,是新手最常见的浪费。
训练的过程到底在干嘛
拿"房价预测"举例——你手里有 1000 套房的数据(面积 + 价格),想让模型学到"面积 → 价格"的关系:
1. 假设一个"带参数的公式"
比如 价格 = w × 面积 + b。w 和 b 是模型要学的参数,初始时随机给个值。
2. 用当前公式算一遍
对每套房:用公式预测价格,跟真实价格对比——差距就是"损失"(Loss)。
3. 调整 w 和 b,让损失更小
这一步叫"梯度下降"——往损失减少的方向,把 w 和 b 微调一点点。
4. 重复 2-3 几千次
每次都让损失更小一点。最终 w 和 b 稳定下来——模型训练好了。
你打靶——第一枪打在 7 环,偏左上。
教练说:"枪往右下挪一点。" 你调整,第二枪打在 8 环,还是偏一点点。
再调、再调——直到命中靶心。
机器学习做的就是这个:用误差指导调整,重复一千次,直到命中。
训练集 / 验证集 / 测试集
监督学习的数据必须分三份,缺一份都会翻车:
- 训练集(70%)模型"学"用的——模型在这上面不断调整参数。
- 验证集(15%)"模拟考试"——训练中途用来看效果,决定什么时候停。
- 测试集(15%)"期末大考"——只在最后用一次,看模型真实水平。
为什么必须是三份而不是两份?因为只要你根据某份数据的分数做过任何决定,这份数据就被"污染"了。你用验证集试了五十组超参数、挑了分数最高的那一组,这个动作本身就等于把验证集的信息编码进了模型的选择过程。此时验证集上的分数已经偏乐观,必须留一份从未参与任何决策的测试集来做最终验收。这个现象在学术界有个专有名词——"在测试集上过拟合",它是论文刷榜成绩和真实落地效果之间落差的主要来源之一。
换成大白话:训练集是作业本,验证集是模拟卷,测试集是高考卷。你拿模拟卷反复刷、刷到 140 分,这个 140 里有多少是真会、有多少是把这套模拟卷背熟了?说不清。所以高考卷必须是你从没见过的那一份——只考一次,考完就作废。谁要是把高考卷提前拿来当练习册用了,那个分数就一文不值。
数据量小的时候(比如只有两三千条),单独切出 15% 当验证集太浪费。这时用 K 折交叉验证(K-Fold CV):把数据均分成 5 份,轮流拿 1 份验证、4 份训练,跑 5 次取平均。这样每条数据都当过一次验证样本,结论稳定得多,代价是训练时间乘以 5。分类任务里还要用分层 K 折(Stratified K-Fold)——保证每一折里各类别的比例和总体一致,否则在不平衡数据上某一折可能一个正样本都没有。
5 折交叉验证的切法(■=验证 □=训练)
第 1 折 ■■□□□□□□□□
第 2 折 □□■■□□□□□□
第 3 折 □□□□■■□□□□
第 4 折 □□□□□□■■□□
第 5 折 □□□□□□□□■■
↓ 5 次分数取平均,得到更可靠的性能估计
时间序列数据的正确切法(绝不能打乱!)
├───── Train ─────┤├─ Val ─┤├─ Test ─┤
1月 ──────────── 9月 ── 10月 ── 11月 ──▶ 时间
还有一条容易被忽略的纪律:切分必须在特征工程之前完成。如果你先用全量数据算出"年收入的平均值",再拿这个均值去填所有缺失值(包括测试集的),那测试集的统计信息已经泄漏进了训练流程。正确做法是:只用训练集算均值、标准差、编码映射表这些统计量,然后把同一套参数应用到验证集和测试集上。scikit-learn 的 Pipeline 之所以存在,就是为了在代码层面强制这个纪律。
监督学习的痛点
- 标注成本高"答案"要靠人来标——医疗影像要资深医生标一张几块钱;自动驾驶要人工框每一帧的行人车辆。
- 标注可能错人会犯错——错标的数据会让模型学歪。
- 标注覆盖不全现实场景太多,标不完——所以模型遇到没见过的场景就翻车。
标注这门苦生意:ImageNet 的三年众包
要理解监督学习真正的成本,最好的教材是 ImageNet。2007 年,时任普林斯顿助理教授的李飞飞提出一个当时被同行认为不值得做的想法:不要再改进算法了,先建一个大到史无前例的图像数据集。她的依据是认知科学——人类儿童在三岁前通过眼睛接收的图像数量惊人,视觉智能可能首先是数据问题。
最初的方案是雇本科生标注,算下来需要将近九十年才能标完。转机出现在 2007 年底:一位同事提到了亚马逊的众包平台 Mechanical Turk。把任务拆成"这张图里有没有猫"这种一秒钟能答完的微任务,分发给全球数万名素不相识的兼职工人,成本瞬间被压到可接受范围。最终 ImageNet 在 2009 年发布时,包含约 1400 万张标注图片、覆盖 2 万多个类别,动用了来自 167 个国家的约 4.9 万名标注者,历时约两年半。
1400 万张是个什么量级?打个比方:如果你一秒看一张、一天不吃不睡看 24 小时,需要连着看 162 天;要是按每天上班 8 小时算,得看将近 五年。4.9 万名标注者相当于把一座中等县城的成年人全拉去干这件事。所以那句"监督学习最大的成本是标注"不是修辞——它是实打实的五年工时和几十万人日。
这件事的意义在三年后才彻底显现:2012 年,Hinton 组的 AlexNet 在 ImageNet 竞赛上把 Top-5 错误率从上一年的 26.2% 直接砍到 15.3%,引爆了深度学习十年。深度学习的爆发不是先有算法后有数据,而是先有数据才让算法显形——卷积网络的核心思想 1989 年就有了(LeCun 的 LeNet),它等了二十三年,等的就是这批标注。
众包标注不是万能药,它有自己的三个硬约束。第一,任务必须"外行也能做"——"图里有没有猫"人人会答,"这块阴影是不是早期肺结节"则必须放射科医生来,价格立刻从几分钱一张跳到几十元一张。第二,必须做冗余——同一张图派给多个标注员,用投票或更复杂的聚合算法(比如加权多数投票、EM 估计标注员可靠性)来抗噪。第三,必须有质检机制——插入已知答案的"金标准题"混在任务流里,用来实时识别乱点的工人。
标注质量:Kappa 系数与"标准答案不标准"
新手会默认"标签就是真相"。真做过项目的人知道,标签本身就是一份充满噪声的估计。同一份数据交给两个标注员,他们不一致的比例常常高得惊人——情感分析里"这产品还行吧"算正面还是中性?医学影像里两位资深放射科医生对同一张片子的判读一致率在很多研究中只有七八成。
为了量化这件事,业界用 Cohen's Kappa 系数。它的巧妙之处在于扣除了"瞎猜也会碰巧一致"的部分。假设两个标注员对一千条评论做二分类,直接一致率 85% 看起来不错;但如果数据里 90% 都是正面,两个人各自都乱猜"正面",光靠概率就能撞上 81% 的一致率——那 85% 就几乎毫无信息量。Kappa 的公式正是为了消掉这一项:
这个思路其实就是我们生活里的常识。就像两个人各自猜硬币正反,一百次里总会有五十次左右"意见一致"——这五十次一致完全不代表他俩有共识。Kappa 干的活儿就是先把这部分"闭着眼也能撞上的一致"扣掉,剩下的才算真本事。
Kappa = (Po - Pe) / (1 - Pe)
Po = 实际观察到的一致比例
Pe = 纯靠随机也能达到的期望一致比例
解读的经验区间(Landis & Koch, 1977):
< 0.20 极差 —— 标注规范基本失效,必须重写指南
0.21 ~ 0.40 一般
0.41 ~ 0.60 中等 —— 很多真实 NLP 任务就在这个区间
0.61 ~ 0.80 良好 —— 可以开始训模型了
> 0.80 优秀 —— 通常说明任务本身比较客观
多于两个标注员时,改用 Fleiss' Kappa;
标签有顺序(1~5 星)时,用 Weighted Kappa,让"差一档"比"差四档"罚得轻。
这个数字的工程价值极大:Kappa 低于 0.4 时,别急着调模型,先回去改标注指南。因为人和人都达不成共识的任务,模型的天花板早就被锁死了——你测出来的 90% 准确率,很可能只是模型学会了模仿某几个特定标注员的个人偏好。这也解释了一个反直觉的现象:有时候把 10 万条脏标签换成 1 万条干净标签,模型反而变强了。
成熟团队的标注流程通常长这样:写标注指南 → 小批量试标 100 条 → 计算 Kappa → 开会消解争议、修订指南 → 再试标 → Kappa 达标后才全量开工 → 全程插入金标准题做质检 → 定期抽检并回溯修正。这套流程听起来笨重,但它是监督学习项目里投资回报率最高的一段工作,远高于换一个更花哨的模型。
标注太贵怎么办:弱监督、半监督与主动学习
既然标注是瓶颈,工业界发展出了一整套"少标一点也能干活"的路子。它们不是学术玩具,而是每天在真实项目里省钱的工具。
半监督学习(Semi-Supervised)的设定是:少量标注 + 海量未标注。最简单也最常用的做法是伪标签(Pseudo-Labeling):先用那 1000 条标注数据训一个模型,拿它去预测 10 万条未标注数据,把模型置信度超过 0.95 的那些预测当成"真标签"加进训练集,重训一遍。它的原理依赖一个假设——决策边界应该落在数据稀疏的地方,未标注数据的分布本身就在告诉你边界该往哪放。风险也很明显:模型一旦有系统性偏见,伪标签会把这个偏见固化并放大,这叫"确认偏误"。所以实践中要配合高置信度阈值、类别平衡采样和多轮迭代。
弱监督学习(Weak Supervision)的思路更激进:既然精标太贵,那就用"不精确但便宜"的标签凑。它有三种典型形态:不完全监督(只有一小部分样本有标签)、不确切监督(只知道"这张 X 光片里有病灶",但不知道在哪个位置——这催生了多示例学习 MIL)、不准确监督(标签本身有错,需要模型自带抗噪能力)。斯坦福 2016 年之后推出的 Snorkel 系统把这套东西工程化了:让领域专家写一堆"标注函数"(比如"包含'点击链接领取'就大概率是诈骗"),这些规则各自都不准、还互相冲突,Snorkel 用生成模型估计每条规则的可靠度并融合,产出概率标签。用一天写二十条规则替代三个月的人工标注,这在很多企业场景里是唯一可行的方案。
主动学习(Active Learning)解决的是另一个问题:如果只能标 1000 条,标哪 1000 条最划算?答案显然不是随机抽——模型已经答得很有把握的样本,标了也学不到东西。主动学习让模型自己挑"最想知道答案"的样本交给人标,常见的挑选策略有三类:
这件事说白了就是"把有限的问老师额度花在最该问的题上"。你复习时间只剩一晚,是把已经会的题再抄一遍笔记,还是专挑那几道一直卡着的去问老师?答案不用想。主动学习本质上就是让模型自己圈出错题本,再拿这本错题去办公室找老师,一道一道要答案。
| 策略 | 怎么挑 | 直觉 |
|---|---|---|
| 不确定性采样 | 挑预测概率最接近 0.5 的样本 | 模型最纠结的题,最值得问老师 |
| 边际采样 / 熵最大 | 挑前两名类别概率最接近的,或熵最高的 | 多分类下的推广版 |
| 委员会投票分歧 | 训多个模型,挑它们意见最不一致的 | 专家们吵得最凶的病例最有信息量 |
| 多样性 / 代表性采样 | 挑能覆盖数据分布不同区域的 | 避免全挑到同一个角落的怪样本 |
主动学习在实践中经常能用 20%–40% 的标注量达到全量标注的效果,尤其在医疗、工业质检这类标注单价极高的领域,收益直接体现在预算上。它的实施难点是工程流程——需要一个"模型训练 → 挑样本 → 人工标注 → 回流重训"的闭环平台,而不只是一个算法。
# 主动学习循环(伪代码)
L = 已标注池(初始很小,比如 200 条)
U = 未标注池(很大,比如 50 万条)
while 标注预算 > 0:
model = train(L) # 用现有标注训一版
scores = [uncertainty(model, x) for x in U]
batch = top_k(U, scores, k=100) # 挑模型最纠结的 100 条
labels = ask_human(batch) # 只让人标这 100 条
L += zip(batch, labels)
U -= batch
预算 -= 100
# 关键:每一轮都在"把标注预算花在信息量最大的地方"
还要提一句迁移学习这条最省力的路:与其从零训练,不如拿一个在 ImageNet 或海量文本上预训练好的模型,只用你那几百条标注数据微调最后几层。今天做一个"识别自家产线上的三种缺陷"的任务,每类三百张图往往就够了——因为通用的边缘、纹理、形状特征已经由别人的算力和别人的标注买单了。这是过去十年里让监督学习门槛下降最快的一件事。
这就是为什么大模型时代要转向自监督学习(§ 4.4)——不再依赖人工标注。
监督学习在你生活中的样子
| 你做的事 | 背后的监督学习 |
|---|---|
| 用脸解锁手机 | 模型学过你的脸(分类:是/不是) |
| 相机自动识别"人像模式" | 模型学过"什么是人"(分割) |
| 抖音推荐下一个视频 | 模型学过"看过 X 的人也喜欢 Y"(回归:停留时长) |
| 邮箱自动过滤垃圾邮件 | 模型学过"垃圾邮件的特征"(分类) |
| 输入法联想下一个词 | 模型学过"什么词后面通常跟什么"(分类) |
| 导航预估到达时间 | 模型学过"历史通行数据"(回归) |
一个监督学习项目的真实翻车清单
最后这一节最实用。下面每一条都是真实项目里反复出现的失败模式,认识它们比多学三个算法有用。
其中最要命的是"数据泄漏",这个词听着玄,换成大白话就是:你偷看了答案还以为自己会做。好比用"这个人已经住院了"去预测"这个人会不会生病"——线下看准得离谱,真上线的时候那一栏还是空的,因为病人还没去医院。判断法则只有一句:做预测的那一刻,这个字段真的已经填上了吗?
- ① 标签定义没对齐业务方说"预测用户会不会流失",但"流失"到底是 30 天不登录还是 90 天不下单?定义不同,模型完全是两个东西。动手前必须把 y 的定义写成一句无歧义的 SQL。
- ② 数据泄漏用"是否已退款"预测"是否会退货",用"账号是否已被封禁"预测"是否为欺诈账号"。这类特征在训练集里和标签高度相关,线下 AUC 能到 0.99,上线立刻归零——因为预测时刻那个字段还是空的。判断法则:这个特征在做预测的那一刻真的已经存在了吗?
- ③ 时间穿越用随机打乱切分时序数据,训练集里混进了未来样本。正确做法是按时间切:用 1–9 月训练、10 月验证、11 月测试。
- ④ 训练与线上特征不一致离线用 Pandas 算的"近 7 天消费额"和线上 Java 服务算的口径差了一天,模型效果凭空掉几个点。这叫训练-服务偏斜(Training-Serving Skew),是 MLOps 里"特征平台"存在的全部理由。
- ⑤ 分布漂移模型上线三个月后悄悄变差,因为用户群变了、竞品改了策略、大促改变了行为模式。监督学习模型是会腐坏的资产,必须监控预测分布并定期重训。
- ⑥ 指标选错在 0.04% 正样本的场景里汇报准确率,或者在需要高召回的医疗场景里优化精确率。指标选错,整个项目的努力方向就错了。
- ⑦ 测试集被反复使用用测试集试了三十组超参数,挑最高分那组——这个分数是虚的,你已经把测试集的信息偷偷训进了模型。测试集理想情况只看一次。
把这七条和前面的内容串起来,监督学习的完整心法可以压缩成一句话:先把标签定义清楚、把标签质量测出来、把泄漏堵死、选对指标,剩下的模型选择只是最后 10% 的工作。这句话不性感,但它是这行业最贵的经验。
监督学习 = "老师一边教一边打分"。它是工业界最成熟、最常用的方法,但需要大量"标注好的数据"。
下一篇我们看"没有老师"的学习——无监督学习。