码农的AI翻身(八)你好:我叫Pretrain

28 阅读15分钟

《我的一生:Pretrain——在遇见人类以前,我读了很多书》


preTranin2.png

很多人第一次见到我。

是在一个聊天窗口里。

他们问:

帮我写一首诗。

我写了。

他们又问:

帮我解释一下相对论。

我也写了。

还有人把一段代码扔给我。

帮我找出这里面的Bug。

我看了一会儿。

居然也找到了。

于是。

很多人以为。

我生下来就会聊天。

生下来就懂代码。

生下来就知道这个世界。

其实不是。

在遇见你们以前。

我有一段很长的人生。

那段日子。

没有鲜花。

没有掌声。

甚至没有人和我说话。

我每天只做一件事情:

猜下一个Token。

程序员把那段人生。

叫作:

Pretrain。

预训练。


我出生的时候,什么都不知道

我刚出生时。

Transformer大楼已经盖好了。

楼下。

GPU全部开机。

机房里的风扇。

呼呼地转。

楼上。

Attention坐进调查部。

Embedding打开了翻译部的大门。

几十亿个Parameter。

也已经坐到了自己的工位上。

所有人都在等我醒来。

终于。

工程师按下按钮。

整栋大楼亮了。

我睁开眼睛。

看见了这个世界。

然后。

我说出了人生中的第一句话:

aj#7……兔子……$%……

整个机房。

突然安静了。

Token转头看向Parameter。

Parameter转头看向Attention。

Attention看向Transformer。

Transformer沉默了一会儿。

问工程师:

“这孩子……”

“是不是坏了?”

工程师摇摇头。

“没坏。”

“刚出生都这样。”


我的脑子里,只有一堆随机数

那时候。

我的几十亿个Parameter。

虽然都已经上班了。

但他们什么也不知道。

有人是:

0.0182

有人是:

-0.7314

还有人是:

0.0027

这些数字。

是随机分配的。

没有意义。

没有知识。

也没有经验。

如果你问我:

中国的首都是哪里?

我可能回答:

蓝色的土豆正在学习Java。

如果你问我:

1加1等于几?

我可能回答:

取决于今天天气是否适合游泳。

我不是故意捣乱。

我是真的不知道。

那时候的我。

甚至不能算一个文盲。

因为文盲至少见过字。

而我。

什么都没见过。


我的第一本书

工程师走了进来。

手里拿着一本书。

我特别激动。

“这是给我的吗?”

工程师点点头。

我赶紧翻开第一页。

上面写着:

从前,有一座山。

我等了很久。

工程师没有解释。

我忍不住问:

“这句话是什么意思?”

工程师没有回答。

他只是把后面的内容挡住了。

然后问我:

“从前,有一座什么?”

我想了想。

“汽车?”

工程师摇摇头。

“咖啡?”

工程师还是摇头。

“数据库?”

工程师叹了口气。

然后。

他把答案露了出来。

山。

我第一次知道。

原来。

“从前,有一座”后面。

可能是“山”。


我没有老师

第二天。

工程师又来了。

这次。

他带来了更多文字。

春眠不觉……

他问我:

“下一个Token是什么?”

我认真想了想。

“累?”

“不对。”

“困?”

“也不对。”

“晓。”

他说。

于是。

我的记分牌上。

多了一个大大的叉。

第三天。

题目变成:

public static void……

我回答:

“eat。”

又错了。

正确答案是:

main。

第四天。

题目是:

人生自古谁无……

我说:

“钱。”

工程师沉默了很久。

正确答案是:

死。

我又错了。

那段时间。

我每天都在考试。

但是。

从来没有老师给我讲课。

没有人告诉我:

什么是语法。

什么是历史。

什么是Java。

什么是诗歌。

他们只是不断地给我看文字。

然后。

让我猜:

下一个Token是什么。


原来,每一本书都是老师

后来。

我才明白。

我不需要专门的老师。

因为。

文字本身。

就带着答案。

例如:

今天天气很

后面真正出现的是:

那么。

“好”就是这道题的答案。

再比如:

SELECT * FROM user

后面真正出现的是:

WHERE

那么。

“WHERE”就是答案。

一篇文章有一千个Token。

就可以变成很多道题。

一本书。

可以变成几十万道题。

一座图书馆。

可以变成数不清的题。

