动手学LLM(ch2)

2.1 理解词嵌入

深度神经网络模型,包括大型语言模型(LLMs),无法直接处理原始文本,因为文本是分类数据,与神经网络的数学运算不兼容。为了达到这个目的,需要将单词转换为连续值向量。记住一句话就行,为了兼容神经网络的数学运算,把所有原始数据类型转变为连续值向量就是嵌入(embedding)。

如下图所示,通过特定的神经网络层或预训练模型,可以将视频、音频和文本等不同类型的数据嵌入为密集向量表示,使深度学习架构能够理解和处理这些原始数据。

需要注意的是,不同的数据格式需要各自专用的嵌入模型,例如,针对文本设计的嵌入模型不适用于音频或视频数据。

嵌入本质上是将离散对象(如单词、图像或文档)映射到连续向量空间的过程,目的是将非数字数据转换为神经网络可处理的格式。虽然词嵌入是最常见的形式,但也可以扩展到句子、段落或整个文档。当前,词嵌入的生成有多种算法和框架,其中Word2Vec是早期和流行的选择,它通过预测上下文生成词嵌入,基于相似上下文中词的相似含义。词嵌入可以有不同维度,从一维到数千维,高维度可以捕捉更多细微关系,尽管计算效率较低。大型语言模型(LLMs)通常生成自己的嵌入,优化以适应特定任务和数据。以GPT-2和GPT-3为例,嵌入大小根据模型变种变化,最小的GPT-2和GPT-3使用768维,而最大的GPT-3使用12,288维,这反映了性能与效率之间的权衡。

如下图所示,如果词嵌入是二维的,我们可以将它们绘制在二维散点图中以便于可视化。在使用词嵌入技术,例如 Word2Vec 时,对应于相似概念的词在嵌入空间中通常彼此接近。例如,在嵌入空间中,不同类型的鸟类相对于国家和城市更为靠近。

注意的是,LLMs 还可以创建上下文化的输出嵌入。这个后面会去讨论

2.2 文本分词(序列化)

如何将输入文本分割成单独的token,这是大型语言模型(LLM)创建嵌入的必需预处理步骤。

如下图所示,文本处理步骤在大型语言模型(LLM)中的最开始的阶段。我们将输入文本分割成单独的token,这些token可能是单词或特殊字符,例如标点符号。后续,我们会将把文本转换成token ID 并创建token嵌入。

读取本地的文本文件

这里没什么需要注意的,就是很简单的读取文件的代码。

# 设置要读取的文件路径,这里是本地文件
file_path = "./the-verdict.txt"
# 打开文件并读取内容
with open(file_path, 'r', encoding='utf-8') as file:raw_text = file.read()  # 读取文件内容
# 输出文本的总字符数
print("Total number of characters:", len(raw_text))
# 输出文件内容的前99个字符,以便预览
print(raw_text[:99])

使用 Python 的正则表达式库 re 模块来示例说明分词

这里其实看看就行,知道分词后大概什么样子就好了,因为我们后面转用预构建的分词器。

# 设置要读取的文件路径,这里是本地文件
file_path = "./the-verdict.txt"
# 打开文件并读取内容
with open(file_path, 'r', encoding='utf-8') as file:raw_text = file.read()  # 读取文件内容
# # 输出文本的总字符数
# print("Total number of characters:", len(raw_text))
# # 输出文件内容的前99个字符,以便预览
# print(raw_text[:99])import re  # 导入正则表达式模块# 定义一个包含标点和空格的字符串
text = "Hello, world. This, is a test."# 使用正则表达式按照空格进行分割,并保留空格作为分割符
result = re.split(r'(\s)', text)
print(result)  # 输出分割结果# 使用正则表达式按照标点(逗号、句号)和空格进行分割,并保留分割符
result = re.split(r'([,.]|\s)', text)
print(result)  # 输出分割结果# 去除结果中的空字符串
result = [item.strip() for item in result if item.strip()]
print(result)  # 输出处理后的结果# 另一个包含不同标点和空格的字符串
text = "Hello, world. Is this-- a test?"# 使用正则表达式按照标点(逗号、句号、问号、感叹号、括号、单引号)和空格进行分割,并保留分割符
result = re.split(r'([,.?_!"()\']|--|\s)', text)# 去除结果中的空字符串
result = [item.strip() for item in result if item.strip()]
print(result)  # 输出处理后的结果preprocessed = re.split(r'([,.?_!"()\']|--|\s)', raw_text)
preprocessed = [item.strip() for item in preprocessed if item.strip()]
print("_"*100)
print(preprocessed[:10])
print(len(preprocessed))

