【教程】从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 = 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”。合并由频率截止决定

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【YOLOV8】1.开发环境搭建

Yolo8出来一段时间了,包含了目标检测、实例分割、人体姿态预测、旋转目标检测、图像分类等功能,所以想花点时间总结记录一下这几个功能的使用方法和自定义数据集需要注意的一些问题,本篇是第一篇,开发环境的配置。 YOLO(You Only Look Once)是一种流行的物体检测和图像分割…

UE4_Ben_图形52_水下效果处理

学习笔记&#xff0c;不喜勿喷&#xff0c;欢迎指正&#xff0c;侵权立删&#xff01;祝愿生活越来越好&#xff01; 在这个后期处理的效果中&#xff0c;我们可以看到有很多不同的&#xff0c;这里有浓雾&#xff0c;波纹扭曲&#xff0c;镜头扭曲和边缘模糊&#xff0c;在第4…

Linux中安装Docker,并使用Docker安装MySQL和Redis

1、安装docker 1卸载系统之前的docker yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine2、安装Docker-CE #安装必须的依赖 sudo yum install -y yum-utils \device-map…

抽象,自定义函数,递归

6.1懒惰是一种美德 如果你 在一个地方编写了一些代码&#xff0c;但需要在另一个地方再次使用&#xff0c;该如何办呢&#xff1f; 假设你编写了一段代码&#xff0c;它计算一些斐波那契数&#xff08;一种数列&#xff0c;其中每个数都是前两个数的和&#xff09;。 现在的…

Freeswitch-soundtouch-变声开发

文章目录 一、介绍二、安装soundtouch2.1 源码安装方式&#xff08;推荐&#xff09;2.1.1下载源码2.1.2解压2.1.3 编译2.1.4 迁移&#xff08;可选&#xff09; 2.2 apt-get 安装 三、使用3.1 终端使用3.2 Freeswitch使用3.2.1编译Freeswitch的mod_soundtouch3.2.2启用 mod_so…

Qt图像处理技术九:得到QImage图像的灰度直方图

效果 原理 得到灰度化值&#xff0c;将灰度化的值带入0-255内&#xff0c;增加&#xff0c;得到可视化图形 源码 // 绘制直方图 QImage drawHistogram(const QImage &image) {QVector<int> histogram(256, 0);// 计算图像的灰度直方图for (int y 0; y < image…

static的用法

static一般用于修饰局部变量&#xff0c;全局变量&#xff0c;函数 1 static修饰局部变量 是因为改为static int a1;后&#xff0c;出了作用域&#xff0c;不会销毁a的值&#xff0c;想要理解其本质&#xff0c;首先先看一下这个图&#xff1a; static修饰局部变量时&#xf…

【代码随想录】【算法训练营】【第30天】 [322]重新安排行程 [51]N皇后 [37]解数独

前言 思路及算法思维&#xff0c;指路 代码随想录。 题目来自 LeetCode。 day 30&#xff0c;周四&#xff0c;好难&#xff0c;会不了一点~ 题目详情 [322] 重新安排行程 题目描述 322 重新安排行程 解题思路 前提&#xff1a;…… 思路&#xff1a;回溯。 重点&…

yolo水果品质:新鲜腐烂橙子检测/分类数据集(3k+图像全标注)

yolo水果品质检测之新鲜腐烂橙子数据集&#xff0c;整个数据集共包含3852张图像&#xff0c;yolo标注完整&#xff08;txt格式&#xff09;,标注类别分为新鲜橙子&#xff08;0&#xff09;和腐烂橙子&#xff08;1&#xff09;两类 图像统一格式&#xff1a;jpg 图像统一分辨…

windows10子系统wsl ubuntu22.04下GN/ninja环境搭建

打开windows10子系统 ubuntu22.04 ubuntu22.04: 首先需要 安装ninja $sudo apt install ninja-build $ ninja --version 1.10.0 安装clang $sudo apt install clang $clang --version Ubuntu clang version 14.0.0-1ubuntu1.1安装gn Github: https://github.com/timniederh…