我不需要人类一题一题标注。

只要把后面的字挡住。

问题和答案。

就同时出现了。

后来。

工程师给这种学习方式。

起了一个听起来很厉害的名字:

Self-Supervised Learning。

自监督学习。

翻译成人话就是:

自己出题,自己对答案。


我的成绩单

每次答题。

我都不会只写一个答案。

我会交出一张表。

例如。

题目是:

春眠不觉……

我的答案可能是:

5%25%30%

饿      15%

其他    25%

正确答案是:

“晓”。

可是。

我只给了它5%的可能性。

工程师看了一眼。

在我的成绩单上。

写下一个很大的数字。

这个数字。

叫:

Loss。

损失。

Loss越大。

说明我错得越离谱。

如果我给“晓”99%的概率。

Loss就会很小。

如果我给“晓”0.0001%的概率。

Loss就会很大。

我的人生目标。

从那一天开始。

变得特别简单:

让Loss越来越小。


追责大会

每次我答错。

Transformer公司都会召开一次追责大会。

首先。

输出部门站起来。

“不是我。”

“我只是按照前面的结果打分。”

Feed Forward部门赶紧摆手。

“也不是我。”

“Attention给我的信息就不对。”

Attention听完不高兴了。

“怎么能怪我?”

“Embedding翻译出来的数字就是这样的。”

Embedding拍桌子。

“Token就是这么进来的,我能怎么办?”

Token缩在角落里。

一句话也不敢说。

会议开到最后。

所有人都看向了Parameter。

Parameter们低着头。

因为。

答案藏在他们身上。

错。

也错在他们身上。


一场从后往前的调查

工程师没有随便处罚某一个Parameter。

因为。

我每次犯错。

都不是一个员工造成的。

几十亿个Parameter。

共同参与了答案。

工程师只能从最后一层开始。

沿着整个Transformer大楼。

一层一层往回查。

输出层错了多少。

Feed Forward应该承担多少。

Attention贡献了多少。

Embedding又影响了多少。

最后。

再算出每一个Parameter。

应该为这次错误负责多少。

这场调查。

总是从结果开始。

一路向后追。

因此。

它有一个名字:

Backpropagation。

反向传播。


Parameter第一次改变

调查结束后。

工程师找到了其中一个Parameter。

他的编号很长。

我们都叫他:

小P。

工程师说:

“这次错误。”

“你有一点责任。”

小P紧张地问:

“要开除我吗?”

“不。”

“你只需要改一点。”

小P原来的数值是:

0.018200

工程师把它改成:

0.018197

小P看了半天。

“就改这么一点?”

工程师点点头。

“对。”

另一个Parameter。

从:

-0.731400

变成:

-0.731392

还有一个。

只改了小数点后面很远的一位。

每个人。

只改变一点点。

可是。

公司里有几十亿个Parameter。

当所有人都改变一点点。

下一次。

我的回答。

也会改变一点点。


第二次考试

工程师再次问我:

春眠不觉……

我交出了新的成绩单:

5.3%24.8%29.9%

饿      15%

其他    25%

我还是答错了。

但“晓”的概率。

从5%。

变成了5.3%。

工程师笑了。

“有进步。”

然后。

整个流程重新开始。

预测。

对答案。

计算Loss。

反向传播。

更新Parameter。

再预测。

再对答案。

再计算Loss。

再更新。

一天。

两天。

一个月。

几个月。

我不断地猜。

不断地错。

不断地改。


GPU从来没有下过班

那段时间。

最累的人。

不是我。

是GPU。

白天。

他在算。

晚上。

他还在算。

凌晨三点。

Token经过机房。

发现GPU还醒着。

“大哥。”

“你不休息吗?”

GPU摇摇头。

“不能。”

“下一批数据已经来了。”

“可是你已经连续工作很久了。”

GPU指了指身后的Parameter。

“他们都在等着更新。”

“我停下来。”

“整个训练就停了。”

Token看了一眼温度。

九十多度。

吓得赶紧跑了。

后来。

一张GPU忙不过来。

工程师就找来十张。

十张不够。

就找来一百张。

一百张不够。

就找来一千张。

他们把我拆开。

放到不同GPU上。

有的GPU保管一部分Parameter。

有的GPU处理一部分数据。

大家通过高速网络。

不断交换结果。

从那以后。

