从零构建大模型|2026-4-5|Last edited: 2026-4-21|
type
Post
status
Published
date
Apr 5, 2026
slug
text_handle
summary
LLM
tags
LLM
category
从零构建大模型
icon
password
原文

2.1 词嵌入

LLM在内的深度神经网络模型无法直接处理原始文本。
原因:文本数据是离散的,无法直接用它来执行神经网络训练的数学运算。我们需要一种将单词表示为连续值的向量格式的方法。
将数据转换为向量格式的过程通常称为嵌入(embedding)
可以通过特定的神经网络层或利用另一个预训练的神经网络模型来嵌入不同类型的数据(如视频、文本、音频)
不同的数据格式需要使用不同的嵌入模型。例如为文本设计的嵌入模型并不适用于嵌入音频数据或视频数据。
嵌入模型 ≠ 大模型,LLM 自身是有嵌入模型。
Query → LLM内部的嵌入层(转成向量)→ Transformer层 → 输出文字
RAG中的嵌入模型是将文本转向量去匹配相关片段,它本身不使用向量与模型交互。
多模态模型是需要多种嵌入模型
嵌入的本质是将离散对象(如单词、图像甚至是整个文档)映射到连续向量空间的点,目的是将非数值的数据转换为神经网络可以处理的格式。
词嵌入是文本嵌入中最常见的形式,但也存在针对句子、段落、整个文档的嵌入技术。这中技术在检索增强生产领域非常流行(RAG)。

word2vec

通过训练神经网络架构,word2vec 实现了根据目标词预测上下文,或者根据上下文预测目标词,从而生成词嵌入。
核心思想:出现在相似上下文的词往往具有相似的含义。
词嵌入的维度(dimension)可以从一维到数千维不等,更高的维度有助于扑捉到更细微的关系,但这通常以牺牲计算效率为代价。
dimension 简单来说就是向量的长度。
维度大的特征不是人类定义的,是模型自己学出来的。
高维嵌入难以进行可视化,人类感官以及常见的图形表示方法本质上局限于三维或更低的维度。
虽然可以使用word2vec等预训练模型为机器学习模型生成嵌入,但大语言模型通常会自行生成嵌入。这些嵌入是输入层的一部分,并且会在训练过程中进行更新。与使用word2vec相比,将嵌入作为大语言模型训练的一部分进行优化的优势在于,嵌入可以针对特定的任务和数据进行优化。
LLM 自有嵌入模型

2.2文本分词

文本分词就是将文本切割成单词和符号,将其转换成一个词元 ID。

2.3 词元转换成词元 ID

notion image
这里有个缺陷,如果分词器 decode 或者 encode 一个没有在词汇表中出现过的词,那么就会有异常。

2.4 引入特殊上下文词元

引入特殊词元来增强模型对上下文和其他相关信息的理解。这些词元可能包括用于标识未知词汇和文档边界的词元。
notion image
notion image
在训练类 GPT 大语言模型时,如果使用多个独立的文档或图书作为训练材料,通常都会在每个文档或图书的开头插入一个词元,以区分前一个文本源。
在不同的LLM 中,可能会引入以下特殊词元。
  • [BOS](序列开始):标记文本的起点,告知大语言模型一段内容的开始。
  • [EOS](序列结束):位于文本的末尾,类似<|endoftext|>,特别适用于连接多个不相关的文本。例如,在合并两篇不同的维基百科文章(或两本不同的图书)时,[EOS]词元指示一篇文章的结束和下一篇文章的开始。
  • [PAD](填充):当使用批次大小(batch size)大于1的批量数据训练大语言模型时,数据中的文本长度可能不同。为了使所有文本具有相同的长度,较短的文本会通过添加[PAD]词元进行扩展或“填充”,以匹配批量数据中的最长文本的长度
GPT模型使用的分词器并不依赖这些特殊词元,而是仅使用<|endoftext|>词元来简化其处理流程。<|endoftext|>词元与[EOS]词元作用相似
GPT模型的分词器也不使用<|unk|>词元来处理超出词汇表范围的单词,而是使用BPE分词器将单词拆解为子词单元,具体参见2.5节。

2.5 BPE

BPE 分词器用于训练大语言模型,比如 GPT2、GPT3和 chatGPT的原始模型。
💡
BPE(Byte Pair Encoding)是一种简单、高效的子词分词算法,专门解决「生词」和「大词汇表」问题。
核心思想:从单个字符开始,不断合并出现频率最高的相邻字符对,直到达到目标词汇表大小

BPE如何处理未知词汇?

BPE 没有使用<|unk|>词元
原理:是将不在预定义词汇表中的单词分解为更小的子词单元甚至单个字符,从而能够处理词汇表之外的单词。
它可以将其表示为字词词元或字符序列。
notion image

2.6 使用滑动窗口进行数据采样

为了生成大语言模型的嵌入向量,接下来的步骤是生成用于训练模型的输入-目标对()
大语言模型是通过预测文本序列的下一个单词来进行预训练。
图 2-6
图 2-6
给定一个文本样本,我们从中提取子样本,作为输入块提供给大LLM。在训练过程中,模型的任务是预测输入块之后的下一个词,我们会屏蔽目标词之后的所有单词。必须说明的是,在模型处理文本之前,文本会经过分词处理。
数据加载器使用滑动窗口从训练数据集中提取类似图 2-6 的所示的输入-目标对(在代码中有体现)。
步幅(stride)决定了批次之间输入的位移量,模拟了滑动窗口方法。
notion image
为了实现高效的数据加载器,我们将输入收集到张量x中,其中每行代表一个输入上下文。第二个张量y包含相应的预测目标(下一个词),它们是通过将输入移动一个位置创建的

数据加载器

