第二部 · 学习第 4 章 / 14

规则不是写出来的,是学出来的

机器学习的全部核心思想,其实只有一句话。这一章用一笔网约车订单把它讲透。

主线 9 分钟 · 深入 7 段 · 实验 3 个
一辆车,几亿笔订单,一个模型。
一辆车,几亿笔订单,一个模型。

一辆网约车从徐家汇开到浦东机场,平台要在你上车前报出一个价。三十年前,这个价会由一张收费表决定:起步价多少,每公里多少,夜间加成多少。表是人定的,写进程序,程序按表算。

今天的平台不用表。它用的是一个模型:把过去几亿笔订单的距离、时段、天气、供需状况和最终成交价喂进去,让模型自己找出「什么样的行程值多少钱」的规律。没有人写过「雨天晚高峰加价 23%」这条规则,但模型的行为里包含了它,而且比人写的更细。

这就是机器学习。这一章要做的事只有一件:把「让模型自己找规律」这句话拆开,看清每一个零件。这些零件在后面的神经网络和大语言模型里一个都不会少,只是尺寸变大了。

一句话的范式转变

传统编程是这样的:人写出规则,程序把输入按规则变成输出。规则是输入,是程序员提供的。

机器学习把这个关系翻转:人提供输入和对应的正确输出(大量的例子),机器找出把前者变成后者的规则。规则是输出,是学习过程产生的。

传统编程:规则 + 数据 → 答案。 机器学习:数据 + 答案 → 规则。

第二章讲过为什么要这样翻转:很多规则人写不出来。你说不清一张照片里「猫」的判据是什么,但你能轻松标出一万张有猫的照片。你说不清一笔行程该值多少钱,但你有一亿笔已经成交的行程。当规则难写而例子好找,机器学习就是那条路。

代价也在这里:学出来的规则不是 if-then,而是几千到几千亿个数字,人读不懂它,只能测试它。这是机器学习「黑箱」性质的根源,后面每一章都会撞上它。

三个零件:数据、模型、目标

任何机器学习系统都由三部分组成。用网约车来对应。

数据。一笔订单在机器眼里是一行数字:距离 12.3 公里,时段 18 点,星期五,降雨 1,起点区域编号 7,当时附近空车数 4……这一行叫一个样本,每个数字叫一个特征。如果这笔订单已经成交,最终价格就是它的标签,也就是我们希望模型学会预测的那个答案。一亿个样本排成一张大表,就是训练数据。

把现实变成这张表的过程叫特征工程,它比听起来重要得多。「星期几」这个特征对预测车费有用,「乘客手机型号」大概没有;「当前时刻」不如「距离早高峰还有几分钟」有用。在深度学习之前,机器学习工程师的大部分时间花在这里,而深度学习最大的贡献之一,就是把这一步也交给了机器。第六章讲这件事。

「把一笔订单变成一行数字」听起来简单,实际做起来全是判断。下面是一个定价模型可能用的特征,以及每一个背后的考虑。

特征 怎么算 为什么要它 / 陷阱
路程距离 路网最短路(不是直线) 最重要的特征;用直线距离会低估跨江订单
预计时长 地图服务的估计 和距离高度相关,但雨天两者会分开
出发时刻 拆成「小时」和「是否工作日」 直接用时间戳没意义,模型需要周期性
距高峰的分钟数 与最近的早晚高峰的时间差 比「小时」更贴近真实的供需变化
天气 降雨量、温度 雨天需求激增;注意用的是「下单时」的天气,不是行程结束时的
起点区域供需比 附近 2 公里的空车数 ÷ 等待订单数 这是溢价的核心,但它随时在变,训练时必须用「当时」的快照
起点 / 终点类型 机场、车站、商圈、住宅 类别特征,要编码成数字
是否节假日 查节假日表 春节前的一周比法定假日更特别
乘客历史订单数 用户过去的下单数 用于预测「会不会取消」,用于定价时要小心公平性问题
当前活动 演唱会、赛事散场 很难自动获得,常靠人工维护的日历

三个观察。一,很多特征是对原始数据的「翻译」,比如把时间戳拆成周期;这一步做得好坏,对传统机器学习模型影响巨大。二,几个特征带有时间陷阱:必须用「下单那一刻能知道的信息」,用事后才知道的信息就是第五章的标签泄漏。三,最后一个特征提醒我们,模型再好,也需要人维护它看不到的世界。深度学习把这张表里的很多手工判断交给了网络,但「用什么时刻的数据」这类问题,它交不出去。