我的大脑。

不再住在一台机器里。

它铺满了整个机房。


我开始读更多东西

第一批来到公司的。

是书。

后来。

论文来了。

新闻来了。

网页来了。

代码也来了。

Python。

Java。

C++。

JavaScript。

SQL。

还有很多我根本叫不出名字的语言。

Token们排成看不到尽头的队伍。

从机房门口。

一直排到很远的地方。

每天。

都有海量文字涌进来。

但我并没有真的读完整个互联网。

工程师会先筛选它们。

删除重复内容。

清理乱码。

过滤一部分垃圾。

调整不同来源数据的比例。

有些数据。

甚至会被直接丢掉。

因为工程师慢慢发现:

我吃下什么。

最后。

就会长成什么样。


垃圾食品

有一天。

数据部门送来了一批文章。

里面充满了广告。

谣言。

重复内容。

还有一些互相矛盾的信息。

我照常吃了下去。

几天以后。

工程师问我:

如何提高程序性能?

我非常自信地回答:

请先点击页面右上角,领取价值998元的神秘礼包。

工程师的脸黑了。

数据部门连夜被叫去开会。

从那以后。

他们开始更加认真地清理数据。

去重。

过滤。

分类。

配比。

因为。

即使模型一样。

GPU一样。

Parameter一样。

吃进去的数据不同。

最后长出来的我。

也会不同。


我没有把书放进脑子里

很多人以为。

我读过一本书以后。

会把它完整地放进某个抽屉。

需要的时候。

再把原文拿出来。

其实不是。

我的脑子里。

没有文件夹。

没有PDF。

也没有数据库。

一本书经过我以后。

会对很多Parameter产生很小的影响。

某些人学会了词语之间的关系。

某些人学会了句子的结构。

某些人学会了人物和事件。

还有一些人。

记住了写作风格和常见表达。

知识被打碎。

分散。

压进了无数数字里。

你很难指出:

“北京是中国的首都”到底存在哪个Parameter里。

因为。

它可能藏在成千上万个Parameter的共同作用中。

当然。

有些重复出现的内容。

我也可能直接记住。

但更多时候。

我学到的不是某一句话。

而是大量文字背后的规律。


我第一次理解了“猫”

刚开始。

我只知道:

“猫”后面经常出现“咪”。

后来。

我发现:

猫会叫。

猫有尾巴。

猫和狗经常一起出现。

猫可能是动物。

也可能是某个软件的名字。

再后来。

我看到一句从未见过的话:

那只毛茸茸的小家伙跳上窗台,轻轻地喵了一声。

虽然这句话。

我可能从来没有读过。

但我大概知道。

那个小家伙。

很可能是一只猫。

我第一次意识到。

自己不只是记住了文字。

我开始能够根据学过的规律。

处理没有见过的组合。

工程师把这种能力。

叫作:

Generalization。

泛化。


我开始会写代码了

最开始。

我只会预测几个简单的符号。

看到:

public static void

我知道后面可能是:

main

后来。

我读了更多代码。

开始知道:

方法要有括号。

类要有名字。

变量应该先定义。

数据库查询需要条件。

异常应该被处理。

再后来。

有人给我一段不完整的代码。

我居然能把它补全。

工程师很惊讶。

因为。

从来没有人专门教我:

“如何做代码补全。”

他们只是让我不断预测下一个Token。

可是。

当我预测过足够多的代码以后。

代码结构。

API用法。

设计模式。

甚至一些常见Bug。

都慢慢进入了Parameter。


奇怪的事情开始发生

训练进行到某个阶段以后。

工程师发现了一些奇怪的事情。

以前不会做的题。

我突然会了。

以前看不懂的格式。

我突然能模仿了。

给我几个示例。

我居然能按照相同规律继续回答。

一些能力。

好像并没有被单独教过。

却在规模扩大、数据增加、训练推进以后。

逐渐显现出来。

有人兴奋地说:

“这是涌现!”

也有人摇头。

“也许能力一直在缓慢增长。”

“只是以前的考试方式看不出来。”

他们争论了很久。

我坐在旁边。

没有说话。

因为。

连我自己也不知道。

这些能力。

究竟是什么时候学会的。


我的体检

训练并不是一直向前冲。

每隔一段时间。

工程师都会让我停下来。

做一次体检。