2.3 将token转换为tokenID

如下图所示,我们将文本token转换为tokenID,稍后可以通过嵌入层进行处理。

# 将预处理后的单词列表去重并排序
all_words = sorted(set(preprocessed))
# 计算词汇表的大小
vocab_size = len(all_words)
# 创建一个字典,将每个单词映射到唯一的整数索引
vocab = {token: integer for integer, token in enumerate(all_words)}
# 输出词汇表的大小
print(vocab_size)# 遍历词汇字典并输出前50个单词及其对应的索引
for i, item in enumerate(vocab.items()):print(item)  # 输出单词及其索引if i >= 50:  # 当索引达到50时停止输出break

封装标记器类

该类实现了一个简单的文本编码和解码器。构造函数接收一个词汇表,将其映射为字符串到整数和整数到字符串的字典。encode 方法将输入文本分割、预处理并转换为整数 ID 列表,decode 方法则将 ID 列表转换回文本,并处理标点前的空格。如下图所示

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()]# 将处理后的每个单词转换为对应的整数IDids = [self.str_to_int[s] for s in preprocessed]return ids  # 返回编码后的ID列表def decode(self, ids):# 根据ID列表生成对应的文本字符串text = " ".join([self.int_to_str[i] for i in ids])# 替换指定标点前的空格text = re.sub(r'\s+([,.?!"()\'])', r'\1', text)return text  # 返回解码后的文本
# 创建一个 SimpleTokenizerV1 实例,传入词汇表
tokenizer = SimpleTokenizerV1(vocab)
# 定义要编码的文本
text = """"It's the last he painted, you know," Mrs. Gisburn said with pardonable pride."""# 使用 tokenizer 的 encode 方法将文本编码为 ID 列表
ids = tokenizer.encode(text)
# 打印编码后的 ID 列表
print("Encoded IDs:", ids)
# 使用 tokenizer 的 decode 方法将 ID 列表解码回文本
decoded_text = tokenizer.decode(ids)
# 打印解码后的文本
print("Decoded text:", decoded_text)
# 再次使用 encode 和 decode 方法,验证编码和解码的一致性
# 编码文本后再解码
consistent_decoded_text = tokenizer.decode(tokenizer.encode(text))
# 打印一致性验证的结果
print("Consistent decoded text:", consistent_decoded_text)

2.4 添加特殊上下文token

在文本处理中,为了提供额外的上下文,添加一些“特殊”标记是非常有用的,特别是在处理未知单词和文本结束时。一些标记化器使用特殊标记来帮助大语言模型(LLM)理解文本,如下图所示。以下是一些常见的特殊标记:

  • [BOS](序列开始)表示文本的开头。
  • [EOS](序列结束)标记文本结束的位置,通常用于连接多段不相关的文本,例如两篇不同的维基百科文章或两本不同的书籍。
  • [PAD](填充)在训练 LLM 时,当批量大小大于 1 时,可能会包含长度不同的多个文本;使用填充标记可以将较短的文本填充到最长的长度,以使所有文本具有相同的长度。
  • [UNK] 用于表示不在词汇表中的单词。 

需要注意的是,GPT-2 不需要上述提到的任何标记,只使用 <|endoftext|> 标记以简化处理,如下图所示。这个 <|endoftext|> 标记类似于 [EOS] 标记。GPT 还使用 <|endoftext|> 进行填充,因为在训练批量输入时通常使用掩码,填充标记不会被关注,因此这些标记的具体内容并不重要。

此外,GPT-2 不使用 <UNK> 标记来处理超出词汇表的单词,而是采用字节对编码(BPE)标记化器,将单词分解为子词单元,这将在后面中讨论。

