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

从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 = vocabself.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 idsdef decode(self, ids):text = " ".join([self.int_to_str[i] for i in ids])text = re.sub(r'\s+([,.?!"()\'])', r'\1', text) #Breturn 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.mzph.cn/diannao/23845.shtml

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

相关文章

深入理解 Spring Boot 启动原理

本文将从以下几个方面进行详细阐述&#xff1a; Spring Boot 启动过程概述BeanFactory 初始化Bean 的实例化和依赖注入Aware 接口的设置Bean 的初始化单例 Bean 的后处理Spring 启动后的后处理启动 HTTP 流量入口 一、Spring Boot 启动过程概述 Spring Boot 的启动过程可以分…

长轮询之websocket

官方文档 背景 WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议,它是为了解决 HTTP 协议存在的一些问题而产生的。WebSocket 的产生背景主要包括以下几点: HTTP 协议的局限性 HTTP 协议是一种请求-响应模型,客户端发起请求,服务端返回响应。这种模型存在一些问题,如…

等级保护测评与风险评估:构建网络安全的双重保障

# 等级保护测评与风险评估&#xff1a;构建网络安全的双重保障 在网络信息技术飞速发展的今天&#xff0c;网络安全问题日益成为社会关注的焦点。等级保护测评和风险评估作为网络安全管理的两个重要环节&#xff0c;对于确保信息系统的安全稳定运行具有重要意义。本文将探讨等级…

Stage #15深度解析:十六进制编码在XSS绕过中的应用

Stage #15深度解析&#xff1a;十六进制编码在XSS绕过中的应用 在网络安全领域&#xff0c;跨站脚本攻击&#xff08;XSS&#xff09;是一种常见的网络攻击手段。随着Web应用安全防护措施的不断完善&#xff0c;攻击者需要更高级的技术来绕过这些防护。本文将详细介绍如何利用…

1782java英语陪学记词系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 java英语陪学记词系统 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助采用了java设计&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统采用web模式&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&…

AI大底座核心平台:百度百舸AI异构计算平台(AI IaaS)与AI中台(AI PaaS)

AI大底座正是整合了以上端到端全要素技术能力&#xff0c;将基础架构IaaS与应用平台PaaS能力深度融合&#xff0c;面向企业和产业AI生 产与应用的全生命周期提供完整解决方案。 百舸AI异构计算平台是AI IaaS层的核心平台&#xff0c;包括AI计算、AI存储、AI加速、AI容器四层套件…

win磁盘映射到linux

有时虚拟机磁盘不够或文件想存在本地但使用linux环境&#xff0c;可以使用磁盘映射 1.windows磁盘映射&#xff0c;指定文件win_share进行文件共享&#xff0c;右键属性共享 2.linux 新建映射目录win_share 3.在linux进行挂载 sudo mount -t cifs //win7ip地址/win_share /hom…

【k8s的三种探针】

一、探针类型 作用&#xff1a;容器内应用的监测机制&#xff0c;根据不同的探针来判断容器应用当前的状态。 k8s 有三种类型的探针&#xff1a;StartupProbe(启动探针)、LivenessProbe(存活探针)、ReadinessProbe(就绪探针)。它们可以同时存在&#xff0c;但如果有StartupPro…

shell(一)

shell 既是脚本语言又是应用程序 查看自己linux系统的默认解析&#xff1a;echo $SHELL 创建第一个shell 文件 touch 01.sh编辑 vi 01.sh01.sh 文件内容 #!/bin/bash echo felicia保存 按Esc 然后输入:wq 定义以开头&#xff1a;#!/bin/bash #!用来声明脚本由什么shell解释…

idea maven 执行 控制台乱码

这是没加出现的问题 上方案

【HTTP系列】TCP/IP协议

文章目录 一、是什么二、划分五层体系应用层传输层网络层数据链路层物理层 四层体系 三、总结参考文献 一、是什么 TCP/IP&#xff0c;传输控制协议/网际协议&#xff0c;是指能够在多个不同网络间实现信息传输的协议簇 TCP&#xff08;传输控制协议&#xff09; 一种面向连…

【YOLOv5/v7改进系列】替换上采样层为Dysample

一、导言 介绍了一种名为DySample的超轻量级且高效的动态上采样器。DySample旨在解决当前动态上采样技术如CARAFE、FADE和SAPA虽然性能提升显著但带来大量计算负担的问题&#xff0c;这些问题主要来源于动态卷积的时间消耗以及用于生成动态核的额外子网络。此外&#xff0c;FA…

STC90C51驱动LCD1602、LCD12864、OLED

主控芯片&#xff08;STC90C516RDPG5151028&#xff09;介绍 ROM64K,RAM1280字节&#xff0c;40Pin&#xff0c;3个定时器&#xff0c;1个串口&#xff0c;8个中断源&#xff08;分别是&#xff1a;外部中断0(INTO)、外部中断 1(INT1)、外部中断 2(INT2)、外部中断 3(INT3)、定…

系统化自学Python的实用指南

目录 一、理解Python与设定目标 二、搭建学习环境与基础准备 三、入门学习阶段 四、中级进阶阶段 五、项目实践与持续深化 六、持续学习与拓展 一、理解Python与设定目标 Python概述&#xff1a;详细介绍Python的历史沿革、设计理念、主要特点&#xff08;如易读、易维护…

pytest构建和测试FastAPI CURD API

文章目录 概述目标FASTAPI 介绍CRUD API 项目设置freezepipreqs 代码介绍run APIpytest测试F&Q1.执行uvicorn app.main:app --host localhost --port 8000 --reload 报错 zsh: /usr/local/bin/uvicorn: bad interpreter2.生成requirement.txt时&#xff0c;pip3 list pipre…

C语言printf( ) 函数有哪些参数?

一、问题 printf( ) 函数的作⽤是向终端输出若⼲个任意类型的数据&#xff0c;此函数由格式控制部分和输出表列两部分组成&#xff0c;格式控制部分⼜由“&#xff05;”和格式字符串组成&#xff0c;那么&#xff0c;此函数格式字符串部分有哪些参数呢&#xff1f; 二、解答 …

Frida 学习之 messages

目录 一、消息发送 二、环境准备 三、从目标进程中发消息 四、在目标进程中接收消息 五、在目标进程中以阻塞方式接收消息 官方链接&#xff1a;Messages | Frida • A world-class dynamic instrumentation toolkit 参考链接&#xff1a;Frida官方手册 - 消息发送_frida…

Git操作--如何将本地文件夹push到远程新建的仓库中

一、从命令行创建一个新的仓库 1、创建一个说明文件 touch README.md 2、首先使该目录成为git可以管理的目录 git init 3、添加所有文件到本地暂存区 git add . #&#xff08;不要忘了后面的点"."&#xff0c;表示所有文件及目录&#xff09; # git add README…

v-model的工作原理是什么

v-model在Vue.js中是一个非常重要的指令&#xff0c;它实现了表单输入与应用状态&#xff08;data&#xff09;之间的双向绑定。以下是v-model的工作原理&#xff0c;我会尽量以清晰的方式分点表示和归纳&#xff1a; 本质&#xff1a; v-model本质上是一个语法糖&#xff0c…

C语言 RTC时间(年月日时分秒) 和 时间戳 互相转换

一、介绍 在C语言中&#xff0c;将年月日时分秒转换为时间戳&#xff08;Unix时间戳&#xff0c;即从1970年1月1日00:00:00 UTC到现在的秒数&#xff09;通常需要使用struct tm结构体和timegm或mktime函数。&#xff08;注意&#xff0c;mktime函数假设struct tm是本地时间&…