【教程】从0开始搭建大语言模型:文本预处理

news2024/11/26 1:56:56

从0开始搭建大语言模型:文本预处理

参考仓库:LLMs-from-scratch

理解Word embedding

深度神经网络模型,包括LLM,不能直接处理原始文本,因此需要一种方法将它转换为连续值的向量,也就是embedding。如下图所示,可以使用各种embedding模型将不同的数据转换为embedding,从而供神经网络处理:
在这里插入图片描述
embedding的主要目的是将非数值数据转换为神经网络可以处理的格式

常用的文本embedding方法有Word2Vec,它通过预测给定目标单词的单词上下文来生成单词嵌入来训练神经网络架构。背后的主要思想是,出现在相似语义中的单词往往具有相似的含义

需要注意的是:LLM通常会生成自己的embedding,这些embedding是输入层的一部分,并在训练期间进行更新。将优化embedding作为LLM训练的一部分而不是使用Word2Vec的优点是,embedding是针对特定任务和手头数据进行优化的。

预处理文本数据

本部分介绍了如何将输入文本分割为单个token,这是为LLM创建embedding所需的预处理步骤。这些token可以是单个单词,也可以是特殊字符(包括标点符号)。LLM的一个通常流程为:
在这里插入图片描述
这里选择的文本是维基百科的一个短篇故事The_Verdict,你可以copy内容然后将它放在一个文本文件中。

预处理该文本的代码为:

首先是读取文件:

with open("./data/the_verdict.txt", "r", encoding="utf-8") as f:
    raw_text = f.read()
print("Total number of character:", len(raw_text))
print(raw_text[:99])
# 输出为:
# Total number of character: 20479
# I HAD always thought Jack Gisburn rather a cheap genius--though a good fellow enough--so it was no

然后使用正则表达式匹配单词,标点符号等内容:

preprocessed = re.split(r'([,.?_!"()\']|--|\s)', raw_text)
preprocessed = [item.strip() for item in preprocessed if item.strip()]
print(len(preprocessed))
print(preprocessed[:30])

其中正则表达式([,.?_!"()\']|--|\s)中:

  • 模式\s匹配任何空白字符(包括空格、制表符等)。
  • 括号 () 表示捕获组
  • [,.] 匹配逗号, 或句号;
  • |表示或者

最后的输出为:

4649
['I', 'HAD', 'always', 'thought', 'Jack', 'Gisburn', 'rather', 'a', 'cheap', 'genius', '--', 'though', 'a', 'good', 'fellow', 'enough', '--', 'so', 'it', 'was', 'no', 'great', 'surprise', 'to', 'me', 'to', 'hear', 'that', ',', 'in']

说明有4649个token。

将token变成对应的ID

在本部分中,我们将把这些token从Python字符串转换为整数表示,以生成所谓的token id。这种转换是将token id转换为embedding向量之前的中间步骤。

该部分主要是建立一个字典,含有字符到id的映射,能够将句子转换为一串id,如下图所示:
在这里插入图片描述
首先是构建字典,代码为:

# 去除重复的单词
all_words = sorted(list(set(preprocessed)))
vocab_size = len(all_words)
print(vocab_size)
# 构建字典,即每个单词对应的数字
vocab = {token:integer for integer,token in enumerate(all_words)}
for i, item in enumerate(vocab.items()):
    print(item)
    if i > 50:
        break

然后,我们构造一个Tokenizer,它的作用是实现token的编解码,即:将句子变成token id和将token id变成句子,编解码的过程为:
在这里插入图片描述

同时,我们需要考虑如果遇到文本里面没有的单词该怎么办。一些特殊上下文token的使用和添加可以增强模型对文本中的上下文或其他相关信息的理解。例如,这些特殊标记可以包括未出现的单词和文档边界的标记。下图展示了使用<|unk|>代替不在字典字的单词:
在这里插入图片描述
其中我们添加了一个<|unk|>标记来表示不属于训练数据的新单词和未知单词,因此也不属于现有词汇表。此外,我们添加了一个<|endoftext|>标记,我们可以使用它来分离两个不相关的文本源。

当在多个独立文档或书籍上训练类似gpt的LLM时,通常在前一个文本源之后的每个文档或书籍之前插入token,这有助于LLM理解,尽管这些文本源是连接起来进行训练的,但实际上它们是不相关的。如下图所示:
在这里插入图片描述
该部分的代码为:

all_tokens = sorted(list(set(preprocessed)))
all_tokens.extend(["<|endoftext|>", "<|unk|>"])
vocab = {token:integer for integer,token in enumerate(all_tokens)}
print(len(vocab.items()))
for i, item in enumerate(list(vocab.items())[-5:]):
    print(item)

输出为:

('younger', 1156)
('your', 1157)
('yourself', 1158)
('<|endoftext|>', 1159)

然后构造Tokenizer,为:

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()]
        # 对于不在str_to_int里面的标记为<|unk|>
        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])
        text = re.sub(r'\s+([,.?!"()\'])', r'\1', text) #B
        return text

