大模型学习路径系列(三)大模型架构
本文在前面语言模型和大模型能力的基础上,进一步解释什么是大模型,同时逐渐深入大模型智能涌现的底层原因。本文首先强调分词技术和大模型架构的重要性,并依据分割粒度进一步完成了对于分词算法的分类和代码实现。
随后会继续更新不同子词分词算法原理(已更新)和代码实现,以及关于大模型架构的深入解析。欢迎点赞收藏关注,也欢迎大家指正!
第三章 大模型架构
1、引言
1.1 什么是大模型?
想象一个能帮你解答生活琐事、创作艺术作品、编写程序,甚至推动科学发现和工程发展的“超级大脑”。这就是“大模型”。那么大模型到底是什么?
大模型的本质:从数据到智慧的飞跃
大模型是基于深度学习的神经网络,拥有数十亿到数千亿个参数,这些参数就像模型学会的“知识点”,通过复杂计算连接,赋予模型理解和生成语言、图像、音频等的能力。
它们的强大主要依赖于三个要素:数据、算力、架构。
第一,大模型在巨量文本、图像(如摄影作品、艺术插图)或多模态数据上训练,学会捕捉世界的规律。第二,大模型参数多、数据规模大的同时,而需要强大的算力支撑。模型训练需要数千GPU或TPU,耗时数周到数月完成一次训练。第三,大模型依赖于强大的模型架构和先进的算法,Transformer架构的突破让模型能够高效理解长序列信息,精准捕捉语义和上下文。
以Grok3、DeepSeek或ChatGPT背后的GPT系列为例,这些模型通过预训练掌握通用知识,再通过微调适配特定任务,如对话、翻译或代码生成。大模型就像一个全能知识库,能快速应对各种需求。
大模型的能力:从生活助手到推动行业变革
大模型的真正魔力在于它们的通用性——它们能轻松应对从生活琐事到全球挑战的各种任务,宛如一位随叫随到的智慧伙伴。大模型就像一位无所不能的智能伙伴,它能在你需要时轻松解答生活中的小问题——比如教你做一道符合口味的番茄炒蛋,或是告诉你明天要不要带伞。而当灵感来临时,它又能化身创作搭档,帮你写首小诗或是生成一张充满未来感的数字画作。在工作中,它更是得力的助手,无论是帮程序员写代码,还是替律师快速梳理合同条款,都能让你事半功倍。更令人惊叹的是,这些AI正在改变医疗诊断、教育教学等各行各业,甚至推动着像蛋白质结构预测这样的重大科学突破。从日常生活到专业领域,大模型正以惊人的适应力和创造力,重新定义着我们解决问题的方式。
最激动人心的,是大模型在科学前沿的壮举,比如DeepMind的AlphaFold。这种突破不仅改变了科学界的游戏规则,也让我们看到大模型的无限可能——它们不只是回答问题,而是为人类探索未知铺路。
分词与架构:大模型的语言基石与智慧核心
要理解大模型为何如此强大,分词和架构的协同作用不可忽视。分词是将文本拆解为最小意义单元(如单词、子词或字符)的过程,它是大模型理解语言的基础。比如,中文的“人工智能”可能被拆分为“人工”和“智能”,而英文的“unbelievable”可能被拆分为“un-”“believe”“-able”。高效的分词技术让模型能够处理多语言、复杂句式甚至俚语,确保从日常对话到学术论文的文本都能被准确解析。而架构则决定了这些分词后的单元如何被组织、理解和生成。Transformer架构通过其注意力机制(Attention),能动态聚焦文本中最重要的部分,捕捉长距离的语义关联,比如理解“他昨天买的书”中的“书”和“买”之间的关系。分词为模型提供了语言的“原料”,而架构则像一位大师级厨师,将这些原料烹饪成美味的菜肴。两者的配合使得大模型对于世界知识的学习能力突飞猛进。
由于知识点密集且重要,关于大模型架构的部分介绍我们会分为三大部分,每一部分用一篇或者几篇博客介绍:MLP基础与架构演变、Transformer架构详解(含代码)、大模型架构类型。本文介绍第一大部分。后面两部分的更新可以期待一下,马上到来~
2、NLP基础之文本处理技术
2.1 分词
分词是将文本拆解为最小意义单元(如单词、子词或字符)的过程,是大模型处理自然语言的基础步骤。自然语言(如中文、英文)是人类可读的文本,而大模型需要将文本转化为数字表示(即 token ID)以进行计算。
分词将文本分割成有意义的单元(如单词或短语),帮助模型更好地理解语义。例如,“我爱学习”分词后为“我”、“爱”、“学习”,每个token都承载一定的语义信息。通过分词(尤其是字词分词),可以有效控制词汇表的大小,避免语言中大量罕见词或新词导致词汇表无限膨胀。例如,“playing”和“played”可以共享词根“play”,减少冗余。
分词能够适应不同语言的特性(如中文无明显词界、英文有空格分隔),并处理标点、表情符号等非标准文本,确保模型对多种语言和格式的兼容性。分词后的token序列为模型提供了一个标准化的输入格式,便于Transformer等架构捕捉token间的上下文关系。
关于分词技术的分类多种多样,本文从分割粒度和语义单元出发,聚焦于分词的输出形式,更加直观,适合快速理解分词技术的核心差异。
2.1.1 Word Level
Word Level 的分词也是基于规则的单词分词,主要基于空格或者标点进行分割。
英文分词
直接基于空格和标点进行分割。
输入文本:I love learning new things!
分词器 Tokenizer:按空格或标点分割,保留标点或去除。
输出分词:["I", "love", "learning", "new", "thing", "!"]
中文分词
由于中文没有空格分隔,通常基于词典匹配或者规则。常见方法有,前/后向最大匹配(优先匹配词典中最长的词),双向匹配(解决歧义)。
输入文本:我爱学习新事物
分词器:使用词典匹配,基于前向最大匹配。
输出分词:["我", "爱", "学习", "新", 事物"]
注意:对于英文,Word Level 分词简单,但需处理缩写(如 don't 可能分为 do 和 n't)、连字符词(如 self-driving)等特殊情况。对于中文,分词效果高度依赖词典质量和算法选择,歧义(如 乒乓球拍卖 可分为 乒乓球 + 拍卖 或 乒乓 + 球拍 + 卖)是主要挑战。Word Level 分词对未登录词 (Out-of-Vocabulary,简称OOV),如新造词、专有名词,处理能力有限。
2.1.1(补充) Word Level代码实现
目标
知行合一,理解单词分词方法,动手实现中英文分词。学会使用正则表达式、外部库Jieba,设计可扩展代码。
代码语言
Python
实现过程
Step 1: 实现简单的英文分词
def word_tokenize_en(text):
# 按空格分割文本
tokens = text.split()
return tokens
text = "I love learning"
tokens = word_tokenize_en(text)
print(tokens)
由上图可见,虽然.split()
方法实现了英文单词的简单分词,但是标点符号与单词粘在一起,未成功分离。
Step 2: 改进英文分词,分离标点
import re
def word_tokenize_en(text):
# 匹配单词 \w+
# 匹配标点 [^\w\s]
# []用于定义一个字符集,匹配方括号中的任意一个字符。
# [^...] 表示匹配不在方括号内的任何字符
# [^\w\s] 表示匹配任何不是字母、数字、下划线或空白字符的字符
# r''表示原始字符串,忽略字符串中的转义字符"\"
tokens = re.findall(r'\w+|[^\w\s]', text)
return tokens
text = "I love learning!"
tokens = word_tokenize_en(text)
print(tokens)
Step 3: 实现中文分词
中文没有空格分隔,需要借助分词工具。本文使用 Jieba 分词处理中文文本。Jieba是一个流行的中文分词库,基于词典和统计模型。jieba.cut()
返回分词结果,需转换为list。
jieba.cut() 实现精确的分词
jieba.cut_for_search() 搜索引擎模式,在精确分词的基础上,进一步对长词进行划分。
import jieba
def word_tokenize_en(text):
tokens = list(jieba.cut(text))
return tokens
text = "我爱学习新事物!"
tokens = word_tokenize_en(text)
print(tokens)
Step 4: 处理中英文混合文本
区分中英文片段,分别调用英文和中文分词逻辑。其中,中文字符的Unicode范围\u4e00-\u9fff(CJK汉字)
import re
import jieba
def word_tokenize(text):
# 初始化分词结果
tokens = []
# 分离中英文片段
segments = [] # 列表初始为空,用于存储文本片段,每个片段是一个元组 (lang, segment)
current_segment = "" # 用于存储正在构建的文本片段,就是存储当前符合某标准的字符
is_chinese = False # 表示当前字符是否为中文
for char in text:
# 如果最新的char是中文
if '\u4e00' <= char <= '\u9fff':
# 如果当前正在构建的片段不是中文 并且 当前片段不为空
# 则将当前片段标记为en,与当前片段存入分割中;
# 其他情况(正在构建的片段是中文 或者 当前正在构建的片段为空)
# 则将最新字符放入正在构建的片段
# 标记正在构建的片段是中文
if not is_chinese and current_segment:
segments.append(("en", current_segment))
current_segment = char
else:
current_segment += char
is_chinese = True
else:
if is_chinese and current_segment:
segments.append(("zh", current_segment))
current_segment = char
else:
current_segment += char
is_chinese = False
if current_segment:
segments.append(("zh" if is_chinese else "en", current_segment))
# 分别处理中英文片段
for lang, segment in segments:
if lang == "zh":
# 中文使用 Jieba 分词
seg_list = jieba.cut(segment)
tokens.extend(seg_list)
else:
# 英文使用正则表达式
seg_list = re.findall(r'\w+|[^\w\s]', segment)
tokens.extend(seg_list)
return tokens
# 测试
text_en = "I love learning!"
text_zh = "我爱学习新事物!"
text_mixed = "我爱learning 新things!"
print("英文:", word_tokenize(text_en))
print("中文:", word_tokenize(text_zh))
print("混合:", word_tokenize(text_mixed))
Step 5: 添加配置项(可选)
使用类对分词器进行封装,添加参数控制行为。
keep_punctuation:决定是否保留标点。
lowercase:决定是否将英文转小写。
import re
import jieba
from typing import List
class WordLevelTokenizer:
def __init__(self, keep_punctuation: bool = True, lowercase: bool = False):
self.keep_punctuation = keep_punctuation
self.lowercase = lowercase
jieba.initialize()
def tokenize(self, text: str):
if self.lowercase: # 统一为小写
text = text.lower()
text = text.strip() # 清除字符串首尾的空白字符
tokens = []
segments = []
current_segment = ""
is_chinese = False
for char in text:
if '\u4e00' <= char <= '\u9fff':
if not is_chinese and current_segment:
segments.append(("en", current_segment))
current_segment = char
else:
current_segment += char
is_chinese = True
else:
if is_chinese and current_segment:
segments.append(("zh", current_segment))
current_segment = char
else:
current_segment += char
is_chinese = False
if current_segment:
segments.append(("zh" if is_chinese else "en", current_segment))
for lang, segment in segments:
if lang == "zh":
seg_list = jieba.cut(segment)
tokens.extend(seg_list)
else:
if self.keep_punctuation:
seg_list = re.findall(r'\w+|[^\w\s]', segment)
else:
seg_list = re.findall(r'\w+', segment)
tokens.extend(seg_list)
return tokens
# 测试
tokenizer = WordLevelTokenizer(keep_punctuation=True, lowercase=True)
print(tokenizer.tokenize("I love learning!"))
print(tokenizer.tokenize("我爱学习新事物!"))
print(tokenizer.tokenize("我爱learning 新things!"))
2.1.2 Character Level
英文分词
将英文文本按单个字符(字母、数字、标点、空格)分割。
输入文本: I love learning!
分词器:逐字符分割,每个字符作为一个token
输出分词:["I", " ", "l", "o", "v", "e", " ", "l", "e", "a", "r", "n", "i", "n", "g", "!"]
中文分词
每个汉字或标点作为一个token,无需词典或匹配算法。
输入文本:我爱学习
分词器:逐汉字或标点分割。
输出分词:["我", "爱", "学", "习"]
注意:Character Level 分词对新词、罕见词和多语言文本处理能力强,但是序列长度增加可能导致Transformer模型的计算复杂度(与序列长度平方相关)显著上升。如,使用基于单词(word)的标记器(tokenizer),单词只会是单个标记,但当转换为字母/字(character)时,它很容易变成 10 个或更多的标记(token)。
2.1.2(补充) Character Level代码实现
目标
知行合一,理解字符分词方法,动手实现中英文分词。学会使用正则表达式、外部库Jieba,设计可扩展代码。
代码语言
Python
实现过程
编写函数,将文本分割为单个字符(包括汉字、字母、数字、标点、空格),支持中英文和标点处理。
Step 1: 实现基本字符分词
Python的字符串是字符序列,直接用list()
或循环遍历。
def char_tokenize(text):
# 逐字符分割
tokens = list(text)
return tokens
text = "我爱learning!521"
tokens = char_tokenize(text)
print(tokens)
Step 2: 添加标点和空格过滤
char.isspace():检查是否为空格
。
[^\w\s]:匹配标点(非字母/数字且非空格)
。
def char_tokenize(text, keep_punctuation=True, keep_space=True):
tokens = []
for char in text:
# 过滤掉空格和标点
if not keep_space and char.isspace():
continue
if not keep_punctuation and re.match(r'[^\w\s]', char):
continue
tokens.append(char)
return tokens
text = "我爱 learning!"
print(char_tokenize(text, keep_punctuation=True, keep_space=True))
print(char_tokenize(text, keep_punctuation=False, keep_space=False))
Step 3: 封装
import re
from typing import List
class CharacterLevelTokenizer:
def __init__(self, keep_spaces: bool = True, keep_punctuation: bool = True):
self.keep_spaces = keep_spaces
self.keep_punctuation = keep_punctuation
def tokenize(self, text: str) -> List[str]:
text = text.strip()
tokens = []
for char in text:
if not self.keep_spaces and char.isspace():
continue
if not self.keep_punctuation and re.match(r'[^\w\s]', char):
continue
tokens.append(char)
return tokens
def detokenize(self, tokens: List[str]) -> str:
return "".join(tokens)
# 测试
tokenizer = CharacterLevelTokenizer(keep_spaces=True, keep_punctuation=True)
print(tokenizer.tokenize("I love learning!"))
print(tokenizer.tokenize("我爱学习新事物!"))
print(tokenizer.tokenize("我爱learning 新things!"))
tokenizer_no_space_punct = CharacterLevelTokenizer(keep_spaces=False, keep_punctuation=False)
print(tokenizer_no_space_punct.tokenize("我爱learning 新things!"))
2.1.3 Sub-word Level(重点)
子词Sub-word Level分词是一种介于单词分词和字符分词之间的分词方法,将文本分割为字词单元(subword units),这些单元通常是单词的片段(如词根、前缀、后缀)或高频字符组合。子词分词在现代大模型(BERT、GPT、LLaMA)中广泛使用,因其再语义表达、词汇表规模和计算效率之间取得了良好的平衡。
子词分词将高频词或语义完整的单元保留位单一token(如英文love、中文”学习“),以捕捉语义。对于低频词或者复杂词,分解为更小的子词(如,playing → play + ##ing,人工智能 → 人工+智能),确保模型能够通过组合理解新词。
子词分词算法依赖于这样一个原则,即不应将常用词拆分为更小的子词,而应将稀有词分解为有意义的子词。
子词分词通过算法(如Byte-Pair Encoding、Word Piece、Sentence Piece等)基于语料库统计学习子词单元。能够平衡语义完整性和序列长度,生成适中的词汇表(通常30k-100k)。
注意:Subword 分词结果高度依赖训练语料和词汇表。若语料未涵盖某些词(如专有名词),可能拆分为字符级(如 红楼梦 → 红 + 楼 + 梦)。中文标点(如 ,。!)通常作为独立 token,但需确保与英文标点(如 , .)编码一致(如 UTF-8)。
由于子词分词是大模型常用分词技术,因此将子词分词的不同算法分别单独作为一小节进行介绍。
按照分割粒度划分的分词技术(图片来自https://github.com/luhengshiwo/LLMForEverybody)
总结
本文首先引入关于大模型的介绍,方便大家对大模型有个初步的轮廓。在介绍的基础上强调分词和架构对于大模型魔力的重要地位。本文重点介绍了根据分割粒度的分词算法分类,并给出基于单词和基于字符分词的简单代码实现,方便大家动手学习,加深对于分词算法的理解。
由于篇幅和知识密集程度原因,关于字词分词的算法(如Byte-Pair Encoding、Word Piece、Sentence Piece等算法)会在即将更新的博客中介绍,欢迎浏览博主主页内容。留个关注,不见不散~