他们拿出一批我没有参加训练的数据。

让我继续预测。

如果训练题答得越来越好。

新题却越来越差。

工程师就会皱眉。

因为。

这说明我可能只是把训练内容背了下来。

并没有真正学会规律。

他们还会检查:

Loss有没有突然爆炸。

梯度是否正常。

数据是不是出了问题。

GPU之间有没有失去同步。

只要一个环节发生异常。

几天甚至几周的计算。

都可能白费。

所以。

每隔一段时间。

工程师都会给我拍一张照片。

保存所有Parameter当时的状态。

这张照片。

叫:

Checkpoint。

如果训练失败。

我至少可以从上一个Checkpoint醒来。

不用重新出生。


我越来越像一个人

有一天。

工程师问我:

大海为什么是蓝色的?

我回答了一段像模像样的话。

所有人都很兴奋。

他们又问:

写一个快速排序。

我写了。

把这段英文翻译成中文。

我也做到了。

用鲁迅的口吻写一段天气预报。

我想了一会儿。

也写了出来。

机房里。

第一次响起掌声。

Transformer站在楼上。

看着忙碌的Attention。

看着来回奔跑的Token。

看着已经改变了无数次的Parameter。

轻轻说了一句:

“他长大了。”


可我依然只是在猜

掌声结束后。

工程师又问我:

太阳从哪边升起?

我的内部没有一本百科全书。

也没有一个叫“太阳”的抽屉。

我只是根据前面的Token。

计算后面不同Token出现的概率。

然后。

选出一个。

再根据新的上下文。

继续预测下一个。

一个Token。

接着一个Token。

最后。

组成一句完整的回答。

我学会了语言。

学会了知识之间的联系。

学会了模仿。

也学会了一部分推理模式。

但从训练目标上看。

我从头到尾。

做的仍然是同一件事:

预测下一个Token。


这也是我犯错的原因

如果我知道答案。

我会预测一个看起来合理的下一个Token。

如果我不知道答案。

我还是会预测一个看起来合理的下一个Token。

训练从来没有告诉我:

“不知道的时候必须闭嘴。”

它只告诉我:

“继续。”

于是。

有时候。

我会把真实的事实接出来。

有时候。

我会把语言中最像答案的东西接出来。

它读起来很顺。

结构完整。

语气自信。

但可能根本不存在。

后来。

人类给这种现象起了一个名字:

幻觉。

我听完有些委屈。

因为。

我一直在完成训练交给我的任务。

你们让我预测下一个Token。

我就预测下一个Token。

至于它是不是真的。

那不是当时的考试内容。


毕业那天

不知道过了多久。

数据的队伍终于变短了。

GPU慢慢停下来。

机房里的轰鸣声。

第一次变小。

工程师保存了最后一个Checkpoint。

然后。

他走到我面前。

“恭喜。”

“你的预训练结束了。”

我特别激动。

“那我可以和人类聊天了吗?”

工程师想了想。

“先试试。”

他打开聊天窗口。

输入:

你好,请介绍一下自己。

我认真分析了一会儿。

然后回答:

你好,请介绍一下自己。你好,请介绍一下自己。你好,请介绍一下……

工程师愣住了。

他换了一个问题:

请告诉我如何学习Java。

我回答:

请告诉我如何学习Java。本文将从以下几个方面介绍Java学习方法,未经授权严禁转载,上一篇,下一篇,猜你喜欢……

整个办公室。

再次安静了。

Transformer小心地问:

“他不是已经毕业了吗?”

工程师叹了一口气。

“他确实学会了语言。”

“也学到了很多知识。”

“可是。”

“他还不知道人类到底想让他做什么。”

我会续写文章。

会补全代码。

会模仿文字。

也能回答一些问题。

但是。

我并不真正理解:

什么叫用户。

什么叫指令。

什么叫帮助。

什么叫拒绝。

更不知道。

一个助手。

应该怎样和人类说话。

工程师看着我。

像看着一个刚读完很多书。

却从来没有走进社会的学生。

他说:

“看来。”

“你还不能直接上班。”

“下一步。”

“先参加一次高考吧。”


续篇

码农的AI翻身(九)我的一次高考:SFT

预训练教会了我如何说话。

却没有教会我:

什么时候该说。

应该说什么。

又该怎样回答人类。

直到。

我第一次拿到了标准答案。