【教程】从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,一经查实,立即删除!

相关文章

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容器四层套件…

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)、定…

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…

Frida 学习之 messages

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

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

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

Python语法详解module4(函数)

目录 一、函数基础1. 函数的概念和作用2. 函数的定义和调用3. 参数传递 二、返回值和文档字符串返回值的概念和用法1. 返回值的概念2. 使用 return 关键字返回值&#xff1a;3. 多个返回值的情况&#xff1a; 文档字符串&#xff08;docstring&#xff09;的作用和使用方法1. 文…

大坝安全监测自动化技术的规范化设计准则

大坝安全监测自动化技术的规范化设计准则 一、施工阶段自动化系统设计要点 在施工阶段&#xff0c;大坝安全监测自动化系统的设计应当涵盖以下几个核心内容&#xff1a; 监测仪器的布局规划及详细的施工图纸设计。 配套土建项目以及防雷设施的施工设计规划。 明确施工过程中的技…

Jenkins工作流程原理

持续集成&#xff1a;自动部署打包发布代码 Jenkins工作流程 项目已经基于Jenkins实现了持续集成&#xff0c;每当我们push代码时&#xff0c;就会触发项目完成自动编译和打包。而需要运行某个微服务时&#xff0c;我们只需要经过两步&#xff1a; 第一步&#xff0c;访问je…

win10下,python3.7安装xlrd和xlwt

win10下&#xff0c;执行import xlwt&#xff0c;结果报错 No module named xlwt。 原因&#xff1a;使用的python没有安装xlwt包。 解决方法&#xff1a; 1&#xff09;打开一个命令窗口&#xff0c;执行&#xff1a;where python&#xff0c;可以看到使用的python路径及版…

2024年SQL Editor趋势

SQL Editor已经超越了仅仅执行查询的传统角色&#xff0c;成为提升生产力、协作和数据管理的综合平台。这一演变反映了QA软件测试人员和开发人员日益增长的需求和复杂需求。让我们深入探讨当前的趋势&#xff0c;强调这些变化如何满足用户的基本需求。 1.增强的协作功能 现代S…

Questflow借助MongoDB Atlas以AI重新定义未来工作方式

MongoDB客户案例导读 Questflow借助MongoDB Atlas赋能AI员工&#xff0c;助力中小型初创企业自动化工作流程&#xff0c;简化数据分析&#xff0c;提升客户体验&#xff0c;推动AI与员工的协作&#xff0c;重新定义未来工作方式。 协作式AI自动化平台 无需编码即可拥有自己的…

动态规划(多重背包问题+二进制优化)

引言 多重背包&#xff0c;相对于01背包来说&#xff0c;多重背包是每个物品会有相应的个数&#xff0c;最多可以选那么多个&#xff0c;因而对于朴素多重背包&#xff0c;需要在01背包的基础上&#xff0c;再加一层物品的循环 朴素多重背包例题 P2347 [NOIP1996 提高组] 砝…

【因果推断python】19_局部平均效应2

目录 局部平均干预效果&#xff1a;后期 对参与度的影响 关键思想 局部平均干预效果&#xff1a;后期 局部平均处理效应明确了我们可以估计因果效应的人群。这也是查看 IV 的另一种方式&#xff0c;它提供了我们可以使用的其他很酷的直觉。在现代 IV 中&#xff0c;我们将工…

Codeforces Round 951 (Div. 2) C、D(构造、线段树)

1979C - Earning on Bets 构造题&#xff1a;观察到k范围很小&#xff0c;首先考虑最终硬币总数可以是多少&#xff0c;我们可以先假设最终的硬币总数为所有k取值的最小公倍数&#xff0c;这样只需要满足每个结果添加1枚硬币即可赚到硬币。 // Problem: C. Earning on Bets //…

《Kubernetes部署篇:基于Kylin V10+ARM64架构CPU+containerd一键离线部署容器版K8S1.26.15高可用集群》

总结&#xff1a;整理不易&#xff0c;如果对你有帮助&#xff0c;可否点赞关注一下&#xff1f; 更多详细内容请参考&#xff1a;企业级K8s集群运维实战 一、部署背景 由于业务系统的特殊性&#xff0c;我们需要针对不同的客户环境部署基于containerd容器版 K8S 1.26.15集群&…