大模型入门 ch02:数据集准备

news2024/9/22 23:35:45

本文是github上的大模型教程LLMs-from-scratch的学习笔记,教程地址:教程链接

Chapter 2: Working with Text

这一章节包括了数据的准备和采样阶段。

1. Tokenizer

大模型通过将token转变为embedding(词嵌入)运作。

首先通过tkenizer,将输入拆分成一个一个的单元。

我们可以自己写一个简单的tokenizer,例如通过空格划分

import re

text = "Hello, world. This, is a test."
result = re.split(r'(\s)', text)

print(result)

>>>
['Hello,', ' ', 'world.', ' ', 'This,', ' ', 'is', ' ', 'a', ' ', 'test.']

如果再包括上标点符号,那么最终我们自制的tokenizer如下:

preprocessed = re.split(r'([,.:;?_!"()\']|--|\s)', raw_text)

2. Token IDs

有了Tokenizer后,我们需要一个词汇表(vocabulary),为每一个token分配一个索引,方便之后进行矩阵运算。

在这里,我们使用简单的字典序,将在训练集中出现的每一个token分配一个token ID。在使用大量数据训练得到了较为完备的词汇表后,对于之后的输入,我们只需要查表,得到对应的下标即可。

于是我们就可以写出一个简单的Tokenizer,包括了encode和decode

class SimpleTokenizerV1:
    def __init__(self, vocab):
        self.str_to_int = vocab
        self.int_to_str = {i:s for s,i in vocab.items()}
    
    def encode(self, text):
        preprocessed = re.split(r'([,.:;?_!"()\']|--|\s)', text)
                                
        preprocessed = [
            item.strip() for item in preprocessed if item.strip()
        ]
        ids = [self.str_to_int[s] for s in preprocessed]
        return ids
        
    def decode(self, ids):
        text = " ".join([self.int_to_str[i] for i in ids])
        # Replace spaces before the specified punctuations
        text = re.sub(r'\s+([,.?!"()\'])', r'\1', text)
        return text

encode负责把文本转换成token IDs
decode负责把token IDs转换成文本

我们首先使用tokenizer,将文本转换成token IDs,然后使用token IDs提取出对应的embeddings输入模型。

3. 特殊符号

加入一些特殊的token是很有必要的,他可以标记文本的结束,也可以标记没有见过的tgoken等。

下面举几个简单的例子:

  • [BOS] (beginning of sequence)表示文本的开头
  • [EOS] (end of sequence) 表示文本的结束
  • [PAD] (padding) 如果LLM的batch_size大于1,那么使用PAD标记来讲每一段文本扩充到相同的长度。
  • [UNK] 表示没在词汇表里的token

GPT 没有使用 [UNK],因为GPT使用的BPE分词器包含了很小的单元,不会有UNK的情况存在。

于是我们在我们的tokenizer代码上进行修改,当识别到没有见过的token时,转换为UNK。

class SimpleTokenizerV2:
    def __init__(self, vocab):
        self.str_to_int = vocab
        self.int_to_str = { i:s for s,i in vocab.items()}
    
    def encode(self, text):
        preprocessed = re.split(r'([,.:;?_!"()\']|--|\s)', text)
        preprocessed = [item.strip() for item in preprocessed if item.strip()]
        preprocessed = [
            item if item in self.str_to_int 
            else "<|unk|>" for item in preprocessed
        ]

        ids = [self.str_to_int[s] for s in preprocessed]
        return ids
        
    def decode(self, ids):
        text = " ".join([self.int_to_str[i] for i in ids])
        # Replace spaces before the specified punctuations
        text = re.sub(r'\s+([,.:;?!"()\'])', r'\1', text)
        return text

encode包含了两个功能:一是将文本拆分成token,二是用token去词汇表中找到token对应的索引,第一步不会出错,第二步有可能找不到。

4. BytePair encoding(BPE)

GPT使用的是BPE分词器,它允许模型将不在预定义词汇表中的单词分解为更小的子单词单元甚至单个字符,使其能够处理未登录词汇表的单词。例如,如果GPT-2的词汇表中没有单词“unfamiliarword”,它可能会将其标记为[“unfaml”,“iliar”,“word”]或其他子单词分解。

