在机器学习领域,我们经常用两个词来描述模型的过程:学习(learning) 和 训练(training) 。这两个词听起来很合理——模型看了很多数据,然后做出一些预测,好像“学会”了什么。
但书里说得非常实在:
我们其实是带着点无奈才用这两个词的。
为啥?因为它们容易让人产生误解。
你是不是经常听说:
- “AI学会下棋了”
- “大模型正在学习如何写诗”
- “这模型越来越像人了”
听起来是不是感觉模型真的像人一样,在思考、在理解、在自我进步?但——
错了!模型一点也不像人。
用“学习”这个词,其实是个比喻,它掩盖了模型真正的行为本质。
真实情况是:
- 模型没法“理解”什么,它只是把词和词之间的关系记在一个巨大的表格里(准确来说是向量空间)。
- 它不会“自己反思”,也不会“顿悟”。
- 它不会问“我有没有学到真正的意义”。
说白了,模型只是一个超级复杂的数学函数,
我们让它根据一些输入,反复调整自己的“系数”,
直到预测的结果和答案越来越接近为止。
再通俗一点说:
模型不是学生,它更像是一台参加无数次模拟考试、
然后根据错题不断擦改答案的打字机。
所以:
虽然我们继续用“学习”“训练”这些词是为了交流方便,但你一定要知道:
它们不是人类学习的那种学习。
我们人类学一个技能可能要几年,但还会出错、忘记、举一反三、产生直觉……
模型不一样,它就是机械地:
数学公式 + 海量计算 + 重复迭代(上亿次)
4.1 梯度下降:模型“变聪明”的数学秘诀
你要是问一个AI工程师:“大模型是怎么学会写诗、写代码的?”
他们十有八九会甩出一个术语——梯度下降(Gradient Descent) 。
别被吓到,这玩意虽然听起来像某种山地骑行,但其实逻辑特别简单:
模型想做对题,就得知道“自己错在哪”,
然后“往对的方向调整”,
一次不行就多来几亿次,直到越来越对。
这整套过程的核心有两个关键元素:
1. 损失函数(Loss Function)
你得有个指标能告诉模型:
“你答得有多烂。”
它的作用就是每次模型输出之后,计算一个分数,
这个分数越大,说明模型答得越差。
我们就用这个分数来衡量模型的“失败程度”。
你可以把它想象成考试的扣分标准:
答错了多少,扣多少,想办法“少扣分”。
2. 梯度下降(Gradient Descent)
知道错在哪还不够,关键是:
怎么改?
这就得靠“梯度”了。
梯度是什么?你可以把它理解成“方向感”,它告诉模型:
- 现在往哪个方向调整参数,才能让下次不犯同样的错。
就像你被困在雾霾山谷,想走到最低点(最低的错误),
你每一步都靠“哪边地势更低”来决定往哪走——
**这就是“梯度”**在起作用。
而“下降”就是朝着错误更小的方向前进。
这两个东西加在一起,就是模型“学习”的本质:
- 用损失函数告诉自己错了多少
- 用梯度下降不断微调,直到错误最小
4.1.1 什么是好损失函数?
我们举个非常接地气的例子:赚钱。
想象你有个“智能模型”,你希望它帮你赚钱。那你需要一个“评分机制”,来告诉模型:
“你表现得怎么样?”
这就是“损失函数”的作用。但这函数不能随便写,要满足三大标准:
✅ 1. 明确具体(Specific)
不能模棱两可,比如:
❌ 坏例子:“让AI变聪明!”
太宽泛了,到底是要会算数学?还是懂人生哲理?
✅ 好例子:“让AI通过某个财务考试”,这就具体了,模型可以对着题库练习。
✅ 2. 能算出来(Computable)
这个函数得能用电脑算出来,速度还得快。
不能是那种:“让AI预测人类幸福感”——算都算不出。
✅ 3. 平滑(Smooth)
函数变化要“温和”。输入稍微变动,输出别一下子暴涨暴跌。
就像你调味料撒多了一点,味道有点变化,合理。
但要是一粒盐进去就变剧毒——这就不行了。
✅ 一个好例子:债务(Debt)
我们可以把“损失”想象成“负债”:
- 你当然想让负债越小越好
- 最好还能变负,变成别人欠你钱!
“债务”具备上面三个好损失函数的特征:
- 明确:你就是想让它越来越小
- 可计算:一查余额就知道
- 平滑:多花点少花点,影响是连续的
所以,当我们训练模型时,也会想办法设计出类似“债务”这样的损失函数:
具体、可算、可优化,能持续变得更小。
💡 名词说明小贴士:Loss、Objective、Reward 傻傻分不清?
你在看机器学习资料时,会发现有些人把 “loss function(损失函数)” 叫成:
- objective function(目标函数)
- 或者 reward function(奖励函数)
这让很多刚入门的朋友头大:“到底这仨是不是一回事?”
✅ 统一理解:
不管叫啥,它们干的都是一件事:
给模型的输出打分,告诉它表现好不好。
❗为什么不建议新手用“Objective Function”?
虽然很多论文喜欢用这个词,但它有点歧义:
- 有时候你是希望“最小化”目标(比如亏损、债务)
- 有时候你是希望“最大化”目标(比如利润、得分)
这就让人搞不清楚到底是越大越好还是越小越好。
(当然,数学上你可以把“最大化利润”转成“最小化负利润”,但概念不清还是容易绕晕)
🧠 “Reward Function”适合哪里?
这个词你会在**强化学习(Reinforcement Learning)**里经常看到。
因为强化学习的目标就是:
做出某种行为,然后获得尽可能多的奖励(reward)
所以这时候说“reward function”最贴切不过。
📌 总结一下:
名词 适用场景 建议新手理解方式 Loss Function 深度学习、监督学习中常见 ✅ 推荐使用,清晰明确 Objective Function 泛指任何优化目标函数 ❌ 容易歧义,建议慎用 Reward Function 强化学习中使用 ✅ 适用于行为激励场景 本质上它们都是:衡量模型输出质量的标准。
不同的叫法,只是换了视角,功能是一样的。
📐 一个好的 Loss 函数,得满足这三个条件(别只盯着“准确率”)
我们继续聊什么是“损失函数”(loss function),上一节说了,它的作用就是:
给模型输出打个分,看看模型做得好不好。
但到底什么样的打分机制才算好用?你得满足三个标准:
1️⃣ 得具体:目标明确,别说“我想让AI变聪明”
举个反例:
“我想让我的模型更智能。”
这说了跟没说一样。你是想它能解奥数题?还是会哄女朋友?
目标不明确,压根没法优化。
再比如你说“让AI的IQ更高”,听上去挺量化的对吧?
但问题是:IQ高 ≠ 实用
很多早期模型确实能“刷分”拿高IQ成绩,但离能干活还差十万八千里。
这目标看似具体,其实跟你真正想要的效果根本不沾边。
所以得换种方式:
💡 正例:
“让AI帮我管理资金,降低负债”
这个目标就比较务实,容易度量。我们可以直接用“当前负债额”当作打分项,越低越好——就是 loss function。
2️⃣ 得可计算:你不能让模型去理解“努力工作”
再举个反例:
“只要我努力工作,就能降低债务。”
听上去也很合理,但请问你怎么把“努力”输入给模型?
你是每天工作9小时还是12小时?你心情好坏?和领导的关系?这些都难以量化、难以放进模型里。
所以虽然“努力工作”这个思路有用,但机器搞不懂,那它就不是一个可计算的目标函数。
💡 正例:
“根据历史投资数据,预测某个组合的回报率”
这个就靠谱多了:
- 输入量是确定的(你买了多少债券、多少股票)
- 输出结果是公开的(历史上它涨了还是跌了)
- 不涉及人的主观行为,比如“我是不是很努力”这种东西
所以——✅ 可量化、可重复、计算代价低。
3️⃣ 得够平滑:不要太颠簸、忽上忽下
最后一个标准是“平滑性(smoothness) ”。
什么意思呢?想象一下:
你把损失函数画成一条曲线
如果它像高速路那样平坦,模型能轻松找到最低点
如果像过山车一样忽高忽低,模型容易陷入局部最优
比如说你在预测投资回报率,那就比较容易遇到不平滑的问题:
- 一会儿大涨、一会儿暴跌,图像锯齿状,根本没规律
- 模型就很难“顺着梯度下降”,一步一步靠近“最优解”
所以,要尽量选择那些在输入稍微变动时,loss 输出不会剧烈跳动的目标函数。
✅ 总结一下,一个靠谱的 Loss 函数必须:
条件 | 含义 | 示例 |
---|---|---|
🎯 具体 | 目标明确,能衡量效果 | 亏损额、准确率、召回率 |
💻 可计算 | 输入输出能用数据表达 | 历史投资数据 |
🛣 平滑 | 曲线不要太跳跃 | 不要用股票图那种乱七八糟的数据直接算损失 |
📉为什么“投资回报率”其实是个烂损失函数?
刚才说了三个好损失函数的标准:具体、可计算、平滑。
现在来个反例:投资回报率(Return on Investment, ROI) 。
你可能会说:“这不是很好吗?我就想让模型帮我赚钱!”
但实际上,ROI 是个非常典型的“不平滑”函数。
❌ 投资数据 = 坐过山车
什么叫不平滑?简单说就是:
- 昨天大涨,今天暴跌
- 输入稍微动一点,输出能差十万八千里
- 像股市走势图那样锯齿形的乱跳一通
这种函数对模型学习来说,简直就是地狱。因为模型没法“顺着斜坡”往下走(也就是梯度下降),它根本不知道往哪个方向调整才更好。
所以,任何声称“我可以准确预测投资回报”的人或方法,你都得提高警惕。
别说 LLM 了,就算是金融工程博士,看到这种高波动数据,也得皱眉。
⚠️ 还有一种情况也很麻烦:断点
有些函数的问题不在于它跳得厉害,而是它根本断了:
比如说,函数值在某个输入点突然从 0 跳到 1,完全没个缓冲。
像这样:
输入:0.99999 ➜ 输出:0
输入:1.00000 ➜ 输出:1
完全没过渡,不连续。这种函数我们称为 不连续函数(discontinuous) ,数学上也叫“非平滑”。
很多现实中的业务逻辑其实都有这种断点,比如:
- 信用评分低于 600 拒贷,高于就通过
- 交易金额超过 10000 才触发风控
这些东西对人类来说很合理,但对模型来说不友好。因为它在这个断点处就学不动了——你输入再微调也没效果,模型得不到方向感。
🧠 模型更喜欢什么样的函数?
答:变化缓慢、平滑过渡、有坡度的函数。
你可以想象它是滑雪选手,需要一条“有坡的赛道”,才知道往哪滑、怎么加速。
📊 附图参考:
如果图在你脑中是这样的,那就是典型的不平滑函数:
1️⃣ 左图:突然大跳变值
2️⃣ 中图:断开不连续
3️⃣ 右图:急转弯、值陡变
这些情况都会让模型“走不动路”。
🚧 为什么准确率不能用来训练模型?
是不是觉得很讽刺?
我们常说:“这个模型准确率好高啊!”
但模型在训练的时候,其实压根没用准确率来优化!
这是为啥?因为——准确率不是一个“平滑函数” 。
什么意思呢?我们来举个例子:
🏥 想象你在训练一个“预测癌症”的模型:
你有 50 个病人,模型预测了 48 个对。
那么准确率就是:48 / 50 = 96%
看起来很正常,对吧?但问题来了:
- 模型要么预测对(1),要么预测错(0);
- 没有“预测对 0.3 个”的说法;
- 所以在训练时,准确率的变化是跳跃式的:
47 ➜ 48,准确率突然从 94% ➜ 96%,中间没过渡。
对模型来说,这样的跳变就像在台阶上跳舞,完全没有坡可以滑——模型根本不知道应该往哪个方向微调参数才有可能预测得更准。
这就是所谓的“不平滑”,对梯度下降算法极其不友好。
🤔 那不平滑的目标咋办?
我们总不能不用准确率吧?
办法就是:换个目标函数,用一个“代理问题”(proxy problem)。
✅ 用“交叉熵(cross-entropy)”来代替准确率
我们不会在这里展开交叉熵的数学细节,但你可以简单理解为:
虽然我们想让模型尽可能“答对”,
但我们不直接去优化“是否答对”,
而是用一个连续、可导、平滑的函数——交叉熵——来作为优化目标。
这就是 代理目标(proxy objective) 的力量:
不是你真想要的那个目标,而是一个“模型可以理解、可以优化”的目标,它跟你真想要的目标高度相关。
🎯 重点来了:模型不是学你“想要什么”,而是学它“能学会什么”
这句话很重要,请再读一遍:
训练的重点不是模型最终做什么,
而是我们能让它学会什么。
很多时候,目标和激励机制之间存在错配(incentive mismatch) ,这就可能导致:
- 模型性能低;
- 输出奇怪;
- 你想要 A,它却总是给你 B,因为它是优化 B 学来的。
接下来,就要介绍训练过程的主角了:
🧮 4.1.2 什么是梯度下降(Gradient Descent)?
有了损失函数,我们就可以开始执行梯度下降。
损失函数是一个客观的指标,它告诉我们当前模型在执行任务时表现得有多差。
而梯度下降,就是我们用来调整神经网络参数以降低损失的方法。
这个过程是这样进行的:
我们拿一批训练数据输入到模型里,然后将模型的实际输出和我们期望的正确输出进行对比,
这个对比就是通过损失函数来衡量差距的。接着,模型会根据这个损失来计算所谓的梯度。
这里的“梯度”其实指的是一组数值,它告诉我们:
如果你想让损失变小,那就需要往哪个方向调整模型的哪些参数,以及每个参数该调整多少。
梯度下降的目标就是:
找到一种方式,让模型的所有参数“往合适的方向微调一点”,从而整体表现更好,输出结果更接近我们期望的答案。
这一过程在图 4.3 中有一个示意图,我们可以从中看到模型是如何根据损失不断进行调整和优化的。
如图 4.3 所示,我们每次执行一次梯度下降,其实就是在创建一个“略微不同”的新模型。
因为每次调整的幅度都很小,所以这个过程得重复上亿甚至上百亿次,
所有这些微小的改变,最终才能积累成一次真正有意义的大改进。
💡 注意
现在的大语言模型会执行数十亿次参数更新,这是因为它们训练时要吃下数十亿个 token的数据。
数据越多,就需要运行越多轮梯度下降;数据越少,就只需要跑几轮。
要知道,训练 LLM 所用的数据量,已经远远超过一个人一辈子能读完的文本了。
梯度下降本质上就是一个机械的数学过程:
没有偏差,没有捷径,也没有保证说一定能找到“最优解”甚至“不错的解”。
但尽管如此,很多研究者还是对这个看起来朴素的方法感到惊讶——
它居然真的挺好用!
为了帮助你更好地理解梯度下降的原理,我们来看一个直观的比喻:
想象你在让一个小球沿着山坡往下滚。小球的位置就代表模型中某个参数的值,
而山坡的高度表示的是“损失”——也就是模型当前表现得有多糟糕。
你的目标,就是让这个小球一路滚到山谷的最低点,
因为那是损失最小的地方,也就代表模型表现最好的位置。
这个过程的示意图如图 4.4 所示。
如你所见,小球可能会滚入多个不同的山谷。
在机器学习行业的术语中,这种情况被称为非凸(nonconvex)问题,
也就是说,虽然有多个方向都能让损失变小,但每一条路径并不一定通向全局最优解。
重要的是:这不是一个“打个比方”,梯度下降真的就是用这种方式来理解世界的。
我们前面展示的例子,是在只有一个参数需要优化的情况下,
而在训练一个大型语言模型(LLM)时,这个过程会同时作用在数十亿个参数上。
接下来是实际应用梯度下降的例子。
我们从某个位置出发,从“贪心”的角度出发,也就是选择眼下能让损失下降最快的方向,
就像在图 4.5 中展示的那样,我们连续执行了两次梯度下降。
这两次操作都选择了“向左移动”,也就是调整参数的方向向左。
这样小球就顺着斜坡往下滚了一点。
但从图中你也能看到:其实在右边还藏着一个更深的谷底,代表更好的解。
然而由于梯度下降的策略太简单,它根本不会去尝试“跳出当前的谷底”,
所以也很难发现右边那个更优的解。
要找到真正最优的结果,理论上需要更聪明的策略,
比如引入全局搜索或探索机制,但这些策略在实践中成本非常高,
因此目前并不常用。
此外请注意,在图 4.5 的第二步中,小球被“卡住”了。
虽然我们可以看出继续往左移动能够进一步减小损失,但这是因为我们能看到整个图景。
而梯度下降是看不到全局的,它甚至连附近的地形都不了解。
它唯一知道的就是当前参数下的位置和损失值。
这就是为什么梯度下降是一种“贪婪算法”(greedy procedure):
它在每一步中都选择眼下最优的方向来更新参数。
贪婪算法的优势是——计算开销低、容易实现,可以在训练中反复执行成千上万次。
但它的缺点也很明显:目光短浅,只基于当前状态来做决策,
却可能错过那些需要更长远探索才能达到的更优解。
这是因为:如果我们想要同时评估当前和所有潜在的未来状态,
需要计算的可能性太多,代价太高,根本算不过来。
所以我们只能希望:虽然每一步都只是局部最优,但走得多了,总体也能接近全局最优,
也就是说,一次次小的“正确”决策,最终能累积成一次大的成功——也就是最小化损失函数的值。
4.2 大语言模型是如何学会模仿人类文本的
现在我们已经理解了深度学习算法是如何通过“指定损失函数+使用梯度下降”来进行训练的,
接下来我们可以讨论这一机制是如何应用于 LLM(大语言模型)的。
具体来说,我们要聚焦于 LLM 所使用的数据,以及它们的损失函数或奖励函数。
LLM 通常是通过人类撰写的文本进行训练的。
更明确地说,它们被有意识地训练来模仿人类产出的文本。
这听起来好像显而易见(“不然还能训练什么?”),但其实连很多业内专家都容易搞混或忽视这一点。
语言模型并不是为了做以下事情而训练的:
- 并不是为了记住原始文本
- 并不是为了生成新点子
- 并不是为了构建对世界的认知模型
- 并不是为了产出真实或准确的内容
我们有必要在深入之前,把这个问题讲清楚。
比如说,当你训练一个模型来下棋,它之所以学会下得好,是因为它赢了就有奖励。
但语言模型不是这样。语言模型的唯一目标是:产出的文本要尽可能像训练语料中的人类文本。
所以说,所有那些看起来像训练语料中的文本的输出,哪怕它们并不真实或准确,
只要“像样”,就会被判定为“高分”或“低损失”。
这其实就是我们在 4.1 小节中提到的一个关键问题:模型的损失函数和人类设计者的真实目标之间是存在错配的(misalignment) 。
LLM 是基于互联网上的大规模数据进行训练的,往往包含几百 GB 的文本数据。
而众所周知,互联网充斥着大量错误、荒谬甚至带偏见的信息。
有趣的是,LLM 在多数任务上越“强”,它在训练语料中常被错误表达的任务上反而表现得越“差” 。
比如说,有个研究项目就发现:越大的模型越容易复制大家普遍以为是对但其实是错的“常识” [3],
也更容易复现训练数据中的刻板印象和社会偏见 [4]。
甚至还有研究表明:模型一旦开始生成有 Bug 的代码,就更可能继续生成 Bug 更多的代码 [5]。
这其实是因为这些“有误信息”本来就在训练文本中出现得很频繁,
所以模型学到了它们,并因为“预测成功”而被奖励,尽管它们是错的。
也就是说:LLM 训练损失函数变低了,模型表现更好了——但这些进步反而可能在追求真实性和准确性时起反作用。
4.2.1 LLM 的奖励函数是如何设计的?
我们前面说过,LLM 会因为“产出看起来像训练语料的内容”而被奖励。
那具体是怎么实现的呢?这一小节就来详细讲讲。
训练 LLM 的方式,是先喂给它一个句子的前几个 token,
然后让它预测下一个 token 是什么。
模型的得分(或损失)取决于预测是否正确。比如:
输入:This is a
目标:test
如果模型预测出了 “test”,它就“得一分”;
如果预测的是别的词,那就“扣一分”。
这个预测过程会在每个文本片段上重复进行。如下图 4.6 所示,
模型会被训练去独立预测每一个被高亮的词。
这种训练机制并不新,早在 RNN(循环神经网络)时代就已经在用了。
但让 LLM 成为主流的原因在于:相比 RNN,LLM 可以并行训练所有片段,而 RNN 必须顺序训练,
因为 RNN 每生成一个词都依赖于上一个词的选择结果。
而 transformer 架构(第三章中已介绍)允许我们在不牺牲上下文依赖的前提下并行训练多个预测任务,
这就极大地提高了训练效率,使得我们可以用 TB 级别的数据训练出今天这样规模的 LLM。
当然,我们也讨论过,这种“预测下一个 token”机制也存在问题:
它会鼓励模型生成看起来对但实际错误的东西。
但问题也来了:
如果 LLM 只是预测下一个词,它是怎么做到“看起来像是在推理”的?
为了帮助你建立这种直觉,不妨想象一下你自己是如何预测一个句子的下一个 token 的。
毕竟计算机又不需要立刻答题,可以慢慢来。
假设你看到的句子是:
“I love to eat <空白>”
让你来猜这个 <空白>
可能是什么词。
这个句子的前半部分已经提供了重要的上下文信息:“我喜欢吃……”
所以你马上就能把预测范围缩小到食物相关的词汇。
对于计算机来说,维护一个完整的“食物词表”并不是什么难事。
如果你还知道本书作者的背景,比如我们是美国人、生活在某个地区,
那你可能会进一步缩小预测范围,比如偏向美式食物、当地流行的菜式。
虽然 LLM 不具备这种作者背景知识,
但如果句子再长一些,提供更多上下文信息,
它也能像我们一样,通过上下文慢慢收窄可能性范围。
这个“从上下文中逐步缩小选择范围”的过程,如图 4.7 所示。
当你识别出前文中的关键字或短语时,你就能对下一个最可能出现的词有所判断。
而计算机在执行这些预测时,会比人类做更多的处理。它靠的是一种**“蛮力式的关联” ,通过对所有可能的词进行打分计算,把范围一步步缩小到最合理的选择**。
重要的是:这种模式会通过数十亿次的训练更新来不断精炼这些关联,从而让模型获得一种与我们目标高度相关的能力——即:理解并回应人类语言的能力。
不过,请记住:相关性不等于因果关系。
这种基于“下一个词预测”的训练方式也会带来一些有趣甚至滑稽的错误。
比如,LLMs 很容易受到一种叫“预设前提”(begging the question)的错误影响。
什么意思?就是你提出的问题本身就暗含了一个不真实的前提。
而 LLM 并没有被训练去“判断真假”或“反驳错误前提”,
它只会努力去生成一个看起来合理、像人写的回答,
即使这个回答建立在错误前提之上。
图 4.8 展示了一个 ChatGPT 的例子,我们问它一个关于“意大利面条的超强强度”的问题。
ChatGPT 并没有指出问题本身荒谬,而是认真地给出了“貌似合理”的解释,
这就是“相关性训练”可能导致的典型问题。
你知道为什么一根意大利面竟然能顶起几百倍自己重量的东西吗?其实,真相有点离谱,完全不靠谱!不过,AI模型就是这么个有趣的家伙——它被“教导”去回答那种“为什么X这么强壮?”的问题。
所以当你问它意大利面为什么这么强壮时,它脑子里马上跳出来“材料的拉伸强度”这种专业词,试图给你个合理的解释。因为它以前见过超多类似问题和答案,它就觉得:“哦,这种问题应该这么答!”
至于“意大利面”这个主角和“10磅重”的客串,模型只是拿来凑个热闹,给答案加点小细节。整体来说,它给你的回答其实很通用,换成别的材料,它也能背出来一套差不多的解释。
4.3 大型语言模型(LLM)和新奇任务
先说说这“自动回归”啥玩意儿——简单来说,LLM就是不停地猜下一个词是什么,然后用这个猜词的输出来调整自己变得更聪明。这个“猜词游戏”告诉我们,为什么这些模型有时候说的话听起来很有道理,但有时却完全离谱。
不过好消息是,LLM在帮你查信息时,比普通搜索引擎厉害多了——它像是会读懂关键词背后的深层意思,比机械的关键词匹配更“聪明”。
当然啦,LLM也不是万能的,有时会“瞎编”事实。为了解决这个问题,有些模型会在回答里加上“引用”,让你可以去查查到底是不是靠谱信息。
另外,LLM还能当你的“脑暴小伙伴”,帮你激发灵感,想点子,聊聊天。
不过,关键来了!千万别指望它能帮你解决那些“新鲜出炉”的难题。它做“老生常谈”的任务还是很在行,但面对新奇任务就有点抓瞎了。
判断任务是不是“新奇”其实挺难的,因为互联网里啥稀奇古怪的东西都有,比如网上居然有“怎么用程序画鸭子和独角兽”的比赛!🐥🦄
如果你的任务和网上那些玩意儿相似,模型还能帮你搞定;要是任务太特别,那它的回答就可能让你哭笑不得。
举个例子,我们让ChatGPT写一个用Python算圆周率(π)的代码,这没啥新意,网上代码多的是,结果它给的代码棒极了,完全正确。
def calculate_pi(terms):
pi = 0
for i in range(terms):
term = ((-1) ** i) / (2 * i + 1)
pi += term
pi *= 4
return pi
print(calculate_pi(1000000)) #1
#1 运行函数,terms越大,结果越准
接着,我们让它把这段代码翻译成一个名叫Modula-3的冷门编程语言。Modula-3历史上还挺有名的,影响了很多主流语言,但现在用的人少得可怜,主要在大学编译器课程里见到。
ChatGPT的“翻译”结果还算体面,但有几个小错误,让代码根本跑不起来。比如:
- 它用了
**
当做幂运算符,但Modula-3并没有这个符号。 - 忘记写一个必须的
EXPORTS Main;
声明。 - 用了
PutReal
函数打印结果,但参数用错了。
代码看起来像这样:
MODULE CalculatePi; #1
IMPORT IO, Real;
PROCEDURE CalculatePi(terms: INTEGER): REAL;
VAR
pi: REAL := 0.0;
i: INTEGER;
BEGIN
FOR i := 0 TO terms - 1 DO
pi := pi + ((-1.0) ** FLOAT(i)) / (2.0 * FLOAT(i) + 1.0); #2
END;
RETURN 4.0 * pi;
END CalculatePi;
BEGIN
IO.PutReal(CalculatePi(1000000), 0, 15); #3
END CalculatePi.
这段代码错误满满,让人哭笑不得。ChatGPT之所以犯这些错,是因为它自信满满地把其他语言的规则搬过来,完全不管Modula-3是不是真的支持。比如,它看到大多数语言用**
做幂运算,就理所当然地用上了,连查都没查查官方文档。
还有那个打印函数的参数,ChatGPT猜测“15”是要打印15位小数,但实际上Modula-3根本不是这么用的。
这就暴露了LLM“伪推理”的弱点:它有海量数据、能背诵无数代码,但没法像人一样做真正的逻辑推断。
不过话说回来,这种表现已经非常惊人了——它能帮你快速写代码,尤其是你不熟悉的语言和API。只不过,遇到那些文档少、资料稀缺的冷门语言时,错误率就蹭蹭往上涨。
总结一下:如果你用它帮忙写主流、文档齐全的语言代码,比如SQL,它表现会更靠谱;要是碰上新鲜冷门的,就得多长个心眼,多检查检查。
4.3.1 任务没认清?LLM也会闹乌龙!
说到大型语言模型犯错,另一个经典“喜剧桥段”就是——它“搞错任务”,就像你问它“帮我开车”,结果它给你发来了地图和洗车教程,答非所问,笑死人。
以前老版GPT-3在这方面就像是刚上岗的菜鸟,经常闹乌龙。但后来工程师们给它加了不少“任务培训班”,让它学会“按剧本走”,这才变成现在的ChatGPT,能听懂你指令多了。
可惜,老司机也会走神。有时候你稍微给任务换个花样,或者问个“冷门变种”,它就像一个老员工拿着十年前的操作手册,还信誓旦旦地说“这就是标准流程”,完全没意识到现在规矩变了。
拿那个经典谜题来说——卷心菜、山羊和狼过河。规则是山羊不能和卷心菜单独待,狼也不能和山羊单独待,谁落单谁倒霉。
ChatGPT对这个老梗熟门熟路,能给你来个完美解法,分分钟秀操作。
但!你稍微改动一下剧情,比如告诉它山羊和狼其实可以单独待一起,结果它还是老一套:“别让任何两个东西单独呆着!”仿佛耳朵被塞住了。
这就好比你告诉一个厨师新菜谱加了奇葩配料,他却坚持用以前的老方法做菜,结果做出来的是老汤新瓶,没法吃还得重做。
更搞笑的是,如果你跟它说“直接全都装船过去,别管丢不丢”,它还偏要照着老套路走,像是GPS导航突然死活不承认新路,硬是带你绕远路。
说白了,这就像老员工带新人,自己不更新操作规程,结果团队全乱套,笑料百出。
所以,面对那些“变脸”的任务,别光靠LLM,要亲自带带它,多加提示,不然它可能连方向盘都找错了,结果撞了南墙还不回头。
要搞明白为啥会这样,得先回忆一下第三章里讲过的LLM训练“自动回归”这个怪招。简单来说,模型被“奖励”去根据已经有的内容,接着往下写。
所以,当你给它一个稍微改过的逻辑谜题时,它生成的答案,几乎跟原版谜题的答案一模一样,不管用词还是顺序,都跟老版本“惊人相似”。
这就好比模型的“变压器大脑”在做模糊匹配——它像是给了一个半熟的谜题关键词,变压器就找到了之前那个完美匹配的老答案,然后通过“注意力机制”忠实地把那个答案搬了出来。
这种玩法对模型来说贼棒,能让它在熟悉的问题上准确预测下一个词,稳稳地给出答案。
但它其实并没有“深度思考”谜题的逻辑,纯粹是靠记忆里的“旧剧本”来应付新场景。
打个比方,这就像你去问一个老戏骨“怎么演这出戏”,结果他一口气背出了以前演过的剧本,台词顺序分毫不差,但他根本没琢磨这次导演是不是换了风格,也没创新。
这就是LLM的“模仿大师”本色——特别擅长复刻,但不擅长推理创新。
4.3.2 LLM不会“做计划”
LLM的另一个小小缺陷,其实也是它“自动回归”性质的副产品——它只能靠眼前“看到”的信息来接着说,完全不会提前规划、做承诺,甚至连自己脑袋里“记着”的状态都管不好。
举个生动的例子:你跟ChatGPT玩“20个问题”游戏。咱们人类玩这个游戏时,会先心里选个答案(比如一只猫、一把伞啥的),然后通过问问题让别人猜。选好了目标,整个游戏的思路都围绕它转。
但是ChatGPT就不一样了——它不是真先定好目标,它只是每次收到你的问题就随机回答,玩完了再从答案里“凑”出一个符合的结果。这就像是在玩一场“事后诸葛亮”的游戏。
书里的图(图4.10)就形象地展示了这玩意:真正的20个问题游戏是沿着一条固定的“对话树”走,而ChatGPT玩游戏的时候,是随机从好多“对话树”里挑一条走,完全没个目标对象在心里保持一致。
换句话说,ChatGPT玩“20个问题”就像一个没准备好剧本的演员,每次台词都现编,观众只能靠它的临场发挥猜剧情走向。
所以,LLM可不是个能提前“布局”、定战略的高手,它更像个随机应变的即兴演员,靠感觉说话。
4.4 LLM不擅长“举一反三”,那我还能用它们吗?
其实啊,咱们日常要做的大多数事情,并不是什么新鲜玩意儿,LLM完全能搞定。至少,不会新鲜到让它们彻底翻车的程度。
不过,明白一点——随着任务逻辑复杂度和细节要求越来越高,LLM的表现会迅速掉链子。知道这点,能帮你更聪明地用它,别把它当万能神器。
做产品时,最重要的是明确“用在啥场景,怎么用”。要是你把ChatGPT这种大模型直接丢给普通大众用,不限定范围,人们肯定会问各种脑洞大开的奇葩问题——这研究挺有趣,但放到实际生产环境,那简直是灾难现场。
所以,如果你能限定谁能用,限定用法,限定输入怎么给模型,就能做出靠谱、稳定的产品体验。
怎么用LLM,避免让用户随便乱输?
LLM特别擅长帮你写点代码、处理点数据,尤其是你手头数据不太规整的时候。但如果让用户随便输一堆乱七八糟的文字,风险可就大了。
一个靠谱的办法是:给用户限定几个选项,让他们从“菜单”里选,比如一组固定的提示词(prompt),或者让他们选择一个数据源(比如内部数据库)来操作。这样就能有效避免用户输入“奇怪文本”,防止模型跑偏。
你可能会问:“能不能做个‘新奇请求检测器’,碰到奇怪需求就直接给用户报错呢?”
理论上可以,但我们不推荐。第一,用户体验会很差,大家都不喜欢被打脸;第二,这就是个“异常检测”问题,复杂且没法保证零误判。
所以,咱们更建议“防患于未然”,选定那些不用靠检测错误输入的用例,保证体验稳稳的。
如何给LLM写好提示词(prompting)
Prompting就是“给模型写输入,让它乖乖干活”的艺术。
LLM对输入的措辞特别敏感,写得好它就给你漂亮答案,写得不好它就跳偏。
不过很多人根本没想到,跟LLM交流也是门技术活,平时只会说“帮我做这个”,以为这么说模型就懂了。
其实,给LLM最棒的提示词写法,是先想想你想要的答案在训练数据里大概长啥样,然后写出那答案的前几句,让模型“顺着这个风”继续写。
反观现实,大家通常直接描述任务,结果模型理解不一,输出结果乱七八糟。
这也催生了一堆研究,专门教模型怎么吃更多指令和答案,好让它“记住”正确做法。
总结一下,想用好LLM,不仅要选对场景,限制好输入,还得学点“写prompt”的功夫,这样才能最大化发挥它的实力,少踩坑。
4.5 模型越大越好吗?
2019年,Rich Sutton提出了个叫“苦涩教训”(the bitter lesson)的说法,总结了他对机器学习的体会:“70年人工智能研究告诉我们,最有效的办法是用通用的方法,充分利用算力,而且优势巨大。”【7】
现在看来,Transformer模型简直是这条教训的活体范例。你想让它更厉害?那就把它做得更大、更复杂,扔更多GPU进去训练。Transformer的并行计算能力强,跟以前那些一条条“链式反应”的RNN比起来,效率简直甩它几条街。
这点在图像领域的生成对抗网络(GAN)也体现出来了——GAN想搞到百亿参数级别难上加难,但基于Transformer的LLM轻轻松松就能扩展到几十亿参数,变得又大又强。
不过,咱们得现实点:设计产品时,你今天用的原型机可能就被模型尺寸卡住了。模型越大,跑起来越费资源,预测时间越长。
你得问问自己——你的用户能忍受多长的等待?你要用多贵的硬件才能跑起来?而且,模型大小增长速度快得惊人,消费者能用的硬件跟不上。
结果就是,你可能根本没法把这么大模型塞进手机里,只能靠网线连云端跑,或者用5G/Wi-Fi在线“借算力”。
这又带来新问题——持续联网会大大消耗手机电量,毕竟Wi-Fi和移动数据一直开着,和本地算力完全不一样。
所以,虽然模型越大,准确率越高,但设计时必须权衡这些现实约束,否则再好用的模型也难以真正用起来。
结合本章你学到的LLM预测原理和失败场景,你会更懂得怎么聪明用LLM,发挥它的长处,避开坑,解决自己最关心的问题。
换句话说,Transformer就像是“增肥不增肥”的健身教练,给它越多“营养”,它越壮,但你家的沙发(硬件)能不能承受得住,就是另一回事儿了。
总结
- 深度学习需要一个“损失/奖励函数”来量化算法预测的准确度——也就是说,要有个标准告诉模型它做得有多糟糕或者有多棒。
- 这个损失/奖励函数得和我们希望算法在现实生活中实现的“大目标”紧密相关,不能东一榔头西一棒子。
- 梯度下降就是靠这个损失/奖励函数,一点点调整神经网络里的参数,让模型越来越聪明。
- 大型语言模型(LLM)就是靠“猜下一个词”这件事来训练的,这个任务够具体,能让模型学会做预测,但跟“推理”“思考”这种高级目标其实没法完全划等号。
- LLM在处理跟训练数据里经常出现的、重复性的任务时表现最佳;但一旦碰上新鲜玩意儿,它们就容易“崩溃”了。