模型。模型是一台带旋钮的机器:输入一行特征,输出一个预测。最简单的模型是一条直线,价格 $= w_1 \times$ 距离 $+ w_2 \times$ 时长 $+ b$。这里的 $w_1$、$w_2$、$b$ 就是旋钮,术语叫参数。旋钮拧到不同位置,同样的输入会给出不同的输出。「学习」,就是找到一组让预测尽量准的旋钮位置。

模型:一台带旋钮的机器。学习就是找到旋钮的位置。
模型:一台带旋钮的机器。学习就是找到旋钮的位置。

一条直线只有三个旋钮,能表达的规律很有限。多项式可以弯曲,决策树可以分段,神经网络可以有几十亿个旋钮。模型越复杂,能表达的规律越丰富,但也越容易学到不该学的东西,第五章讲这个矛盾。

目标与优化。有了数据和模型,还需要回答两个问题:错了多少?怎么改?

「错了多少」由损失函数回答。对车费预测,最自然的损失是预测价与真实价之差的平方,在所有样本上求平均。损失越小,模型越准。损失函数把「好不好」这个模糊的评价变成了一个可以计算、可以比较的数。

「怎么改」由优化算法回答。最常用的是梯度下降:对每一个旋钮,计算「把它稍微往右拧一点,损失会增大还是减小」,然后往减小的方向拧一小步。对所有旋钮同时做这件事,重复几千几万次,损失就一路下降。梯度下降就像蒙着眼睛下山,每一步都摸一摸脚下哪边更陡,往低处迈一小步。它不保证到达最低的谷底,但在实践中出奇地有效,而且它就是训练万亿参数大模型时用的那个算法,一个字都没变。

蒙着眼睛下山:摸坡度,迈一小步。
蒙着眼睛下山:摸坡度,迈一小步。
旋钮的位置 → ↑ 损失 起点:随机的旋钮 停在这个谷底 更低的谷在这里,但从左边出发看不见它 每一步:摸脚下的坡度,往低处迈一小步
梯度下降:沿着损失下降的方向一小步一小步走。它可能停在一个局部的谷底。

假设模型只有两个旋钮 $w_1$、$w_2$,那么损失 $L(w_1, w_2)$ 就是一张二维地形图,横纵坐标是两个旋钮的位置,高度是损失。学习的目标是找到地形的最低点。

梯度就是在当前位置「最陡上坡」的方向,写作 $\nabla L = (\partial L/\partial w_1,\ \partial L/\partial w_2)$。梯度下降的更新规则是:

$$w \leftarrow w - \eta \nabla L(w)$$

减号表示往下坡走,$\eta$ 是步长,术语叫学习率。步长太小,下山慢得像蜗牛;步长太大,会在山谷两侧来回跳,甚至越跳越高。调学习率是训练里最常见的手工活。

真实模型有几百万到几千亿个旋钮,地形是几千亿维的,没有人能画出来,但算法完全一样:算梯度,走一小步,重复。有两个实践细节值得知道。一是不需要用全部数据算梯度,随机抽一小批样本估计一下就够了,这叫随机梯度下降,它不但省算力,抽样带来的噪声还能帮助模型跳出一些浅坑。二是对神经网络来说,几十亿个旋钮的梯度可以用一种叫反向传播的方法一次性高效算出来,第六章讲。

用最小的例子把「学习」从头算一遍。假设我们只用距离预测车费,模型是一条直线:$\hat{y} = w \cdot x + b$。两个旋钮,$w$ 是每公里单价,$b$ 是起步价。手里有三笔订单:

距离 $x$(公里) 实际车费 $y$(元)
2 14
5 23
10 38

随便起一个初始值:$w = 1$,$b = 0$。三笔预测分别是 2、5、10,和真实值差得很远。损失用均方误差:

$$L = \frac{1}{3}\big[(2-14)^2 + (5-23)^2 + (10-38)^2\big] = \frac{144 + 324 + 784}{3} \approx 417$$