我们下载tiktoken来使用GPT开源的分词器 pip install tiktoken

tokenizer = tiktoken.get_encoding("gpt2")

text = (
    "Hello, do you like tea? <|endoftext|> In the sunlit terraces"
     "of someunknownPlace."
)

integers = tokenizer.encode(text, allowed_special={"<|endoftext|>"})

print(integers)

BPE tokenizer将没见过的单词拆分成子单词或者单个字符,从而解决UNK的问题

5 滑动窗口数据采样

我们训练llm每次生成一个单词,因此我们希望相应地准备训练数据,其中序列中的下一个单词表示要预测的目标:

使用滑动窗口的方式来组织数据,每一段数据的长度都是上下文长度context_length,其中target是input向右偏移一位得到的。输入是input[:i+1]的话,预测值就是target[i]

于是我们构建一个数据集:

from torch.utils.data import Dataset, DataLoader


class GPTDatasetV1(Dataset):
    def __init__(self, txt, tokenizer, max_length, stride):
        self.input_ids = []
        self.target_ids = []

        # Tokenize the entire text
        token_ids = tokenizer.encode(txt, allowed_special={"<|endoftext|>"})

        # Use a sliding window to chunk the book into overlapping sequences of max_length
        for i in range(0, len(token_ids) - max_length, stride):
            input_chunk = token_ids[i:i + max_length]
            target_chunk = token_ids[i + 1: i + max_length + 1]
            self.input_ids.append(torch.tensor(input_chunk))
            self.target_ids.append(torch.tensor(target_chunk))

    def __len__(self):
        return len(self.input_ids)

    def __getitem__(self, idx):
        return self.input_ids[idx], self.target_ids[idx]

max_length是上下文长度,stride是滑动窗口的步长,如果max_length==stride,那么滑动窗口之间就没有重叠的文本,如果max_length > stride,那么就存在重叠的文本部分。一篇文章会被拆分为多个max_length那么长的输入,stride决定了这些输入之间是否会有重叠,这些输入片段的预测标签就是其右移1位的片段。

一个没有重叠的输入是这样的:
在这里插入图片描述

6 创建token embeddings

现在我们组织完成了输入的数据集,但是我们的输入仍然是token IDs,现在我们需要把这些token IDs转换成embeddings(嵌入),转换为高维的向量表示,并且这些embedding在大模型中也是可训练的参数。

方法很简单,我们有token IDs后,我们就可以创建一个词嵌入矩阵,维度为词汇表大小 * 嵌入维度
之后我们只需要使用token IDs,就可以从这个词嵌入矩阵中取出对应行内保存的向量。本质上还是独热编码,假设我们有一个6*3的矩阵,我们使用[0,0,0,1,0,0]的矩阵去左乘词嵌入矩阵,就可以取出第4行的内容,OK。

在Python中很容易实现

embedding_layer = torch.nn.Embedding(vocab_size, output_dim)

tensor([[ 0.3374, -0.1778, -0.1690],
        [ 0.9178,  1.5810,  1.3010],
        [ 1.2753, -0.2010, -0.1606],
        [-0.4015,  0.9666, -1.1481],
        [-1.1589,  0.3255, -0.6315],
        [-2.8400, -0.7849, -1.4096]], requires_grad=True)
        
print(embedding_layer(torch.tensor([3])))
tensor([[-0.4015,  0.9666, -1.1481]], grad_fn=<EmbeddingBackward0>)

torch.nn.Embedding自动帮我们将3转换为了独热编码,取出了下标为3的向量。

7 加入位置编码

将token转换为词嵌入后,仍然存在一个问题,一个输入中如果有两个相同的token,那么他们的嵌入一致,但是他们的位置并不同,我们还需要加入位置信息。
位置编码和token编码结合作为输入,喂给大模型。

GPT-2使用绝对位置编码,所以我们创建另一个embedding层:

context_length = max_length
pos_embedding_layer = torch.nn.Embedding(context_length, output_dim)

pos_embeddings = pos_embedding_layer(torch.arange(max_length))

