LLM早期学习笔记
随着AI大模型技术的快速发展,其实从今年5月份开始,我也越发觉得LLM在企业中的应用越来越广泛,因此我也开始学习LLM,本文是一些LLM相关的学习笔记,主要记录了LLM的发展历程、应用场景、基本的技术原理等,另外本篇还侧重于介绍NLP中一些常见的概念,这样能快速的切入到大模型的学习中。
为什么要学习大模型(ChatGPT)?
人工智能时代的趋势
- 人工智能大潮已来,不掌握就可能被淘汰。
- 类似职场中使用PPT和Excel的基本技能。
使用与熟练的区别
- 掌握基本使用方法 ≠ 使用好。
- PPT、Excel、Python等,掌握好的人待遇明显更高。
- 大模型也是一样,未挖掘潜力时容易胡乱回答,用得好则效率和效果大幅提升。
大模型的局限性
- 并非万能,不能直接解决企业内部具体问题,需要进行微调或训练。
ChatGPT/GPT的影响
对社会
- 本质是高效的信息聚合工具,取代大量基础的信息整合工作(写报告、财经文章、代码等)。
- 不会完全取代岗位,但提高了某些岗位的效率,可能降低这些岗位的需求。
对行业
- GPT3到GPT4并非重大技术突破,而是交互方式更贴近人类需求,表现更惊艳。
对个人
- 掌握开发和微调模型的能力是关键。
- 未来将大量产生垂直领域的GPT类模型开发岗位。
- 掌握如何构造高效的Prompt指令提升效率。
课程设计逻辑与学习建议
设计逻辑
- 从基础词向量到大模型(MLP到GPT)逐步演进。
- 不宜过于深入基础,也不能完全省略基础知识。
- 直接复现GPT对初学者门槛过高,故强调历史逻辑逐步演进学习。
学习建议
- 已掌握内容可跳过;数学遗忘建议复习(向量、矩阵、概率分布)。
- 编程实践简单,熟悉可跳过;不熟悉则建议逐步实践。
为什么使用GPT2而非GPT3?
- GPT3(175B参数)计算资源需求巨大,显存需求近1TB,普通硬件无法承受。
- GPT2(109M)更适合学习与演示,占用显存约500M。
- GLM公开版本109M(教学)与2.6B(挑战)更具实际操作性。
框架选择(Paddle、Torch、Huggingface)
Paddle使用原因
- 百度提供免费环境(32G V100),对无计算资源的学习者友好。
- Paddle与Torch类似,上手容易,但部分功能需查文档。
- 掌握多个框架是优势,未来国产GPU/NPU可能仅支持Paddle。
框架对比
- Tensorflow: 最早框架,工程配套强大,但易用性较差。
- Torch: 易用性强,最新Torch2.0性能显著提升。
- Paddle: 结合Tensorflow与Torch优点,易用性好但生态相对较弱。
Huggingface介绍
- Transformer领域的Github。
- 基于PyTorch,模型和数据资源丰富,便于快速微调。
- PaddleNLP类似Huggingface,但活跃度和资源量远逊。
AIStudio平台简介
- 百度推出,免费提供GPU资源兑换(V100、A100),便于无资源用户学习。
- 显存容量对大模型训练更为关键(比GPU芯片重要)。
大模型发展史
自然语言处理(NLP)领域从静态词向量,到动态词向量,再到对话模型的发展演进路径:
-
静态词向量阶段:
- 经典方法:
skip-gram
、CBOW
、GloVe
、fastText
。 - 特点:生成的词向量不随上下文改变,无法体现词汇的语义变化。
- 经典方法:
-
动态词向量阶段:
- 典型模型:
ELMo
、Transformer
、BERT
、Ernie
系列。 - 特点:词向量能够随上下文变化,更好地捕获语义细节。
- 典型模型:
-
Prompt与Zero-shot阶段:
- 典型模型:
GPT 1,2
→GPT3
→InstructGPT
→ChatGPT
。 - 特点:强调通过Prompt(提示)和零样本(Zero-shot)方式,模型能够处理未见过的任务,更加通用和灵活。
- 典型模型:
-
对话阶段:
- 典型模型:
Plato
、WebGPT
、ChatGPT
。 - 特点:专注于自然的人机对话与交流能力。
- 典型模型:
我列出了各种模型的应用场景(如摘要、翻译、分类、序列标注、阅读理解),以及模型初始训练(初始化)与后续微调(finetune)的过程。总体而言,这是NLP技术发展的脉络,从静态向量到动态向量再到通用的生成与对话模型,体现了模型越来越强大的泛化能力和交互性:
graph LR
A["自然语言处理(NLP)发展史"] --> B["静态词向量阶段"]
A --> C["动态词向量阶段"]
A --> D["Prompt与Zero-shot阶段"]
A --> E["对话阶段"]
B --> B1["skip-gram"]
B --> B2["CBOW"]
B --> B3["GloVe"]
B --> B4["fastText"]
B --> B5["特点:词向量不随上下文改变<br/>无法体现词汇语义变化"]
C --> C1["ELMo"]
C --> C2["Transformer"]
C --> C3["BERT"]
C --> C4["Ernie系列"]
C --> C5["特点:词向量随上下文变化<br/>更好捕获语义细节"]
D --> D1["GPT 1,2"]
D1 --> D2["GPT3"]
D2 --> D3["InstructGPT"]
D3 --> D4["ChatGPT"]
D --> D5["特点:通过Prompt和Zero-shot方式<br/>处理未见过的任务,更通用灵活"]
E --> E1["Plato"]
E --> E2["WebGPT"]
E --> E3["ChatGPT"]
E --> E4["特点:专注自然的<br/>人机对话与交流能力"]
F["应用场景"] --> F1["摘要"]
F --> F2["翻译"]
F --> F3["分类"]
F --> F4["序列标注"]
F --> F5["阅读理解"]
G["训练过程"] --> G1["初始训练(初始化)"]
G1 --> G2["后续微调(finetune)"]
词向量
词向量与gpt有什么关系?可以说词向量是gpt的基石,gpt的训练过程就是通过词向量来训练的。词向量开启了预训练的大门,之前要么基于传统机器学习(HMM、CRF、BOW等),要么基于one-hot直接进网络训练。
要理解词向量,可以把它想象成在多维空间中为每个词赋予一个坐标。在这个"语义空间"里,意思相近的词,它们的坐标也相近。这就像在地图上,北京和上海的地理位置很近,所以它们的经纬度坐标也相似。
词向量最神奇的一点是,向量之间的运算也能对应现实世界中的语义关系。一个经典的例子是:
vector('国王') - vector('男') + vector('女') ≈ vector('女王')
这说明模型捕捉到了"性别"这个抽象概念,并将其表示为了空间中的一个方向。
这种表示方式远优于传统的one-hot
编码,因为one-hot
将每个词都视为独立的、互不相关的维度,无法体现词与词之间的相似性。
gpt与bert本质上都可归类为动态词向量,最开始gpt1和bert只是训练方式的不同,目标都是为了解决下游任务。这里的"动态"指的是词的向量表示会根据上下文而改变。例如,“bank"这个词在"river bank”(河岸)和"investment bank"(投资银行)这两个短语中的意思完全不同,因此动态词向量模型会为它们生成两个不同的向量,从而更精确地捕捉其含义。
语言模型
语言模型是什么?
语言模型用于评估一个句子出现的概率,判断句子是否正确,是否符合语法。 例如,一个好的语言模型会认为句子"我喜欢学习人工智能"出现的概率很高,而对于"学习喜欢我人工智能"这样不合语法的句子,给出的概率则会很低。它就像一个语法和常识的裁判。
数学表示: $$ p(W) = p(w_1, w_2, …, w_T) $$
这个公式叫做概率的链式法则。它告诉我们,一个完整句子的概率,等于第一个词出现的概率,乘以在第一个词出现条件下第二个词出现的概率,再乘以在前两个词都出现的条件下第三个词出现的概率,以此类推。
举个例子,计算"我今天很高兴"的概率:
P("我", "今天", "很高兴") = P("我") * P("今天" | "我") * P("很高兴" | "我", "今天")
$$ p(W) = p(w_1)p(w_2|w_1)p(w_3|w_1,w_2)…p(w_t|w_1,w_2,…w_{t-1}) $$
传统语言模型的问题
-
参数空间太大
- 句子长度=T,词表=N,参数空间=N^T
- 想象一下,即使我们的词汇表只有10000个词,我们要预测的下一个词依赖于前面5个词,那么所有可能的组合数量将是一个天文数字 (10000^5)。我们不可能在任何语料库中见到所有这些组合,也无法存储这么多参数。
-
稀疏性太强
- 若w_i在语料库中没出现过,那么概率=0
- 这个问题更致命。意思是很多词的组合在训练数据中根本没出现过。例如,语料库里有大量的"今天天气很好",模型学会了
P("很好" | "今天天气")
。但如果语料库里从未出现过"今天心情很好",模型可能就会错误地认为P("很好" | "今天心情")
的概率是0。这显然是不对的,因为模型没有学会"天气"和"心情"可以被类似地修饰。 - 解决方案:加入约束性假设
N-Gram模型
如何计算一个词出现的概率?
基于语言环境中出现的次数,当语料库足够大时:
$$ P(w_k|w_1,…,w_{k-1}) = \frac{count(w_1,…,w_k)}{count(w_1,…,w_{k-1})} $$
举个例子,假设我们的语料库只有一句话:“我爱北京天安门,天安门上太阳升”。
我们来计算P("门" | "天安")
的概率(使用2-gram,即Bigram)。
首先,计算分母count("天安")
,“天安"出现了2次。
然后,计算分子count("天安门")
,“天安门"这个组合也出现了2次。
所以概率是 2/2 = 1
。
马尔可夫假设
当前词出现的概率只与前面N个词相关: 这是一种"目光短浅"的假设,认为一个词的出现,只和它身边的几个词有关,和更久远的历史无关。这大大简化了问题,但也牺牲了捕捉长距离依赖的能力。比如在句子"我出生在中国,……,我的母语是汉语"中,最后一个词"汉语"其实和开头的"中国"有很强的关联,但一个很短的N-Gram模型可能就捕捉不到了。
$$ P(w_k|w_1,…,w_{k-1}) = P(w_k|w_{k-n+1},…,w_{k-1}) $$
具体计算: $$ P(w_k|w_1,…,w_{k-1}) \approx \frac{count(w_{k-n+1},…,w_k)}{count(w_{k-n+1},…,w_{k-1})} $$
N-Gram的分类
-
Unigram:不考虑前词依赖。每个词都相互独立。相当于把一句话的词都扔进袋子里,再一个个摸出来,完全不考虑顺序。
- 参数空间=N
-
Bigram(2-gram):考虑前面1个词。“管中窥豹,可见一斑”,只看前一个词。能构建简单的词语搭配,比如"人工"后面很可能跟"智能”。
- $P(w_k|w_1…w_{k-1}) = \frac{count(w_{k-1}w_k)}{count(w_{k-1})}$
- $P(W) = P(w_1)P(w_2|w_1)…P(w_T|w_{T-1}) = \prod_{i=1}^T P(w_i|w_{i-1})$
- 参数空间=N²
-
Trigram(3-gram):考虑前面2个词。“瞻前顾后”,多看一个词,看得更准一些。比如知道"我的"后面跟"名字"的概率,比知道"的"后面跟"名字"的概率要更准。
- 参数空间=N³
N越大,模型越能考虑更长的上下文,理论上越精确。但N越大,参数越多,稀疏性问题也越严重。比如"我爱北京天安门"这个5-gram组合,可能在整个互联网上也出现不了几次。
为什么要计算P(S)=P(W₁…Wₜ)?
-
非预训练场景
- N-gram信息作为特征工程,用于纠错、作为特征输入下游NLP任务。例如,在输入法中,如果用户输入 “I hav a pen”,系统可以比较
P("I have a pen")
和P("I hav a pen")
的概率。前者的概率会高得多,从而向用户建议纠正。
- N-gram信息作为特征工程,用于纠错、作为特征输入下游NLP任务。例如,在输入法中,如果用户输入 “I hav a pen”,系统可以比较
-
预训练场景
- 无监督(自监督)训练需要标签
- 语言模型通过前文预测下一个字,难度较高但应用场景多
- GloVe基于词语共现频率构建标签
- BERT基于整句预测中间缺失的词,与CBOW类似(前后词预测中间词)
语言模型的评估指标PPL
PPL(Perplexity)的定义
困惑度(Perplexity)用于评估语言模型的质量。它的直观解释是:模型在预测下一个词时,平均有多少个合理的选择项。
想象一下你在玩猜词游戏。如果模型对于"今天天气真"后面的词非常确定是"好”,那么它的困惑度就接近1,因为它只有一个选项。如果模型觉得可能是"好"、“不错”、“糟糕"等等,有多个不确定的选项,那么它的困惑度就会比较高。
因此,困惑度越低,说明模型对句子的概率分布预测得越准确,模型性能越好。
$$ PPL(S) = P(W_1W_2…W_n)^{-1/N} $$
$$ = \sqrt[N]{\frac{1}{P(w_1…w_n)}} $$
$$ = \exp\left(-\frac{1}{N}\sum_{i=1}^N \log P(w_i|w_1…w_{i-1})\right) $$
当语言模型使用2-gram时: $$ PPL(S) = \exp\left(-\frac{1}{N}\sum_{i=1}^N \log p(w_i|w_{i-1})\right) $$
神经网络语言模型
N-Gram模型虽然简单有效,但"稀疏性"和"无法泛化"的硬伤让它很快遇到了瓶颈。神经网络语言模型(Neural Network Language Model, NNLM)的出现,正是为了解决这些问题。
为什么需要神经网络?
思考一下N-Gram的根本问题:它把每个词(如"国王"和"皇帝”)都看作是孤立的符号,无法理解它们在语义上的相似性。如果训练数据里有"国王的演讲",但没有"皇帝的演讲",N-Gram就学不到任何关于后者的知识。
神经网络语言模型的核心思想就是:用词向量来表示词,让模型在向量空间中学习语义。
神经网络语言模型如何工作?
一个基本的神经网络语言模型通常包含以下步骤:
- 输入层(词向量): 不再是孤立的词,而是将输入词(如"我"、“爱”、“中国”)转换为低维、稠密的词向量。这些向量是模型参数的一部分,会在训练中不断学习优化。
- 隐藏层: 一个或多个神经网络层(如全连接层、RNN或Transformer),负责处理输入的词向量序列,捕捉词与词之间的复杂关系和语法结构。
- 输出层: 经过隐藏层计算后,输出一个非常长的向量,其维度等于词汇表的大小。这个向量经过Softmax函数处理,转换成一个概率分布,表示下一个词可能是词汇表中每一个词的概率。
graph TD
subgraph NNLM
A["输入:'the','cat','sat'"]
B["嵌入层:词转向量"]
C["隐藏层:RNN/Transformer 捕捉上下文"]
D["输出层/Softmax"]
E["预测概率:P('on')=0.8,P('slept')=0.1 等"]
A --> B
B --> C
C --> D
D --> E
end
神经网络的优势
- 缓解稀疏性问题: 这是最大的优势。因为相似的词(如"猫"和"狗",“国王"和"皇帝”)有相似的词向量。模型如果学会了处理"猫坐垫子上",它就能自动泛化到"狗坐垫子上",因为"猫"和"狗"的向量在模型看来是接近的。模型从学习"词的组合"变成了学习"语义的组合"。
- 能处理更长的上下文: 相比N-Gram固定的、很短的窗口,像RNN和Transformer这样的结构原则上可以考虑更长的历史信息,从而更好地理解语言的深层含义。