算梯度。对 $w$ 求偏导:$\partial L/\partial w = \frac{2}{3}\sum (\hat{y}_i - y_i)\,x_i = \frac{2}{3}[(-12)(2) + (-18)(5) + (-28)(10)] = \frac{2}{3}(-394) \approx -263$。对 $b$:$\partial L/\partial b = \frac{2}{3}\sum(\hat{y}_i - y_i) = \frac{2}{3}(-58) \approx -39$。两个梯度都是负的,意思是「把旋钮往大调,损失会下降」。

取学习率 $\eta = 0.01$,更新:$w \leftarrow 1 - 0.01 \times (-263) = 3.63$,$b \leftarrow 0 - 0.01 \times (-39) = 0.39$。再算一遍损失,已经降到 50 左右。重复几百次,$w$ 会收敛到 3 附近、$b$ 到 8 附近:每公里三元,起步八元。没有人告诉模型这两个数字,它们是从三笔订单里「学」出来的。

真实模型和这个例子的区别只有规模:旋钮从两个变成几千亿个,样本从三笔变成几万亿个 token,其余的每一步都一样。

损失函数把「错了多少」变成数字,但「错」可以有不同的算法,选择取决于任务和你对错误的态度。

均方误差:预测与真实之差的平方的平均。它对大错误惩罚极重(差 10 元的惩罚是差 1 元的一百倍),适合「大错误特别不能接受」的回归任务,也是数学上最好处理的一种。缺点是对异常值敏感:一笔录入错误的天价订单会把整个模型拉偏。

绝对误差:差的绝对值的平均。对每一元的错误一视同仁,对异常值稳健。当数据里有脏值、或者你关心的是「典型情况下差多少」时,它更合适。

交叉熵:分类任务的标准损失。模型输出的是每个类别的概率,交叉熵衡量「真实类别被分到的概率有多小」:真实类别概率 0.9 时损失很小,0.01 时损失很大。它的一个重要性质是惩罚「自信地错」远超「犹豫地错」,这与第十章讲的校准直接相关。大语言模型预训练用的就是它:每一步预测下一个 token 的交叉熵。

选损失函数时的一条经验:先问「什么样的错误最贵」,再选那个对这种错误惩罚最重的函数。这一步是把业务判断写进数学的地方,值得由懂业务的人参与。

本章讲的是梯度下降,因为它通向神经网络和大模型。但在表格数据(订单、病历、学生记录)上,至今用得最多的常常不是神经网络,而是决策树的家族。

决策树学出来的东西是一连串问题:「距离大于 10 公里吗?是的话,是高峰期吗?是的话,价格约 45 元。」它的构造不用梯度,而是贪心地选择每一步「最能把数据分开」的问题。它的优点是人能读懂,缺点是容易过拟合,一棵树会长到把每个样本都单独分出来。

随机森林训练几百棵树,每棵只看一部分数据和一部分特征,最后投票。单棵树的过拟合被平均掉了,准确率大幅提高。梯度提升树则一棵接一棵地训练,每棵专门去修正前面所有树的错误,它的名字里有「梯度」,因为「该往哪个方向修正」是用梯度算的,但树本身仍然不是梯度下降训练的。

为什么在表格数据上树常常打败神经网络?一个解释是表格特征各有各的尺度和含义,树天然能处理「距离」和「是否节假日」这种性质完全不同的特征,而神经网络需要仔细的预处理。另一个原因是数据量:几万行的表格不足以喂饱一个深度网络。所以第四章的一条实用建议是:在表格数据上,先跑一个梯度提升树作为基线,再考虑别的。

四种学习方式

按「答案从哪里来」,机器学习分成几个范式。

监督学习:数据带标签。历史订单有成交价,照片有人标了「猫」,邮件被标过「垃圾」。模型学习从特征到标签的映射。这是最成熟、应用最广的一类,识别和预测两种能力几乎都来自它。它的瓶颈是标签贵:一百万张标注好的医学影像,需要放射科医生花几年。

无监督学习:数据没有标签,模型只能找结构。把一亿个乘客按出行习惯自动分成几群,把新闻按主题自动归类,在交易记录里找出「和别的都不像」的异常。它不告诉你每一群是什么,只告诉你数据里有这样的分野。

强化学习:第三章讲过。没有标签,只有行动之后的奖励。它学的不是「这个输入对应什么输出」,而是「这种情况下该做什么」。