调用该代码处理字典厘米没有出现过的单词:

text1 = "Hello, do you like tea?"
text2 = "In the sunlit terraces of the palace."
text = " <|endoftext|> ".join((text1, text2))
print(text)
tokenizer = SimpleTokenizerV2(vocab)
print(tokenizer.encode(text))
print(tokenizer.decode(tokenizer.encode(text)))

输出为:

Hello, do you like tea? <|endoftext|> In the sunlit terraces of the palace.
[1160, 5, 362, 1155, 642, 1000, 10, 1159, 57, 1013, 981, 1009, 738, 1013, 1160, 7]
<|unk|>, do you like tea? <|endoftext|> In the sunlit terraces of the <|unk|>.

可以看到,Hello被解码成了<|unk|>。

在LLM中,还有一些其他的特殊token:

  • [BOS](sequence的开始):标记文本的开始。它标志着LLM的内容从哪里开始。
  • [EOS](end of sequence):位于文本的末尾,在连接多个不相关的文本时特别有用,类似于<|endoftext|>。例如,当组合两篇不同的维基百科文章或书籍时,[EOS] token表示一篇文章的结束和下一篇文章的开始
  • [PAD](padding):当训练批量大小大于1的LLM时,批处理可能包含不同长度的文本。为了确保所有文本具有相同的长度,使用[PAD]标记对较短的文本进行扩展或“填充”,直至批处理中最长文本的长度。

Byte pair encoding(BPE)

本部分中介绍的BPE分词器(tokenizer)用于训练LLM,如GPT-2、GPT-3和ChatGPT中使用的原始模型。因为BPE的实现比较复杂,本部分使用tiktoken库,它含有BPE的实现,通过pip install tiktoken==0.5.1命令安装即可。

实例化一个BPE tokenizer进行句子的编解码,如下:

import 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)
strings = tokenizer.decode(integers)
print(strings)

输出为:

[15496, 11, 466, 345, 588, 8887, 30, 220, 50256, 554, 262, 4252, 18250, 8812, 2114, 286, 617, 34680, 27271, 13]
Hello, do you like tea? <|endoftext|> In the sunlit terraces of someunknownPlace.

从结果中可以看出:

  • <|endoftext|>token分配一个相对较大的token ID,即50256。这是因为用于训练GPT-2、GPT-3等模型以及ChatGPT中使用的原始模型的BPE分词器,总词汇量为50257,其中<|endoftext|>被分配了最大的token ID。
  • BPE分词器可以处理任何未知单词,如someunknownPlace。BPE底层的算法将不在其预定义词汇表中的单词分解为更小的子单词单元甚至单个字符,使其能够处理未在词汇表的单词。因此,如果分词器在分词过程中遇到不熟悉的单词,BPE算法可以将其表示为子单词标记或字符序列,如下所示:
    在这里插入图片描述
    BPE的思路:它通过迭代地将频繁字符合并为子词,将频繁子词合并为单词来构建词汇。例如,BPE从将所有单个字符添加到其词汇表(“a”,“b”,…)开始。在下一阶段,它将频繁出现在一起的字符组合合并为子词。例如,“d”和“e”可以合并成子词“de”,这在许多英语单词中很常见,如“define”、“depend”、“made”和“hidden”。合并由频率截止决定

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

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