最后,我们将token embedding简单加上位置embedding后,就得到了LLM的输出

input_embeddings = token_embeddings + pos_embeddings

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2117396.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【机器学习】高斯网络的基本概念和应用领域以及在python中的实例

引言 高斯网络&#xff08;Gaussian Network&#xff09;通常指的是一个概率图模型&#xff0c;其中所有的随机变量&#xff08;或节点&#xff09;都遵循高斯分布 文章目录 引言一、高斯网络&#xff08;Gaussian Network&#xff09;1.1 高斯过程&#xff08;Gaussian Proces…

Android14音频进阶之高通Elite架构指定通道播放(八十四)

简介: CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布:《Android系统多媒体进阶实战》🚀 优质专栏: Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏: 多媒体系统工程师系列【原创干货持续更新中……】🚀 优质视频课程:AAOS车载系统+…

【Linux】多线程:线程概念,线程与进程的区别与联系,多线程相较于多进程的优势

目录 一、进程基本属性回顾 二、线程概念 三、操作系统为什么要引入线程—多进程和多线程的区别 为什么多线程比多线程调度效率更快&#xff1f; 四、线程的优点 五、线程的缺点 六、线程异常 一、进程基本属性回顾 在学习线程之前&#xff0c;我们先来回顾一下进程的基…

6. LinkedList与链表

一、ArrayList的缺陷 通过源码知道&#xff0c;ArrayList底层使用数组来存储元素&#xff0c;由于其底层是一段连续空间&#xff0c;当在ArrayList任意位置插入或者删除元素时&#xff0c;就需要将后序元素整体往前或者往后搬移&#xff0c;时间复杂度为O(n)&#xff0c;效率比…

64、Python之函数高级:装饰器实战,动态语言也能有类型检查

引言 Python作为一门动态类型语言&#xff0c;有时候&#xff0c;一个不小心的类型错误只有在实际运行中才有可能被发现。相较而言&#xff0c;静态类型语音虽然不够灵活&#xff0c;但是&#xff0c;类型错误等语法检查在编译期间就可以提前发现了。 那么我们有没有方法在Py…

Visual Studio Code 月刊 (2024-08)

文章目录 配置文件编辑器Django 单元测试支持vscode.dev 上的 IntelliSenseNotebook 差异查看器通过键盘调整列的大小源代码管理图GitHub Copilot结语 2024 年 8 月 Visual Studio Code&#xff08;简称 vscode&#xff09;发布了 version 1.93。该版本带来了许多更新&#xff…

Spring Boot Admin集成与自定义监控告警

目录 一.Spring Boot Admin集成 1.引入依赖 2.添加配置 3.监控界面 二.Spring Boot Admin告警机制 1. 基本告警机制 2. 配置告警 2.1 triggers触发器讲解 3. 自定义通知 3.1 Instance 对象 三.Spring Boot Admin支持的监控属性 1.常见的Spring Boot Admin监控属性 …

进阶SpringBoot之配置 Swagger API 框架信息

Swagger&#xff1a;API 框架 RestFul API 文档在线自动生成工具&#xff0c;API 文档与 API 定义同步更新 Swagger 官网 Maven 仓库 创建 Spring Boot 项目&#xff0c;依赖勾选 Spring Web pom.xml 导入相关依赖&#xff1a; springfox-swagger2、springfox-swagger-ui …

何为数据中台

数据中台 什么是数据中台 2014年马云正式提出“DT&#xff08;Data Technology&#xff09;”的概念&#xff0c;人类从IT时代走向了DT时代&#xff0c;阿里内部的数据平台事业部大刀阔斧的建立整个集团的数据资产&#xff0c;同年&#xff0c;阿里从芬兰Supercell公司接触到…

Canny算子 一张图看懂

对于最高值和最低值的设置&#xff0c; 1&#xff0c;high t最大值一般以一阶导数幅度图的最大值的30%-40%来定 2&#xff0c;最小值一般halcon里默认为 low theigh t/3得到 3&#xff0c;canny的优势是有极大值抑制&#xff0c;所以提取的边缘是1个像素的窄边缘。 3&#xff0…