自监督学习:这是过去十年最重要的新范式,也是大语言模型的根基。它的想法是从数据本身制造标签:把一句话遮住一个词,让模型猜;把一段文字截断,让模型续写。标签就藏在数据里,不需要人标,所以可以用整个互联网来训练。第七章开始讲它怎么造出语言模型。

监督学习的每一个标签背后都是人的时间。ImageNet 的一千四百万张图片是几年间几万名众包工人标出来的;自动驾驶公司雇了大量标注员逐帧框出行人和车辆;一个能读病理切片的模型,需要病理医生逐张标注肿瘤边界。标签不但贵,还会带进标注者的偏见和错误。

于是有了一系列绕开它的办法。半监督学习用少量标注数据加大量未标注数据,先用标注部分训练一个粗模型,再让它给未标注部分打「伪标签」。主动学习让模型自己挑最不确定的样本请人标注,把人的时间用在刀刃上。迁移学习在一个大数据集上训练好的模型,换个任务只需少量新数据微调,这是深度学习时代的默认做法。自监督学习则彻底不要人工标签,它的巨大成功是大语言模型能出现的直接原因。

对使用者来说,这一段的实用结论是:当有人说「我们的模型在某任务上准确率 98%」,值得追问的是「标签是谁标的、怎么标的」。模型学到的上限,是标签的质量。

一个完整的项目

把这些零件装起来,一个机器学习项目长这样:

  1. 定义任务:预测什么?用什么指标衡量好坏?错了的代价是什么?
  2. 收集数据:哪些历史记录可用?它们能代表未来吗?有没有偏差?
  3. 构造特征:把原始记录变成模型能用的数字。
  4. 划分数据:一部分用来训练,一部分留着最后考试。这一步是第五章的主角。
  5. 训练:选模型,跑梯度下降,看损失下降。
  6. 评估:在留出的数据上考试,看指标。
  7. 部署与监控:上线,然后盯着它,因为世界会变。

在实际项目里,第一步和第二步花的时间通常远超第五步。「用什么模型」往往是最不重要的决定;「预测的是不是对的东西」和「数据里有没有陷阱」才是。

传统编程 规则 数据 程序 答案 机器学习 数据 答案 训练 规则 一个项目的七步 1 定义任务预测什么、错了谁担 2 收集数据能代表未来吗 3 构造特征记录变成数字 4 划分数据留一份最后考 5 训练梯度下降 6 评估在没见过的数据上 7 部署与监控世界会变 第 7 步发现分布偏移,就回到第 2 步。时间大多花在第 1、2 步,而不是第 5 步。
上:传统编程与机器学习的翻转。下:一个项目的七步,最后一步会把你送回第二步。

把七步流程套在一个具体的教育场景上走一遍,看每一步会撞到什么。假设一所高中想在期中前找出「期末可能不及格」的学生,提前干预。

1. 定义任务。预测什么?「期末不及格」是一个清楚的标签。但先问:预测出来之后做什么?如果是让班主任多谈一次话,误报的代价很低;如果是把学生分到「补差班」,误报的代价是伤害一个原本正常的孩子。这个答案决定了后面的一切。

2. 收集数据。过去三年的出勤、作业提交、测验成绩、平台登录记录,以及期末成绩。立刻遇到的问题:三年前的教材和考试方式变了;去年这个年级换了老师;平台是前年才上线的,更早的登录记录是空的。

3. 构造特征。「作业提交率」「最近三次测验的趋势」「距上次登录的天数」。陷阱:「是否参加了补习班」这个特征只在期末后由老师补录,用它就是标签泄漏。

4. 划分数据。按学年切:前两年训练,最近一年测试。不能随机打乱,否则模型会「偷看」同一学年的同学。

5. 训练。一个梯度提升树,二十分钟。这是整个项目最轻松的一步。

6. 评估。准确率 91%。但不及格率只有 12%,所以要看召回率:模型找出了多少真正不及格的学生?答案是 55%。也就是说它漏掉了近一半,而它标出的学生里有三成实际上及格了。这个模型能用,但要当作提示而不是判决。

7. 部署与监控。上线后一个学期,召回率降到 40%。原因:学校推行了新的作业平台,「提交率」这个特征的含义变了。回到第二步。

这个例子里没有任何一步是技术难题,每一步都是判断。这就是本章开头那句话的另一面:机器学习把规则交给了机器,却把更多的判断留给了人。