注意,在进行文本标记化时,如果输入文本中的单词不在词汇表中,例如 "Hello",则会产生错误。为了解决这种情况,可以在词汇表中添加特殊标记,如 "<|unk|>",用于表示未知单词。此外,由于我们已经在扩展词汇表,可以再添加一个名为 "<|endoftext|>" 的标记,它在 GPT-2 的训练中用于表示文本的结束(并且在连接多个文本时也会使用,例如当训练数据集包含多篇文章、书籍等时)。

tokenizer = SimpleTokenizerV1(vocab)
text = "Hello, do you like tea. Is this-- a test?"
tokenizer.encode(text)

为了让标记化器能够正确使用新的 <|unk|> 标记,我们需要对其进行相应的调整。接下来,我们可以尝试使用修改后的标记化器进行标记化

import re  # 导入正则表达式模块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()]# 将不在词汇表中的单词替换为 "<|unk|>"preprocessed = [item if item in self.str_to_intelse "<|unk|>" for item in preprocessed]# 将处理后的每个单词转换为对应的整数IDids = [self.str_to_int[s] for s in preprocessed]return ids  # 返回编码后的ID列表def decode(self, ids):# 根据ID列表生成对应的文本字符串text = " ".join([self.int_to_str[i] for i in ids])# 替换指定标点前的空格text = re.sub(r'\s+([,.:;?!"()\'])', r'\1', text)return text  # 返回解码后的文本# 文件路径
file_path = "./the-verdict.txt"
# 打开文件并读取内容
with open(file_path, 'r', encoding='utf-8') as file:raw_text = file.read()  # 读取文件内容# 对文本进行预处理,分割并去除空白
preprocessed = re.split(r'([,.?_!"()\']|--|\s)', raw_text)
preprocessed = [item.strip() for item in preprocessed if item.strip()]# 将预处理后的单词列表去重并排序
all_tokens = sorted(set(preprocessed))
# 在词汇表中添加特殊标记
all_tokens.extend(["<|endoftext|>", "<|unk|>"])
# 计算词汇表的大小
vocab_size = len(all_tokens)# 创建一个字典,将每个单词映射到唯一的整数索引
vocab = {token: integer for integer, token in enumerate(all_tokens)}# 打印词汇表中最后五个单词及其索引
for i, item in enumerate(list(vocab.items())[-5:]):print(item)# 创建标记化器实例
tokenizer = SimpleTokenizerV2(vocab)# 定义两个示例文本
text1 = "Hello, do you like tea?"
text2 = "In the sunlit terraces of the palace."
# 连接两个文本,用 "<|endoftext|>" 标记分隔
text = " <|endoftext|> ".join((text1, text2))
print(text)  # 打印连接后的文本# 使用标记化器进行编码
ids = tokenizer.encode(text)# 打印编码后的 ID 列表
print("Encoded IDs:", ids)# 使用标记化器的 decode 方法将 ID 列表解码回文本
decoded_text = tokenizer.decode(ids)
# 打印解码后的文本
print("Decoded text:", decoded_text)# 再次使用 encode 和 decode 方法,验证编码和解码的一致性
# 编码文本后再解码
consistent_decoded_text = tokenizer.decode(tokenizer.encode(text))
# 打印一致性验证的结果
print("Consistent decoded text:", consistent_decoded_text)

2.5 字节对编码(BPE)

  • GPT-2 使用字节对编码(BytePair Encoding, BPE)作为其标记化器。
  • 这种方法允许模型将不在预定义词汇表中的单词拆分为更小的子词单元,甚至是单个字符,从而能够处理超出词汇表的单词。
  • 例如,如果 GPT-2 的词汇表中没有单词 "unfamiliarword",它可能将其标记化为 ["unfam", "iliar", "word"] 或其他子词拆分,这取决于其训练时的 BPE 合并策略。
  • 原始的 BPE 标记化器代码可以在这里找到:https://github.com/openai/gpt-2/blob/master/src/encoder.py。
  • 在本章中,我们使用了 OpenAI 的开源库 tiktoken 中的 BPE 标记化器,该库的核心算法用 Rust 实现,以提高计算性能。
  • 我在 ./bytepair_encoder 目录中创建了一个笔记本,比较了这两种实现的性能(tiktoken 在样本文本上的速度约快 5 倍)。

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

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