相关文章

Sql注入-报错注入

报错注入&#xff08;Error-Based Injection&#xff09;是一种通过引起数据库报错并从错误信息中提取有用信息的SQL注入攻击手法&#xff1b;攻击者利用数据库在处理异常情况时返回的错误消息&#xff0c;来推断出数据库结构、字段名甚至数据内容&#xff1b;这种攻击方法依赖…

【html】如何用html+css写出一个漂亮的“众成教育”页面

先来看看效果图&#xff1a; 源码&#xff1a; <!DOCTYPE html> <html><head><meta charset"utf-8" /><title></title><style>* {margin: 0;padding: 0;/* border: 2px solid #000; */}.con {width: 1000px;height: 840px…

redis之发布与订阅

华子目录 什么是发布与订阅&#xff1f;常用命令psubscribe pattern1 [pattern2...]subscribe channel1 [channel2...]publish channel messagepunsubscribe pattern1 [pattern2...]unsubscribe [channel1 [channel2...]]pubsub subcommand argument1 [argument2...] 示例1示例…

JAVAEE之网络初识_协议、TCP/IP网络模型、封装、分用

前言 在这一节我们简单介绍一下网络的发展 一、通信网络基础 网络互连的目的是进行网络通信&#xff0c;也即是网络数据传输&#xff0c;更具体一点&#xff0c;是网络主机中的不同进程间&#xff0c;基于网络传输数据。那么&#xff0c;在组建的网络中&#xff0c;如何判断到…

MicroPython教程:ESP8266 快速参考

ESP8266 快速参考 Adafruit Feather HUZZAH 板&#xff08;图片来源&#xff1a;Adafruit&#xff09;。 以下是基于 ESP8266 的开发板的快速参考。如果这是您第一次使用该板&#xff0c;请考虑先阅读以下部分&#xff1a; 关于 ESP8266 端口的一般信息ESP8266 的 MicroPytho…

大中小面积紫外光老化加速试验机装置

高低温试验箱,振动试验台,紫外老化试验箱,氙灯老化试验箱,沙尘试验箱,箱式淋雨试验箱,臭氧老化试验箱,换气老化试验箱,电热鼓风干燥箱,真空干燥箱&#xff0c;超声波清洗机&#xff0c;盐雾试验箱 一、产品用途 紫外光加速老化试验装置采用荧光紫外灯为光源,通过模拟自然阳光中…

使用wireshark分析tcp握手过程

开启抓包 tcpdump -i any host 127.0.0.1 and port 123 -w tcp_capture.pcap 使用telnet模拟tcp连接 telnet 127.0.0.1 123 如果地址无法连接&#xff0c;则会一直重试SYN包&#xff0c;各个平台SYN重试间隔并不一致&#xff0c;如下&#xff1a; 异常站点抓包展示&#xff…

mmdetection的生物图像实例分割二:自定义数据集注册与模型训练

mmdetection的生物图像实例分割全流程记录 第二章 自定义数据集注册与模型训练 文章目录 mmdetection的生物图像实例分割全流程记录前言一、数据集的注册1.数据集的基本信息引入2.数据集base路径的更改3.数据集的评估 二、配置文件更改1.数据集任务配置2.模型配置3.训练过程配…

恭喜!Z医生喜提世界顶级梅奥诊所访问学者邀请函

➡️【院校简介】 梅奥诊所&#xff08;Mayo clinic&#xff09;&#xff0c;于1863年在美国明尼苏达州罗彻斯特创立&#xff0c;是全球规模最大的综合性非营利医生执业组织。它是以不断创新的医学教育和世界领先的医学研究为基础&#xff0c;建立起来的全美规模最大、设备最先…

基于 Amazon EC2 快速部署 Stable Diffusion WebUI + chilloutmax 模型

