Merge pull request #22 from sunhanyu714/main

translate_chapter2.8_update
This commit is contained in:
Ethan-Chen-plus 2024-04-29 16:37:23 +08:00 committed by GitHub
commit cee96d8ea2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -0,0 +1,183 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 2.6 使用滑动窗口进行数据采样"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"在前面的章节中,我们将 token IDs 转换为连续的向量表示,也就是所谓的 token 编码,作为 LLM 的输入。然而LLM 的一个缺点是自注意力机制(将在第 3 章详细介绍),不包含序列中的 token 位置或顺序信息。\n",
"\n",
"先前介绍的 embedding 层的生成方式中,相同的 token ID 总是被映射成相同的向量表示,不会在乎 token ID 在输入序列中的位置,如图 2.17 所示。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**图 2.17 编码层将 token ID 转换为相同的向量表示不管其在输入序列中的位置如何。例如token ID 5 ,无论是在 token ID 输入向量的第一还是第三个位置,都将产生相同的编码向量。**\n",
"\n",
"![](../img/fig-2-17.jpg)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"在原则上具有确定性的、与位置无关的编码对于可重现性是有益的。然而由于LLM的自注意力机制本身也不关注位置因此将额外的位置信息注入到LLM中是有帮助的。\n",
"\n",
"为了实现这一点,有两种常用的位置编码方式:相对位置编码和绝对位置编码。\n",
"\n",
"绝对位置编码与序列中的特定位置相关联。对于输入序列中的每个位置,都会添加一个唯一的位置编码到 token 中,来表示其确切位置。例如,第一个 token 将具有特定的位置编码,第二个 token 将具有另一个不同的位置编码依此类推如图2.18所示。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**图2.18 位置编码被添加到 token 中,以创建 LLM 的输入。位置向量具有与原始 token 相同的维度。出于简化考虑token 编码显示为值为1。**\n",
"\n",
"![](../img/fig-2-18.jpg)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"相对位置编码不是专注于 token 的绝对位置,而是侧重于 token 之间的相对位置或距离。这意味着模型学习的是 “彼此之间有多远” 而不是 “在哪个确切位置”的关系。这样做的好处是,即使模型在训练过程中没有看到这样的长度,它也可以更好地推广到不同长度的序列。\n",
"\n",
"两种类型的位置编码旨在增强 LLM 理解 token 顺序和关系的能力,确保更准确和更具上下文意识的预测。它们的选择通常取决于具体的应用程序和正在处理的数据的性质。\n",
"\n",
"OpenAI 的 GPT 模型使用绝对位置编码,在训练过程中进行了优化,而不是像原始 Transformer 模型中的位置编码那样固定或预定义。这个优化过程是模型训练本身的一部分,我们将在本书的后面部分实现。现在,让我们创建初始的位置编码,为即将到来的章节创建 LLM 输入。\n",
"\n",
"在本章中,我们之前专注于非常小的编码大小,以说明为目的。现在,我们考虑更现实和有用的编码大小,并将输入 token 编码为 256 维向量表示。这比原始的GPT-3 模型使用的要小(在 GPT-3 中,编码大小为 12,288 维),但对于实验来说仍然是合理的。此外,我们假设 token ID 是由我们之前实现的 BPE 标记器创建的,其词汇量大小为 50,257\n",
"> output_dim = 256\n",
"\n",
"> vocab_size = 50257\n",
"\n",
"> token_embedding_layer = torch.nn.Embedding(vocab_size, output_dim)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"使用上面的 token_embedding_layer ,如果我们从 dataloader 中采样数据,我们将每个批次中的每个 token 编码成一个256维的向量中。如果我们的批次大小为8每个批次有四个 token 则结果将是一个8 x 4 x 256的张量。\n",
"\n",
"首先让我们实例化第2.6节 “使用滑动窗口进行数据采样” 的 dataloader\n",
">max_length = 4\n",
"\n",
">dataloader = create_dataloader_v1(\n",
"> raw_text, batch_size=8, max_length=max_length, stride=max_len)\n",
"\n",
">data_iter = iter(dataloader)\n",
"\n",
">inputs, targets = next(data_iter)\n",
"\n",
">print(\"Token IDs:\\n\", inputs)\n",
"\n",
">print(\"\\nInputs shape:\\n\", inputs.shape)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"前面的代码打印如下输出:\n",
">Token IDs:\n",
"\n",
">tensor([[ 40, 367, 2885, 1464],\\\n",
" [ 1807, 3619, 402, 271],\\\n",
" [10899, 2138, 257, 7026],\\\n",
" [15632, 438, 2016, 257],\\\n",
" [ 922, 5891, 1576, 438],\\\n",
" [ 568, 340, 373, 645],\\\n",
" [ 1049, 5975, 284, 502],\\\n",
" [ 284, 3285, 326, 11]])\n",
" \n",
">Inputs shape:\n",
" >torch.Size([8, 4])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"正如我们所看到的token ID 张量是 8x4 维的,这意味着数据批次由 8 个文本样本组成,每个样本有 4 个 token。\n",
"\n",
"现在让我们使用 token_embedding_layer 将这些 token ID 嵌入为 256 维的向量:\n",
"> token_embeddings = token_embedding_layer(inputs)\n",
"> \n",
"> print(token_embeddings.shape)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"前面的代码打印如下输出:\n",
"\n",
">torch.Size([8, 4, 256])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"根据 8x4x256 维的张量输出,我们可以看出每个 token ID 现在被嵌入为一个 256 维的向量。\n",
"对于 GPT 模型的绝对嵌入方法,我们只需要创建另一个具有与 token_embedding_layer 相同维度的嵌入层:\n",
"\n",
">context_length = max_length\n",
"\n",
">pos_embedding_layer = torch.nn.Embedding(context_lengthe, output_dim)\n",
"\n",
">pos_embeddings = pos_embedding_layer(torch.arange(context_length))\n",
"\n",
">print(pos_embeddings.shape)\n",
"\n",
"如前面的代码示例所示pos_embeddings 的输入通常是一个占位符向量 torch.arange(context_length),其中包含一系列数字 0、1、...,一直到最大输入长度减 1。context_length 是一个变量,表示 LLM 支持的输入大小。在这里,我们选择它与输入文本的最大长度类似。在实践中,输入文本可以比支持的上下文长度长。这种情况下,我们必须截断文本。\n",
"\n",
"print 语句的输出如下:\n",
"\n",
">torch.Size([4, 256])\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"正如我们所见,位置嵌入张量由四个 256 维向量组成。我们现在可以直接将它们添加到标记嵌入中PyTorch 将在每个 8 批次中的每个 4x256 维标记嵌入张量中添加 4x256 维的 pos_embeddings 张量:\n",
">input_embeddings = token_embeddings + pos_embeddings\n",
"\n",
">print(input_embeddings.shape)\n",
"\n",
"print 输出如下:\n",
"\n",
">torch.Size([8, 4, 256])\n",
"\n",
"我们创建的 input_embeddings如图 2.19 所总结的,是嵌入的输入示例,现在可以由我们将在第 3 章开始实现的主要 LLM 模块进行处理。\n",
"\n",
"![](../img/fig-2-19.jpg)\n",
"**图 2.19 作为输入处理流程的一部分,输入文本首先被分解为单个 token 。然后使用词汇表将这些标记转换为 token ID。将 token ID 转换为编码向量,然后添加相似大小的位置编码,生成用作主要 LLM 层的输入编码。**\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": []
}
],
"metadata": {
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 2
}