相关文章

17【Protues单片机仿真】基于51单片机的太阳能智能谷物翻晒机器人

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于51单片机&#xff0c;避障&#xff0c;低于50CM报警&#xff0c;LED灯亮起&#xff0c;自动翻晒用光敏电阻&#xff0c;光照强度大&#xff0c;电机转动&#xff0c;相当于翻晒粮食&#xff0…

Linux——pod的调度

pod的调度 控制器: rc/rs 副本数量控制器 主要保证pod的数量符合管理员要求&#xff0c;并不会对pod进行额外的管理 以下三种控制器&#xff0c;本质上是服务控制器。具备以下特性&#xff1a; 副本数量的控制服务的滚动更新&#xff08;更新pod&#xff09;支持更新失…

高校教师成果管理小程序的设计与实现springboot(lw+演示+源码+运行)

摘 要 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供服务。针对高校教师成果信息管理混乱&#xff0c;出错率高&#xff0c;信息安全…

C++ STL初阶(14): map和set

1.关联式容器与键值对 前导文章&#xff1a;C 二叉树进阶-CSDN博客 之前我们学习的线性的容器&#xff0c;如&#xff1a;vector deque list等都叫作序列式容器 与之对立的概念是关联式容器 关联式容器 也是用来存储数据的&#xff0c;与序列式容器不同的是&#xff0c;其 里面…

【C++】检测TCP链接超时——时间轮组件设计

目录 引言 时间轮思想 设计的核心思路 完整代码 组件接口 个人主页&#xff1a;东洛的克莱斯韦克-CSDN博客 引言 对于高并发的服务器来说&#xff0c;链接是一种比较珍贵的资源&#xff0c;对不活跃的链接应该及时释放。判断连接是否活跃的策略是——在给定的时间内&#…

Redis中BigKey与MoreKey优化笔记

1.MoreKey 在Redis中&#xff0c;MoreKey问题通常指的是当数据库中的key数量非常多时&#xff0c;使用如KEYS *这样的命令去检索所有的key&#xff0c;这会导致Redis服务阻塞&#xff0c;影响正常业务。因为Redis是单线程操作的&#xff0c;执行这类命令时会占用大量时间&…

Arthas redefine(加载外部的.class文件,redefine到JVM里 )

文章目录 二、命令列表2.2 class/classloader相关命令2.2.3 redefine&#xff08;加载外部的.class文件&#xff0c;redefine到JVM里 &#xff09;举例1&#xff1a;加载新的代码&#xff0c;jad/mc 命令使用举例2&#xff1a;上传 .class 文件到服务器的技巧 二、命令列表 2.…

柯桥韩语学校|韩语每日一词打卡:회갑연[회가변]【名词】花甲宴

今日一词:회갑연 韩语每日一词打卡&#xff1a;회갑연[회가변]【名词】花甲宴 原文:인구 노령화에 따라서 요즘 회갑연보다는 고희연을 더 많이 지냅니다. 意思&#xff1a;随着人口老龄化&#xff0c;最近比起花甲宴&#xff0c;更多人办古稀宴。 【原文分解】 1、인구[인구]…

【BurpSuite】访问控制漏洞和权限提升 | Access control vulnerabilities (3-6)

&#x1f3d8;️个人主页&#xff1a; 点燃银河尽头的篝火(●’◡’●) 如果文章有帮到你的话记得点赞&#x1f44d;收藏&#x1f497;支持一下哦 【BurpSuite】访问控制漏洞和权限提升 | Access control vulnerabilities (3-6&#xff09; 实验三 Lab: User role controlled b…

【IoT-NTN】系统消息SIB31信令分析

3GPP卫星通信发展迅速&#xff0c; TS36.331 R17中新增SIB31携带星历信息&#xff0c;本文对SIB31的信令内容进行了分析。 SystemInformationBlockType31 分析报告 一、概述 本文档详细描述了SystemInformationBlockType31&#xff08;简称SIB31&#xff09;的结构和内容&am…