ar地产沙盘互动体验提供更加丰富多彩的楼盘信息

AR增强现实技术作为其重要分支&#xff0c;正逐步在全球市场中崭露头角。国内的AR增强现实技术公司正致力于链接物理世界和虚拟世界&#xff0c;为用户带来沉浸式的AR体验。它们打造线上线下联动的一站式文旅景区数字化运营平台&#xff0c;让您在享受旅游的同时&#xff0c;也…

什么是Vector Database(向量数据库)?

什么是Vector Database(向量数据库)&#xff1f; 向量数据库是向量嵌入的有组织的集合&#xff0c;可以随时创建、读取、更新和删除。向量嵌入将文本或图像等数据块表示为数值。 文章目录 什么是Vector Database(向量数据库)&#xff1f;什么是嵌入模型(Embedding Model)&…

用蒙特卡罗积分法近似求解定积分的值及举例

一、背景知识 1、连续随机变量的概率密度函数 对于连续型随机变量的概率密度函数&#xff08;PDF&#xff09;&#xff0c;其在整个定义域上的积分必须等于1。这是概率密度函数的一个基本属性&#xff0c;它确保了随机变量取任何值的概率之和等于1&#xff0c;符合概率论的公…

家用洗地机哪个牌子好?专家推荐榜单助你挑选最合适的洗地机

随着科技不断发展&#xff0c;智能家居产品逐渐融入我们日常生活中&#xff0c;洗地机作为家庭清洁必备工具&#xff0c;越来越受到消费者青睐&#xff0c;但是面对市面上种类繁多的洗地机&#xff0c;我们如何挑选到适合自己的产品呢&#xff1f;专家推荐榜单助你挑选最合适的…

在vue项目中使用markdown-it回显markdown文本

前言 其实有很多插件都是可以用来回显markdown文本的,这个插件也是其中之一。 文档地址:markdown-it | markdown-it 中文文档 这个文档在vue2和vue3里面都可以使用,所以还是比较推荐的 使用 安装 npm install markdown-it --save 应用 <template><div><…

正邦科技(第10天)

这里写目录标题 任务一任务二任务三 任务一 下位机报上来的十进制数据进行解析&#xff1a; 360170 固定报文&#xff0c;一个F对应一个字节&#xff0c;温度值&#xff0c;湿度值&#xff0c;烟雾浓度值是十进制转16进制&#xff0c;告警状态需要高低位移位&#xff0c;然后再…

【Pycharm】功能介绍

1.Code Reformat Code 格式化代码&#xff0c;可以帮助我们去自动调整空格等&#xff0c;根据python语法规范自动调整 2.Settings 1.创建py文件默认填充模版 3.读写py文件编码格式一致性 顶部代码指定的编码方式作用&#xff1a; 可以保证python2/3解释器在读取文件的时候按…

个人项目———密码锁的实现

布局组件 布局效果 组件绑定 密码锁的实现代码 using TMPro; using UnityEngine; using UnityEngine.UI;public class PasswordPanel : MonoBehaviour {// public Button button;// 所有按键的父物体public Transform buttonPanel;// 输入字符串的文本框public TMP_Text input…

英国树莓派五大天王和你相约上海国际嵌入式展!

6月12日-14日 上海世博展览馆3号馆 H3馆 237展位 树莓派(Raspberry Pi),这个曾经让全球掀起"创客热潮"的小型单板电脑,如今已经成为嵌入式行业不可或缺的一员。作为行业先驱,树莓派基金会正携手团队,亮相2024年6月12日至6月14日在上海举办的 Embedded World上海国…

【Elasticsearch】es基础入门-03.RestClient操作文档

RestClient操作文档 示例&#xff1a; 一.初始化JavaRestClient &#xff08;一&#xff09;引入es的RestHighLevelClient依赖 <!--elasticsearch--> <dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest…