学习《Build a Large Language Model (From Scratch)》一书
《Build a Large Language Model (From Scratch)》
参考
setup/01_optional-python-setup-preferences
.setup/02_installing-python-libraries
按照步骤配置环境:
git clone --depth 1 https://github.com/rasbt/LLMs-from-scratch.git
cd LLMs-from-scratch
conda create -n LLMs python=3.10
conda activate LLMs
conda install jupyterlab watermark
pip install -r requirements.txt
在这里遇到了以下问题:
解决方案:
hash -r
解释:
hash
是一个 Bash 内建命令,用于查找并记住命令的位置。如果你在安装了新的软件之后,想要立即使用它,但是 Bash 仍然使用旧的命令,那么你可以使用 hash -r
命令来刷新 Bash 的命令缓存。目录:
dataloader = create_dataloader_v1(raw_text, batch_size=8, max_length=4, stride=4)
其中参数:
raw_text
是原始文本。batch_size
是批量大小。max_length
是滑动窗口的大小。stride
是滑动窗口的步长。步骤1:定义Token ID和词汇表
假设我们有4个Token,其ID是 2, 3, 5, 1,词汇表的大小为6。
import torch
input_ids = torch.tensor(2, 3, 5, 1) # Token的ID
vocab_size = 6 # 假设词汇表有6个单词
output_dim = 3 # 我们希望嵌入是3维向量
- input_ids 是一个张量,表示我们的输入文本。
- vocab_size 是词汇表的大小,也就是可能的Token ID的总数。
- output_dim 是嵌入向量的维度。
步骤2:创建嵌入层
torch.manual_seed(123) # 设置随机种子,结果可复现
embedding_layer = torch.nn.Embedding(vocab_size, output_dim) # 创建嵌入层
- torch.nn.Embedding 是PyTorch提供的嵌入层,用于将Token ID映射为向量。
- 嵌入层的权重矩阵是随机初始化的。
权重矩阵的形状为 (vocab_size, output_dim)。
假设随机初始化后为:
tensor([ 0.1, -0.2, 0.3,
[ 0.4, 0.5, -0.6],
[ 0.7, -0.8, 0.9],
[ 1.0, -1.1, 1.2],
[-1.3, 1.4, -1.5],
[ 1.6, -1.7, 1.8]])
- 每一行是一个Token ID对应的嵌入向量。
- 比如,Token ID为2的嵌入向量是 [0.7, -0.8, 0.9]。
步骤3:查询嵌入向量
embedding_vector = embedding_layer(torch.tensor(2))
print(embedding_vector)
输出:
tensor([0.7, -0.8, 0.9])
解释:
- 这段代码从嵌入层中查找Token ID为2的向量,也就是矩阵中的第3行(索引从0开始)。
扩展到批量处理:
print(embedding_layer(input_ids))
输出:
tensor([ 0.7, -0.8, 0.9, # ID 2
[ 1.0, -1.1, 1.2], # ID 3
[ 1.6, -1.7, 1.8], # ID 5
[ 0.4, 0.5, -0.6]]) # ID 1
2.8 位置编码(Positional Encoding)
问题:为什么需要位置编码?
嵌入层只能将Token ID映射为向量,但无法表示Token的位置。
例如:
- 对于句子 “I love NLP” 和 “NLP love I”,它们的Token是一模一样的,但顺序完全不同。
为了让模型区分位置,我们需要给每个Token加上位置信息。
步骤1:创建位置嵌入
context_length = 4 # 假设句子长度为4
output_dim = 3 # 嵌入维度与Token嵌入相同
pos_embedding_layer = torch.nn.Embedding(context_length, output_dim) # 位置嵌入层
假设位置嵌入层初始化后的权重矩阵是:
tensor([[ 0.1, 0.2, -0.3], # 位置0
[ 0.4, -0.5, 0.6], # 位置1
[-0.7, 0.8, -0.9], # 位置2
[ 1.0, -1.1, 1.2]]) # 位置3
步骤2:查找位置嵌入
position_ids = torch.arange(context_length) # 生成位置ID [0, 1, 2, 3]
pos_embeddings = pos_embedding_layer(position_ids) # 查询位置向量
print(pos_embeddings)
输出:
tensor([[ 0.1, 0.2, -0.3], # 位置0
[ 0.4, -0.5, 0.6], # 位置1
[-0.7, 0.8, -0.9], # 位置2
[ 1.0, -1.1, 1.2]]) # 位置3
步骤3:将Token嵌入和位置嵌入相加
token_embeddings = embedding_layer(input_ids)
input_embeddings = token_embeddings + pos_embeddings
print(input_embeddings)
输出:
tensor([[ 0.8, -0.6, 0.6], # Token ID 2 + 位置 0
[ 1.4, -1.6, 1.8], # Token ID 3 + 位置 1
[ 0.9, -0.9, 0.9], # Token ID 5 + 位置 2
[ 1.4, -0.6, 0.6]]) # Token ID 1 + 位置 3
解释:
总结
文章作者: Alan Zeng
原始链接: https://alanzeng.com/blogs/13378/
版权说明:本博客所有文章除特别声明外,均采用BY-NC-SA 4.0许可协议。获得许可后,要求转载时注明文章出处和网站链接,谢谢!