在词元转换成嵌入向量前,还需要实现一个高效的数据加载器(data loader)。这个数据加载器会遍历输入数据集,并将输入和目标以PyTorch 张量的形式返回,这些 PyTorch 张量的形式返回,这些 PyTorch 张量可以被视为多维数组。
 
💡
数据加载器解决的是数据怎么喂给模型
具体来说目标是返回两个张量
  1. 包含大语言模型所见的文本输入的输入张量
  1. 包含大语言模型需要预测的目标词元的目标张量。
💡
这里先简单记下数据加载器的常用参数意义
  • max_length: 上下文长度,也就是说模型每次最多参考前面 max_length 个词。
  • stride :滑动步长/偏移量
    • 无重叠:如果 max_length = stride 大白话就说每抄 10 个字,向后挪 10 个字,批次之间无重叠。重叠的好处 无冗余、速度快,但是学不到完整上下文、泛化能力差。
      有重叠: stride < max_length
      假设数据集为”白日依山尽黄河入海流欲穷千里目“,strip 为 5,max_length 为 10,
      那么 first batch 白日依山尽黄河入海流
      second batch 黄河入海流欲穷千里目
      这样就有重叠了。
      有重叠可能产生过度拟合(看训练样本数量和质量)。
      简单来说 stride 就是控制样本的长度,在原始样本中依据 stride 切割
      为什么需要重叠?
      语言具有连贯性,如果不重叠,模型就学不到词之间的联系,保证不会遗留文本边界处的逻辑连接。
      stride > max_length 没意义
  • batch_size 批次大小/并行打包数
    • 语言模型通过 GPU or CPU训练,这里决定一次给多少。
 
图 2-6-1
图 2-6-1
图 2-6-1 通过滑动窗口来从输入数据集中生成多个批次的数据。如果步幅设置为 1,那么在创建下一个批次时没输入窗口向前移动一位,如果步幅与输入窗口大小相等,则可以避免批次之间的重叠。

2.7 创建词嵌入

准备输入文本以进行 LLM 训练的最后一步是将词 ID 转换为嵌入向量。
notion image
 
question1: 由于GPT类的LLM是通过反向传播算法训练的深度神经网络,因此需要连续的向 量表示或嵌入。 why?
question2: onehot 编码
😅
Q:为什么torch 知道知道词元 id就能输出该词元对应的矩阵,是 torch 已经训练好了,知道这些权重了吗
A: 示例中没有训练 ,输出的矩阵是一个随机的。但是使用了随机种子保证每次输出的一致的。实际应用一般不固定随机种子。
使用固定种子可以保证初始权重是一致的。
 

2.8 词元位置

notion image
图 2.8-2
图 2.8-2
😅
图 2.8-2
嵌入层将词 ID 转换为相同的向量表示,而不考虑它在输入序列中的位置。例如图中 id 为 5在输入向量的第一个位置还是第四个位置,都会产生相同的嵌入向量。
😅
原则上,这种确定性的、与位置无关的词 ID 嵌入对于可重复性是有好处的,然而,由于 LLM 的自注意力机制本身也是位置无关的,因此将额外的位置信息注入 LLM 是有帮助的,因此将额外的位置信息注入 LLM是有帮助的
question:
找到的资料说明是:
位置在语义中很重要,例如“人咬狗” ,“狗咬人” ,词的位置不同,意思不同。
在自注意公式中没有位置信息,上面这 2 个词,计算出来的匹配分值是一样的。
 
 

绝对位置、相对位置

绝对位置嵌入直接与序列中的特定位置相关联。对于输入序列中的每个位置都添加一个唯一的嵌入以传达其确切位置。
相对位置:重点在于此之间的相对位置或距离。
 
图 2.8-3
图 2.8-3
😅
图 2.8-3
输入文本首先被分解成单个词。然后使用词汇表转换为词 ID。词 ID 被转换为嵌入向量并添加类似大小的位置嵌入,最终形成用于主要 LLM 层的输入嵌入。
 
😅
为什么需要嵌入层
嵌入层的作用,就是把这些一维的类别编号 (Discrete ID) 映射成一个连续的浮点数稠密向量 (Continuous Vector)
在高维空间里捕捉“词与词的血缘关系”
单独的 ID 无法表达词义的关联性。比如“猫 (cat: 3760)”和“狗 (dog: 3290)”是相近的动物,但从数字编号上看毫无关联。
嵌入层就像是一个在 256 维空间里的“宇宙坐标系”。
  • 在刚开始(未训练时),所有词语被随机扔进这个坐标系的各个角落。
  • 随着模型的训练,模型会发现“猫”和“狗”老是出现在相似的语境下,于是它会不断微调这个嵌入层里的参数。
  • 最终,“猫”和“狗”在这个 256 维的向量空间里会靠得非常近;而它们又会和“苹果”、“桌子”离得非常远。 也就是说:嵌入层让原本死板的编号,拥有了极其丰富的语义灵魂。 这是机器能够“理解”人类词汇的基础。

总结

LLM 需要将文本数据转换成为数值向量,嵌入(Embeddings)。因为无法处理文本数据。
嵌入是将数据转换成连续的向量空间。
第一步 原始文本被分解为标记(tokens),这些标记可以是单词或字符,然后将标记转换为整数表示(token IDs)。
特殊标记 如<|unk|> 增强模型理解并处理各种上下文。如未知单词或标记不相关文本之间的边界。
滑动窗口方法来生成 输入和目标对,用于 LLM 训练。
Py-Torch 中的嵌入层充当查找操作,检索与标记 ID 对应的向量。由此产生的嵌入向量提供了标记的连续表示。
嵌入嵌入为每个标记提供了一致的向量表示,由于它们缺乏对序列中位置的感觉。解决方案:绝对位置和相对位置嵌入。
 
Loading...