[Redis][集群][上]详细讲解

目录 0.前言1.基本概念2.数据分片算法0.前言1.哈希求余2.一致性哈希算法3.哈希槽分区算法(Redis使用) 0.前言 说明&#xff1a;该章节相关操作不需要记忆&#xff0c;理解流程和原理即可&#xff0c;用的时候能自主查到即可 1.基本概念 哨兵模式提高了系统的可用性&#xff0…

试用Debian12.7和Ubuntu24.4小札

Debian GNU/Linux 12 (bookworm)和Ubuntu 24.04.1 LTS是现阶段&#xff08;2024年9月26日&#xff09;两个发行版的最新版本。Ubuntu Server版本默认就不带桌面&#xff08;ubuntu-24.04-live-server-amd64.iso&#xff09;&#xff0c;这个默认就是最小化安装&#xff08;安装…

Moshi: a speech-text foundation model for real time dialogue

视频号 挺神奇的东西 整下来 kyutai-labs/moshi (github.com) git clone https://github.com/kyutai-labs/moshi.git 在线体验 moshi.chat 结束后 点击Download audio Download video 可以下载音频与视频 &#xff08;不过是webm格式&#xff09; 发行版 已上传至资源 小…

springboot+大数据基于数据挖掘的招聘信息可视化大屏系统【内含源码+文档+部署教程】

博主介绍&#xff1a;✌全网粉丝10W,前互联网大厂软件研发、集结硕博英豪成立工作室。专注于计算机相关专业毕业设计项目实战6年之久&#xff0c;选择我们就是选择放心、选择安心毕业✌ &#x1f345;由于篇幅限制&#xff0c;想要获取完整文章或者源码&#xff0c;或者代做&am…

【C++】 vector 迭代器失效问题

【C】 vector 迭代器失效问题 一. 迭代器失效问题分析二. 对于vector可能会导致其迭代器失效的操作有&#xff1a;1. 会引起其底层空间改变的操作&#xff0c;都有可能是迭代器失效2. 指定位置元素的删除操作--erase3. Linux下&#xff0c;g编译器对迭代器失效的检测并不是非常…

数论——数数(找质因数个数),三位出题人(组合数学,快速幂)

数数&#xff08;找质因数个数&#xff09; 题目描述 登录—专业IT笔试面试备考平台_牛客网 运行代码&#xff08;通过率一半&#xff09; #include <iostream> #include <vector> using namespace std; const int N5e66; int n; vector<bool>vis; vo…

vmware-toolbox安装,VMware虚拟机访问win10共享目录

问题&#xff1a;VMware界面无法安装vmware-toolbox&#xff0c;共享目录设置失败 解决方法&#xff1a; VMware设置 共享文件夹 ubuntu24 vm中运行vmware-toolbox-cmd -v 检查版本 vm运行sudo apt install open-vm-tools // vm可能需要重启 vm的 /mnt 目录下如果没有 hgfs…

骨传导耳机哪个牌子好?年度五大热门骨传导耳机推荐清单来了!

近年来&#xff0c;骨传导耳机以其独特的传音方式和开放耳道的设计&#xff0c;逐渐成为运动爱好者和追求健康生活方式人群的新宠。与传统耳机相比&#xff0c;骨传导耳机不仅能够保护听力&#xff0c;还能在享受音乐的同时保持对周围环境的警觉。 随着骨传导耳机市场的不断壮…

1.MySQL的安装

目录 下载安装包 安装前环境的准备 正式安装 下载安装包 MySQL安装网址:https://www.mysql.com/cn/ 进去之后就是上面这个页面&#xff0c;进行汉化的时候将这个网页拉至最下&#xff0c;右下角点成中文就可以&#xff0c;如下这个页面。 回到页面顶端&#xff0c;点击下载&a…

并发编程---线程与进程

业务场景&#xff1a;小明去理发店理发。 小明去理发店理发&#xff0c;完成理发需要吹&#xff0c;剪&#xff0c;洗、理的过程。由这个场景我们引用进程和线程这两个 概念。 一.进程 1.什么是进程 进程是具有独立功能的程序关于某个数据集合上的一次运行活动&#xff0c;是…