前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >Learning "Build a Large Language Model (From Scratch)"

Learning "Build a Large Language Model (From Scratch)"

作者头像
alanzeng
发布2025-01-14 21:45:28
发布2025-01-14 21:45:28
17600
代码可运行
举报
文章被收录于专栏:alanzeng423
运行总次数:0
代码可运行

学习《Build a Large Language Model (From Scratch)》一书

《Build a Large Language Model (From Scratch)》


Setup

参考

  • setup/01_optional-python-setup-preferences
  • .setup/02_installing-python-libraries

按照步骤配置环境:

代码语言:javascript
代码运行次数:0
复制
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

在这里遇到了以下问题:

image-20240929162323569
image-20240929162323569

解决方案:

代码语言:javascript
代码运行次数:0
复制
hash -r
image-20240929162500733
image-20240929162500733

解释:

  • hash 是一个 Bash 内建命令,用于查找并记住命令的位置。如果你在安装了新的软件之后,想要立即使用它,但是 Bash 仍然使用旧的命令,那么你可以使用 hash -r 命令来刷新 Bash 的命令缓存。

Chapter 01

Chapter 02

目录:

  • 2.1 Understanding word embeddings
  • 2.2 Tokenizing text
  • 2.3 Converting tokens into token IDs
  • 2.4 Adding special context tokens
  • 2.5 Byte pair encoding
  • 2.6 Data sampling with a sliding window
  • 2.7 Creating token embeddings
  • 2.8 Encoding word positions
  • 2.9 Summary

背景知识

  1. 什么是Token?
  2. Token是指文本的最小单位,可以是一个字、一个单词或一个子词。
    • 例如,句子 “I love NLP” 可以被分解为 “I”, “love”, “NLP”。
  3. 什么是Token ID?
    • 每个Token会被映射到一个唯一的数字ID。
    • 假设我们有一个词汇表:“I”, “love”, “NLP”, “AI”,其中:
    • “I” 的ID是0
    • “love” 的ID是1
    • “NLP” 的ID是2
    • “AI” 的ID是3
  4. 为什么需要嵌入(Embedding)?
    • 模型无法直接处理文字或数字ID,我们需要将这些ID转为具有实际意义的向量(连续值表示)。
    • 比如,“NLP”的ID是2,我们可能需要一个三维向量 1.2, -0.4, 0.6 来表示它。

2.6 数据采样与滑动窗口

代码语言:javascript
代码运行次数:0
复制
dataloader = create_dataloader_v1(raw_text, batch_size=8, max_length=4, stride=4)

其中参数:

  • raw_text 是原始文本。
  • batch_size 是批量大小。
  • max_length 是滑动窗口的大小。
  • stride 是滑动窗口的步长。

2.7 Token Embedding 创建

步骤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维向量

代码语言:javascript
代码运行次数:0
复制
- input_ids 是一个张量,表示我们的输入文本。
- vocab_size 是词汇表的大小,也就是可能的Token ID的总数。
- output_dim 是嵌入向量的维度。

步骤2:创建嵌入层

torch.manual_seed(123) # 设置随机种子,结果可复现

embedding_layer = torch.nn.Embedding(vocab_size, output_dim) # 创建嵌入层

代码语言:javascript
代码运行次数:0
复制
- torch.nn.Embedding 是PyTorch提供的嵌入层,用于将Token ID映射为向量。
- 嵌入层的权重矩阵是随机初始化的。

权重矩阵的形状为 (vocab_size, output_dim)。

假设随机初始化后为:

tensor([ 0.1, -0.2, 0.3,

代码语言:txt
复制
    [ 0.4,  0.5, -0.6],
代码语言:txt
复制
    [ 0.7, -0.8,  0.9],
代码语言:txt
复制
    [ 1.0, -1.1,  1.2],
代码语言:txt
复制
    [-1.3,  1.4, -1.5],
代码语言:txt
复制
    [ 1.6, -1.7,  1.8]])
代码语言:javascript
代码运行次数:0
复制
- 每一行是一个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])

解释:

代码语言:javascript
代码运行次数:0
复制
- 这段代码从嵌入层中查找Token ID为2的向量,也就是矩阵中的第3行(索引从0开始)。

扩展到批量处理:

print(embedding_layer(input_ids))

输出:

tensor([ 0.7, -0.8, 0.9, # ID 2

代码语言:txt
复制
    [ 1.0, -1.1,  1.2],  # ID 3
代码语言:txt
复制
    [ 1.6, -1.7,  1.8],  # ID 5
代码语言:txt
复制
    [ 0.4,  0.5, -0.6]]) # ID 1

2.8 位置编码(Positional Encoding)

问题:为什么需要位置编码?

嵌入层只能将Token ID映射为向量,但无法表示Token的位置。

例如:

代码语言:javascript
代码运行次数:0
复制
- 对于句子 “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) # 位置嵌入层

假设位置嵌入层初始化后的权重矩阵是:

代码语言:javascript
代码运行次数:0
复制
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:查找位置嵌入

代码语言:javascript
代码运行次数:0
复制
position_ids = torch.arange(context_length)  # 生成位置ID [0, 1, 2, 3]
pos_embeddings = pos_embedding_layer(position_ids)  # 查询位置向量
print(pos_embeddings)

输出:

代码语言:javascript
代码运行次数:0
复制
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嵌入为

代码语言:javascript
代码运行次数:0
复制
token_embeddings = embedding_layer(input_ids)

将Token嵌入与位置嵌入相加

代码语言:javascript
代码运行次数:0
复制
input_embeddings = token_embeddings + pos_embeddings
print(input_embeddings)

输出:

代码语言:javascript
代码运行次数:0
复制
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

解释:

  • 每个Token的向量中都加入了对应位置的位置信息。
  • 新生成的向量将用于模型的下一步处理。

总结

  1. 嵌入层:
    • 将Token ID映射为连续向量表示。
    • 初始向量随机生成,随着训练不断优化。
  2. 位置嵌入:
    • 给每个Token附加位置信息,帮助模型理解顺序。
  3. 最终输入:
    • Token嵌入和位置嵌入相加,生成模型的输入。

Chapter 03

文章作者: Alan Zeng

原始链接: https://alanzeng.com/blogs/13378/

版权说明:本博客所有文章除特别声明外,均采用BY-NC-SA 4.0许可协议。获得许可后,要求转载时注明文章出处和网站链接,谢谢!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-09-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Setup
  • Chapter 01
  • Chapter 02
    • 背景知识
    • 2.6 数据采样与滑动窗口
    • 2.7 Token Embedding 创建
      • 假设之前的Token嵌入为
      • 将Token嵌入与位置嵌入相加
  • Chapter 03
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档