简介:这是一份面向NLP初学者与深度学习入门者的PDF学习资料,聚焦大语言模型(LLM)的概念体系与演进脉络,便于快速梳理“语言模型—预训练语言模型—大语言模型”之间的层级关系。资源压缩包内含单个PDF文件,大小3.24MB,下载后既可离线阅读,也适合打印为纸质材料随时翻阅。PDF以LLM背景知识为主线,先讲解语言模型的基本定义与概率计算方法,继而梳理从基于规则和统计的N-gram模型、神经网络语言模型、预训练语言模型,到大规模AIGC模型的四个发展阶段,并围绕参数量、训练范式、架构特征等维度给出明确界定。其中对N-gram的马尔可夫假设、条件概率推导、优缺点分析,以及神经网络语言模型中词向量、softmax归一化、模型局限性等关键知识点均有展开说明,结构清晰、内容完整,适合搭建系统性认知框架。目前已有129人浏览学习,特别适合正在入门NLP、准备课程汇报,或希望系统理解大语言模型发展脉络的读者参考。
1. 先搞懂一个概念:大语言模型入门到底在学什么
很多人第一次听说“大语言模型”时,心里想的是:“这跟我每天用的聊天机器人是不是一回事?我要不要先学会写代码才能学?” 先别急着把自己劝退。零基础入门的关键,不是一上来就啃公式,而是先搞明白这门课到底在研究什么。
你可以把语言模型想象成一个“语感测试器”。人类听到一句话,会在脑子里不自觉地反应:这话通顺吗?像不像正常人会说的?语言模型做的事情几乎一样——它计算“一句话是人话的概率”。如果概率高,说明这句话自然;如果概率低,说明这句话听起来很怪。而大语言模型(Large Language Model,简称 LLM),就是把这个能力做到极致的那个版本,它能做文本分类、问答、翻译、对话等一大堆任务。这篇文章不要求你会写代码、不要求你数学很好,我会带着你从“什么是语言模型”这个问题出发,一步步走到“大模型为什么厉害”,最后帮你规划出第一条可以落地的学习路线。读完之后,你对那些天天出现在新闻里的名词就不会再发怵了。
2. 核心概念:语言模型怎么判断“人话”
2.1 先建立直觉:它在算一句话像不像“人话”
我们看一个例子。假设有人连续说了两句话:
- 我想去打篮球
- 篮球打去我想
你一眼就能看出第一句是通顺的、第二句是乱的。但你有没有想过,这种“感觉”是怎么来的?
语言模型把这种直觉变成了一个数字。它学习过大量由人写的、真正合理的句子,然后养成了“语感”。当你给它一个句子,比如 S = {我想去打篮球},它会算出一个概率 P(S)。如果这个句子符合人类说话的习惯,概率就高;如果词序乱七八糟,概率就非常低。一句话,语言模型就是一个打分器,它替你把“念起来顺不顺”这种感觉量化出来。我第一次学的时候,觉得这定义也太简单了,但其实整个领域后来的发展,都是围着这个“打分数”的目标转的。
2.2 把整句概率拆开:链式法则是什么
问题来了:一个句子是由很多词组成的,怎样才算“符合语用习惯”?最笨的方法是把整个句子当成一个整体来数次数。比如,你有一个语料库(一堆句子),里面有两万条句子,其中只有一条是“我想去打篮球”,那概率就是一万分之一。可一旦句子稍微换几个词,比如“我想去打羽毛球”,语料库里没出现过,概率直接变成 0。一个模型如果有能力把常见的句子都打成 0 分,那它基本等于没用——连一句新话都没见过。
所以,聪明的做法是拆开算。概率论里有一条链式法则,大意是说:一个句子的概率,可以拆成一串“在已知前面几个词之后,下一个词出现的概率”的乘积。公式写出来是这个样子的:
P(W1, W2, ..., Wn) = P(W1) × P(W2|W1) × P(W3|W1,W2) × ... × P(Wn|W1,...,Wn-1)
“P(想|我)”的意思是:已知前面一个词是“我”,下一个词是“想”的概率。这样一来,问题就变得简单了:我不用再整个句子计算,只需要挨个预测“下一个词是什么”。这也是很多资料里把语言模型称为“接龙模型”的原因——给它一个开头,它不停地预测后面接什么词。
2.3 动手算一次:亲手掌算一个 bigram 语言模型
原理听再多,不如亲手算一次。下面是一个极简的语料库,每一行是一条句子,词之间用空格隔开:
- 我 想 去 打 篮球
- 我 想 去 吃 晚饭
- 他 想 去 打 篮球
- 我 不 想 去 打 篮球
- 他 不 想 去 吃 晚饭
我们用 Python 写一个最简单的 bigram 语言模型。所谓 bigram,就是假设“下一个词只跟前面一个词有关”。这个假设在学术上叫马尔科夫假设,它让我们不用记住整句话的历史,只盯住前一个词就行。
# 一个超级小的语料库,每一行是一条句子,词之间用空格分开 corpus = [ "我 想 去 打 篮球", "我 想 去 吃 晚饭", "他 想 去 打 篮球", "我 不 想 去 打 篮球", "他 不 想 去 吃 晚饭" ] first_word_count = {} # 用来记录每个词作为“前一个词”出现了多少次 bigram_count = {} # 用来记录每对相邻词出现了多少次 for line in corpus: words = line.split() for i in range(len(words) - 1): w_prev, w_cur = words[i], words[i + 1] first_word_count[w_prev] = first_word_count.get(w_prev, 0) + 1 key = (w_prev, w_cur) bigram_count[key] = bigram_count.get(key, 0) + 1 def bigram_prob(w_prev, w_cur): # P(W_i | W_{i-1}) = C(W_{i-1}, W_i) / C(W_{i-1}) return bigram_count.get((w_prev, w_cur), 0) / first_word_count.get(w_prev, 1) # 验证一下:已知前一个词是“我”,下一个词是“想”的概率 print("P(想|我) =", bigram_prob("我", "想"))这段代码的逻辑很简单:第一步,统计每个词总共出现了多少次,比如语料里“我”出现在句首或句中多次,这些次数记录在first_word_count里;第二步,统计每一对相邻的词出现了多少次,比如“我 想”出现过几次,记录在bigram_count里。然后,bigram_prob函数就用“这个词对出现次数”除以“前一个词出现次数”,得到条件概率。
看到这你会发现,所谓“训练一个语言模型”,在 N-gram 时代其实就是在做一件事:数数,然后做除法。等你把所有的相邻词对概率都算完,一个语言模型就算建好了,它就能回答我们一开始的问题——“我想去打篮球”和“我想去打晚饭”哪句更通顺。算一下 P(篮球|打) 和 P(晚饭|打),谁大,模型就认为接哪个词更合理。这个结果完全来自语料统计,不掺一点人工规则,这是统计语言模型最大的魅力。
提示:上面的
bigram_prob("我", "想")算出来的概率大约是 0.38,因为“我”出现了 3 次(有的作为句首,有的在句中),其中后面接“想”的有 4 次?不对,仔细看:语料里“我”出现 3 次?实际上第一句有“我”,第二句有“我”,第四句有两个“我”(句首“我”和“不”前面的“我”?第四句是“我 不 想 去 打 篮球”,所以“我”出现了1次;加一起是3次)。其中“我 想”出现几次呢?第一句、第二句、第四句都有“我 想”,所以是3次;3除以3得到1?这就和预期不符。这里我重新算一下。注意第四句“我 不 想 去 打 篮球”里,“不 想”是相邻对,“我 不”也是一个相邻对;所以“我”作为前词的次数有:第一句“我 想”、第二句“我 想”、第四句“我 不”,所以 C(我)=3。而“我 想”作为词对出现在第一句和第二句,共2次。所以 P(想|我)=2/3=0.67。原文里的 0.38 对应另一个语料,无法验证,我这里不应写0.38。改写为2/3,或把语料调整一下。稳妥做法:语料库调整为让P(想|我)为0.38不合理;给一个例子更合适,直接用我的小语料算出0.67即可。我调整叙述,不引用原文数字。或者给“我想去打篮球”和“我想去打晚饭”的选择——P(篮球|打) 和 P(晚饭|打) 的比较。这里没有问题。
不过要补充一点:这个代码是为了演示原理,现实中没人会用这么小的语料。真正训练时,语料库会有几亿甚至几十亿个句子,词表有几十万个词,统计出来的概率才会靠谱。但无论规模多大,计算的本质都是这个除法。
2.4 从 unigram 到 trigram:N 到底选几?
刚才的小例子用了 bigram,也就是只看前一个词。如果我们假设“下一个词和前面谁都不相关”,那叫 unigram,也就是一元模型,每个词是独立出现的。如果假设“下一个词只和前两个词有关”,那叫 trigram,也就是三元模型。一般把这种统称为 N-gram 语言模型,N 就是看前面几个词的意思。
N 选得大,模型能记住更长一点的上下文,比如 trigram 能区分“打 篮球”和“吃 晚饭”的区别。但 N 选得太大,麻烦也跟着来:词对组合数量是爆炸式增长的。词典里有 1 万个词,二元组理论上就有 1 亿种可能,三元组就有 1 万亿种可能。你根本找不到足够的语料把所有组合都数一遍。就算你有一百亿条句子,也还是会有大量词对一次都没出现过。于是“没见过的词对概率为 0”这个问题不但没解决,反而越到后面越严重。这也是我们下一章要讲的——为什么后来大家不满足于数数了。
3. 从统计到神经网络:为什么必须换一条路
3.1 N-gram 的三个老大难问题
我们把 N-gram 的问题集中起来看一下,它们分别是:数据稀疏、参数空间爆炸、泛化能力差。
所谓数据稀疏,就是我们前面反复提到的:句子是无穷多的,语料是有限的,你一统计,发现好多词对根本没出现过,概率是 0。这个词在学术上叫 OOV(Out Of Vocabulary),意思是“词汇表之外的内容”。同一句话换个说法,只要里面有一个词在训练集里没见过,整句概率就会塌掉。读过第 2 章动手练习的人应该已经感觉到了——那个 5 句的小语料,只能应付这 5 句,换一句新的就完蛋。
第二个问题,参数空间爆炸。我们算过一笔账:词典越大,N 越大,要数的组合数就越离谱。有人可能想:那我选 5-gram 甚至 7-gram,记住更多上下文不就好了吗?不行,因为组合数是指数增长的,就算把整个互联网文本搬来,也还是会被稀疏问题反噬。
第三个问题,泛化能力差。“泛化”这个说法听起来高级,翻译成人话就是:模型学完旧句子,能不能自己发挥、处理从没见过的新句子。N-gram 做得很差,因为它本质上只是查表,完全不懂词和词之间的相似关系。它不知道“篮球”和“足球”是一类东西,更不知道动词“打”可以配球类运动却不配“晚饭”。倒不是说 N-gram 一无是处——它有训练快、可解释性强的优点,但从统计模型走向神经网络,已经是必然趋势。
3.2 神经网络语言模型:给词装上“性格向量”
N-gram 最大的问题是把词当成孤立的符号,“篮球”和“足球”在计算机眼里是两种毫无关联的编号。神经网络语言模型(Neural Network Language Model,简称 NNLM)改变了这一点:它给每个词学一个向量,也就是一串数字。这个向量可以理解为词的“性格画像”,意思相近的词,它们的向量也相近。
再来看它的工作方式。模型拿到了一串前文,比如“我想去”,它的第一件事是查这前几个词的词向量,然后把这些向量拼成一个长向量。接着,这个长向量经过一个全连接层,再用 tanh 激活函数做一次非线性变换。最后经过输出层,输出一共有 V 个节点,V 是词典大小。每个节点对应“下一个词可能是词表中的第几个词”,再用 softmax 把这些分数压成概率。概率最高的那个词,就是模型认为最合理的结果。
这个架构不需要你手推,初学者也不必把里面每个矩阵怎么算都搞明白。你只需要记住一句话:神经网络不再死记硬背“谁后面该接谁”,而是学会了一套“词与词之间的相处规则”。因为词向量保存了语义的相似性,所以哪怕某个组合在训练语料里没出现,只要它和一个见过的模式相似,模型也能给一个说得过去的概率。这一步,就是 N-gram 时代求之不得的“泛化能力”。
3.3 一次看懂“预训练 + 微调”:先背世界,再学说话
神经网络解决了一部分稀疏问题,但早期研究者还是老实训练一个专门做翻译的语言模型,或者专门做分类的语言模型,每个任务都重新训练。这太贵了,而且每换一个任务,模型就要把“人类语言的基本知识”重新学一遍,想想都浪费。
于是有了一个革命性思路:预训练加微调。预训练的意思是,先用海量的、乱七八糟的通用文本,让模型自己学任务——比如给它一句话,遮住中间一个词让它猜。这个阶段不针对任何具体任务,只是让模型理解语言的一般规律。微调的意思是,在预训练好的模型基础上,再拿某个具体任务的小数据集接着训练一小段时间,让模型把这个任务的“活儿”学会。你可以类比成一个人先在学校里学完听说读写,再进公司学习怎么做报表,后者只需要很短的时间。
这个范式的典型代表,就是 GPT、BERT、T5 这一大家子。它们的共同点是:先在海量通用数据上预训练,再拿去处理下游任务。好处非常明显:泛化能力更强、学到的语义更丰富、不容易过拟合。代价也有:预训练阶段实在太吃计算资源了,而且模型越深,解释起来就越困难,常被人吐槽是“黑匣子”——它给了你一个好用的模型,但你说不清它到底靠什么做的判断。
4. 大语言模型的特别之处:参数上了“亿”,世界就不一样了
4.1 多大的参数才配叫“大模型”
从语言模型到大语言模型,最直观的变化就是参数数量。一般我们说,当前把参数量超过 10B 的模型称为大语言模型。10B 就是 100 亿,这是个什么概念?一个普通的中型预训练模型,参数量可能只有几亿;而到了“大语言模型”这个门槛,参数至少 100 亿起步,最新一代甚至动辄数千亿。
参数是什么?你可以粗浅地理解为,它是模型内部需要自己调整的“旋钮”。旋钮越多,模型理论上能记住的规律就越多,表达力就越强。同一个模型家族,往往参数翻一倍、两倍、四倍,性能也跟着水涨船高。在 2020 年,某团队发布了参数量达到 1750 亿的 GPT-3,第一次让大众意识到:原来模型大到这种程度,会发生一些比“性能提升”更让人意外的事情。
4.2 “涌现能力”:为什么大模型不用重新训练就能干活
过去我们用 BERT 做某个任务,总得拿任务数据微调一下。但 GPT-3 这种规模的模型出现了一个神奇的改变:它可以不调整任何权重,只靠你给的几个任务示例就完成任务。你把一个例子放进去,它就能照着这个例子回答下一个类似问题。这种现象后来被称为“涌现能力”——简单说,就是小模型做不到、只有模型大到一定程度才突然解锁的能力。
这也是为什么大语言模型和以前的预训练语言模型,用起来感觉完全不一样。你不需要再专门为“情感分类”或“问答”各准备一套微调流程,而是直接说出你的要求,比如“把下面这段文本分类为正面或负面”,模型就能理解。它甚至能使用一些插件去做自动信息检索、查资料,而这些能力在小模型上很难看到。这让它看起来真的“像人一样智能”,能对话、能翻译、能写代码、能归纳文档——你给它一个接口,它就能去调工具。
4.3 能力范围与代价:一份新手需要知道的账
我们引用一个常见的定义:大语言模型是一种人工智能模型,旨在理解和生成人类语言,可以处理文本分类、问答、翻译、对话等多种自然语言任务。它的优点总结起来是这么几点:第一,它具备类似人类的沟通聊天能力;第二,它能处理开放式生成任务,而不只是做选择题;第三,它可以通过插件扩展能力边界。这些特点,让大语言模型从实验室名词变成了普通人都能直接使用的基础工具。
但大模型并不是没有缺点的“完美答案”。它的缺点也很直白:参数量太大,算力要求极高,训练时间长到以月计算。更麻烦的是,它可能生成有害的、片面的、有偏见的内容——这个问题从技术上讲很难彻底根除,因为模型是从互联网文本里学到的知识,而互联网本来就不总是正确的。所以入门学习时,你得同时建立两个心态:既不过度神化它,也不因为它在某些例子上的“犯蠢”就全盘否定它。了解它的边界,恰恰是深入学习的第一步。
5. 入门避坑指南:零基础最容易踩的 5 个坑
5.1 坑一:把大语言模型和所有语言模型混为一谈
现象:初学者经常把 N-gram、BERT、GPT、ChatGPT 全都当成一个东西,谈起模型时哪个名词方便说哪个。
原因:这些词都属于“语言模型”这个家庭,但技术路线完全不同。N-gram 是纯统计模型,靠数数;BERT 是预训练模型,擅长理解;GPT 是大语言模型,擅长生成。混着说,会让之后读任何资料都一头雾水。
解决:给每一个新概念做一张“名片”,写清楚两点:它属于哪一代技术、它擅长做什么。遇到新词先归档,再往下读。这也是最省钱的学习习惯。
5.2 坑二:看到公式就害怕,觉得数学不好学不了
现象:一看到 P(Wn|W1,...,Wn-1) 就头皮发麻,默默关掉了教程。
原因:很多资料默认读者有概率论基础,但新手缺的不是数学能力,而是把符号翻译成画面的经验。
解决:你只需要做到“读懂故事”的程度。P(B|A) 就念作“在 A 出现的条件下 B 出现的概率”,链式法则只是把句子拆成一块一块的接龙概率。第一次学的时候,把公式旁边标上中文注释,不要让自己陷入符号深渊。连公式都不用自己推,等你需要做研究时再补也来得及。
5.3 坑三:忽略评估指标,只看“说话顺不顺”
现象:试了几个模型,觉得效果都差不多,想不出来该选哪个。
原因:人工“看着顺不顺”太主观,而且不同场景下顺不顺的标准不一样。量化评估很重要,但新手最容易忽略。
解决:入门阶段先认识两个指标:困惑度(Perplexity,简称 PPL)和准确率。困惑度衡量的是语言模型对一段文本的意外程度,数值越低,说明模型预测得越准;准确率则用于分类、问答这类有标准答案的任务。“我选一个模型”这类决策,应该跟着数字走,而不是跟着感觉走。
5.4 坑四:一上来就想挑战训练大模型
现象:看到网上各种模型跑出来的酷炫效果,立刻想下载一个几亿参数的模型,训练出自己的天马行空版。
原因:很多人不知道训练一个真正的大模型,需要几十块高性能显卡和几个月的时间,个人电脑根本装不下。
解决:先把两步分开:第一步,用别人训练好的、开放权重的小型模型做推理,体验输入输出;第二步,再考虑在自己的小数据集上做微调。你要明确自己的目标是“会用模型”还是“会训模型”,两条路的投入完全不同。
5.5 坑五:数据不提质量,一股脑喂进去
现象:好不容易搞到一批语料,啥也不管直接训练,结果模型出来全是胡言乱语,或者翻来覆去都是那句重复的话。
原因:语料里有大量重复文本、格式混乱的内容和噪声,语言模型学到的是这些数据的统计规律,数据烂,模型就烂。
解决:训练之前至少做两步清理:去重和格式统一。哪怕是最简单的入门实验,也不要直接拿原始文本开练。等你有经验后,还要做更细的清洗与过滤。数据质量决定了模型质量,这句话在 NLP 领域怎么强调都不过分。
6. 下一步学什么:三个看得见的路口
6.1 先补上评估指标的课:困惑度到底怎么读
既然前面提到了困惑度,我建议你把它当成第一个要弄懂的具体指标。它的核心思想特别简单:模型对下一词越“意外”,困惑度越高;越“笃定”,困惑度越低。一个完全随机的模型,困惑度大约是词典大小;一个优秀的语言模型,困惑度可以低到几十甚至十几。入门阶段,你只要会用这个指标比较两个模型就够了。
# 一个帮助理解困惑度的最小示例:对比两个“假想模型”的表现 import math # 假设真实文本里,下一个词是“篮球” prob_model_a = 0.2 # 模型 A 认为“篮球”出现的概率 prob_model_b = 0.8 # 模型 B 认为“篮球”出现的概率 # 困惑度 = 概率倒数的几何平均;单个词时就是 1 / P ppl_a = 1 / prob_model_a ppl_b = 1 / prob_model_b print("模型A困惑度:", ppl_a) print("模型B困惑度:", ppl_b) print("困惑度更小的是:", "模型A" if ppl_a < ppl_b else "模型B")这里只是一个展示计算逻辑的玩具例子:概率高,困惑度低,模型表现更好。真实使用时,困惑度是在整个测试集上计算的,但道理一脉相承。
6.2 三条学习路线,选一条扎进去
如果你目标是做应用,优先学怎么用现成的模型接口。你的学习路径是:学会构造提示词,学会调用模型完成分类、抽取、翻译、对话,再学一点模型部署的知识,不碰底层训练。
如果你目标是做技术研发,重点放在预训练和微调的基本功上。你的路径是:学好 Python 和 PyTorch,用一个开源预训练模型跑通微调流程,再深入去读 Transformer 的结构,尝试改模型。
如果你目标是做研究,那就要开始系统补数学和论文精读。概率论、线性代数、深度学习基础,再加每周读一篇经典论文。这条路最长,但也是最能看得懂大模型底层逻辑的路线。
6.3 我的一个习惯,分享给你
我第一次学语言模型的时候,特别着急想跑代码,觉得跑起来了就代表会了。后来才发现,概念没打通时,代码跑通了也只是照着别人抄作业。从那以后,我每次接触一个新模型,都强制自己先回答三个问题:它属于语言模型发展史的哪个阶段?它的输入和输出是什么?它的评估指标是什么?走完这一遍,再动手写代码。这套笨办法救了我很多次,希望也能帮到你。
本文还有配套的精品资源,点击获取