从网约车到你的领域

机器学习的语法是通用的。把「网约车订单」换成「学生的学习记录」,特征变成出勤、作业提交、测验分数、在线时长,标签变成「期末是否及格」,就是学情预警。换成「病人的检查数据」和「三十天内是否再入院」,就是临床预测。换成「一篇文章的词频」和「它的主题」,就是文本分类。

每换一个领域,三个问题一定要重新问:数据从哪来,能不能代表要预测的对象?标签是什么,它真的是我们关心的那个东西吗?错了的代价由谁承担?学情预警模型把一个学生标成「高风险」,如果老师因此多关注他,是好事;如果系统因此把他分到差班,就是另一回事。模型给概率,人给决定,这个分工在本书后面会反复出现。

带走一句话

机器学习是:用数据和答案,让一台带旋钮的机器通过不断减小损失,自己找到规则。规则藏在旋钮的位置里,人读不懂,但可以测试。

自测先自己想,再点开答案
  1. 「传统编程把规则当输入,机器学习把规则当输出。」用网约车的例子解释这句话。

    答案

    传统做法是人定一张收费表(规则),程序按表计算价格。机器学习做法是把历史订单(数据)和成交价(答案)交给模型,模型自己找出「什么行程值多少钱」的规律,这个规律是学习的产物。

  2. 损失函数和评估指标有什么区别?

    答案

    损失函数是训练时用来指导旋钮往哪拧的数学量,必须可导、可计算,比如均方误差。评估指标是我们真正关心的业务量,比如「预测价与实际价相差 10% 以内的比例」。两者常常不同,训练优化的是前者,最后汇报的是后者。

  3. 自监督学习为什么能用「整个互联网」训练,而监督学习不能?

    答案

    监督学习需要人为每个样本提供标签,成本随数据量线性增长。自监督学习从数据自身制造标签(遮一个词让模型猜),不需要人工,所以数据量只受限于能收集到多少文本。

  4. 一个学情预警模型准确率 90%,老师该怎么用它?

    答案

    把它当作提示而不是判决:模型给出概率,老师去了解这个学生的实际情况再决定做什么。还要问准确率是在什么数据上测的、是否覆盖了本校学生、以及误报和漏报各自的代价。

本章术语

样本与特征Sample & feature

样本是训练数据里的一条记录(一笔订单、一张照片);特征是描述这条记录的各个数值(距离、时段、像素)。把现实变成特征的过程叫特征工程,在深度学习之前是机器学习工程师的主要工作。

标签Label

监督学习中希望模型学会预测的那个答案:订单的成交价、照片里是不是猫。标签通常由人提供,昂贵且可能带入标注者的偏见与错误。模型学到的上限是标签的质量。

模型与参数Model & parameters

模型是一台「带旋钮的机器」:输入特征,输出预测。旋钮就是参数(权重、偏置),学习就是找到让预测尽量准的参数取值。参数从一条直线的三个到大语言模型的上万亿个。

损失函数Loss function

把「模型错了多少」变成一个可计算、可比较的数,例如预测值与真实值之差的平方的平均。训练就是不断调整参数使损失下降。损失函数(训练用)与评估指标(最终汇报用)常常不同。

梯度下降Gradient descent

最常用的优化算法:对每个参数计算「稍微改动会让损失增大还是减小」(梯度),沿减小的方向走一小步,反复进行。像蒙眼下山。步长叫学习率。它就是训练万亿参数模型时用的那个算法。

监督学习Supervised learning

用带标签的数据训练模型,学习从特征到标签的映射。最成熟、应用最广的范式,识别与预测两类能力主要来自它。瓶颈是标签昂贵。

无监督学习Unsupervised learning

数据没有标签,模型只能寻找结构:把样本自动分群、发现异常、压缩表示。它不告诉你每一群是什么,只告诉你数据里存在这样的分野。

自监督学习Self-supervised learning

从数据自身制造标签:遮住一个词让模型猜、截断一段文字让模型续写。不需要人工标注,因此可以用整个互联网训练。它是大语言模型能出现的直接原因。

训练Training

用数据反复调整模型参数以降低损失的过程。一个完整项目还包括定义任务、收集数据、构造特征、划分数据、评估、部署与监控,其中「用什么模型」往往是最不重要的决定。