Golang path/filepath包详解:高效路径操作与实战案例

Golang path/filepath包详解&#xff1a;高效路径操作与实战案例 引言基础用法Abs 函数Base 函数Clean 函数Dir 函数Ext 函数FromSlash 和 ToSlash 函数 基础用法Abs 函数Base 函数Clean 函数Dir 函数Ext 函数FromSlash 和 ToSlash 函数 路径操作Join 函数Split 函数Rel 函数Ma…

LabVIEW编程语言出于什么原因开发的?

LabVIEW最初由美国国家仪器公司&#xff08;NI&#xff09;于1986年开发&#xff0c;目的是为工程师和科学家提供一种图形化编程环境&#xff0c;简化数据采集、仪器控制、自动化测试和测量系统开发等工作。开发LabVIEW的主要原因包括以下几点&#xff1a; 简化复杂系统开发&am…

《数字图像处理(面向新工科的电工电子信息基础课程系列教材)》Chapter 1课件2024

每一轮备课都有新的感悟。 禹晶、肖创柏、廖庆敏《数字图像处理&#xff08;面向新工科的电工电子信息基础课程系列教材&#xff09;》 禹晶、肖创柏、廖庆敏《数字图像处理》资源二维码

Tektronix泰克MSO5204B混合信号示波器4+16通道2G

Tektronix泰克MSO5204B混合信号示波器416通道2G 2 GHz、416 通道、10/5 GS/s&#xff08;2/4 通道&#xff09;混合信号示波器&#xff0c;50 M/25 M 记录长度泰克 MSO5204B 2 GHz、416 通道、10/5 GS/s&#xff08;2/4 通道&#xff09;混合信号示波器&#xff0c;50 M/25 M …

机器学习强化学习

版权声明 本文原创作者:谷哥的小弟作者博客地址:http://blog.csdn.net/lfdfhl1. 强化学习概述 1.1 定义与核心概念 强化学习是一种目标导向的机器学习方法,它使智能体能够在环境中通过试错学习最优行为策略。这种学习过程涉及到智能体与环境之间的交互,智能体根据当前状态…

AI基础 L8 Local Search I 局部搜索

Iterative Improvement Algorithms • In many optimization problems, the path to a goal is irrelevant — the goal state itself is the solution • State space a set of goal states — find one that satisfies constraints (e.g., no two classes at same time) —…

《系统安全架构设计及其应用》写作框架,软考高级系统架构设计师

论文真题 随着社会信息化进程的加快&#xff0c;计算机及网络已经被各行各业广泛应用&#xff0c;信息安全问题也变得愈来愈重要。它具有机密性、完整性、可用性、可控性和不可抵赖性等特征。信息系统的安全保障是以风险和策略为基础&#xff0c;在信息系统的整个生命周期中提…

【审批流】基于JAVA开发的工作流审批系统(直接集成或者直接可使用)

基于Javavue开发的智能审批系统&#xff0c;低代码平台 软件资料清单列表部分文档清单&#xff1a;工作安排任务书&#xff0c;可行性分析报告&#xff0c;立项申请审批表&#xff0c;产品需求规格说明书&#xff0c;需求调研计划&#xff0c;用户需求调查单&#xff0c;用户需…

Android APK插件化:DynamicAPK技术如何改变游戏规则

在移动应用开发领域&#xff0c;尤其是Android平台&#xff0c;应用的体积和更新速度一直是开发者和用户关注的焦点。随着应用功能的不断增加&#xff0c;APK文件的大小也在逐渐膨胀&#xff0c;这不仅增加了用户的下载成本&#xff0c;也影响了应用的更新效率。DynamicAPK技术…

数学建模笔记——层次分析法

数学建模笔记——层次分析法 数学建模笔记——层次分析法1. 层次分析法的基本原理和步骤2. 层次分析法的建模过程2.1 问题的提出2.2 模型原理2.3 为该问题建立层次结构模型2.4 构造判断矩阵1. 判断矩阵的含义2. 为该问题构造判断矩阵 2.5 一致性检验1. 一致性检验方法2. 对上述…