自2023年以来&#xff0c;AI绘图已经从兴趣娱乐逐渐步入实际应用&#xff0c;在众多的模型中&#xff0c;作为闪耀的一颗明星&#xff0c;Stable diffusion已经成为当前最多人使用且效果最好的开源AI绘图软件之一。Stable Diffusion Web UI 是由AUTOMATIC1111 开发的基于 Stabl…

flutter3-os:基于flutter3.x+dart3+getx手机版os管理系统

flutter3-os-admin跨平台手机后台OS系统。 原创Flutter3.22Dart3.4Getxfl_chart等技术开发仿ios手机桌面OA管理系统。自研栅格化布局引擎、自定义桌面壁纸、小部件、底部Dock菜单、可拖拽悬浮球等功能。 全新自研栅格化OS菜单布局引擎。 使用技术 编辑器&#xff1a;VScode技术…

Datetime,一个 Python 的时间掌控者

大家好&#xff01;我是爱摸鱼的小鸿&#xff0c;关注我&#xff0c;收看每期的编程干货。 一个简单的库&#xff0c;也许能够开启我们的智慧之门&#xff0c; 一个普通的方法&#xff0c;也许能在危急时刻挽救我们于水深火热&#xff0c; 一个新颖的思维方式&#xff0c;也许能…

NMF算法

1. NMF算法 NMF算法&#xff0c;即非负矩阵分解&#xff0c;是一种无监督学习算法&#xff0c;主要用于数据降维和特征提取&#xff0c;特别是在数据元素具有非负性约束的情况下。 NMF是一种数据降维模型&#xff0c;它的基本模型是通过矩阵分解将非负数据转换到新的空间&…

性能测试和功能测试有什么区别吗?

性能测试和功能测试是软件测试中两个不同的概念和方法。尽管它们都是为了提高软件质量和健壮性而进行的测试&#xff0c;但它们关注的方面和方法却不同。下面我将详细介绍性能测试和功能测试的区别。 一、定义和目的 性能测试是测试软件系统在不同条件下的性能和响应能力&…

微软新AI工具 Recall 被白帽公开锤了?

近日&#xff0c;一些网络安全研究人员演示了恶意软件是如何成功窃取 Windows Recall 工具收集到的数据。 2024年5月21日&#xff0c;微软发布全新的“CopilotPC”&#xff0c;这类 AI PC 通过与高通的最新芯片合作&#xff0c;实现了一个叫做“Recall”的功能。借助这个人工智…

lnmp平台部署web应用,安装Discuz社区平台详细文章——更新中

Nginx网站service 详细相关介绍-特点-http状态码-配置文件、将nginx添加永久环境变量 访问网站404是什么&#xff1f;_nginx 稳定版-CSDN博客文章浏览阅读1.2k次&#xff0c;点赞33次&#xff0c;收藏24次。开源Web服务器软件。_nginx 稳定版https://blog.csdn.net/2301_771619…

mmdetection的生物图像实例分割三:自定义数据集的测试与分析

mmdetection的生物图像实例分割全流程记录 第三章 自定义数据集的测试、重建与分析 文章目录 mmdetection的生物图像实例分割全流程记录前言一、测试集的推理1.模型测试2.测试数据解析 二、测试结果的数据整合三、生物结构的重建效果 前言 mmdetection是一个比较容易入门且上…

MySQL Doublewrite Buffer 有了解过吗?

引言&#xff1a;在数据库管理中&#xff0c;确保数据的完整性和一致性是至关重要的。然而&#xff0c;在持久化数据到磁盘的过程中&#xff0c;可能会遇到各种意外情况&#xff0c;如断电或系统崩溃&#xff0c;从而导致部分数据写入&#xff0c;而另一部分数据未能成功写入&a…

eclipse怎么导入python项目

python项目导入eclipse的步骤&#xff1a; 1、首先&#xff0c;打开Eclipse集成开发程序&#xff0c;在菜单栏上点击“File(F)”&#xff0c;在弹出来的列表中点击“导入&#xff08;I&#xff09;...”。 2、在弹出来的“导入”窗口中&#xff0c;选择“常规”选项中的“现有…