2024年5月

一、SentencePiece 简介

SentencePiece 在大模型领域主要用于文本的 分词 和 编码。

1、分词

是将文本分割成一个个独立的词语或符号。传统的中文分词方法,例如 BMM 分词、隐马尔可夫(H M M ) 分词,都是基于规则的,需要人工制定分词规则。而 SentencePiece 则是基于 无监督学习 的,它可以自动学习文本的语义和结构,并根据学习结果进行分词。

2、编码

是将分词后的词语或符号转换为数字形式,以便计算机能够处理。SentencePiece 使用了一种称为 字节对编码 的方法,它可以将每个词语或符号编码成一个或多个字节。字节对编码的优点是能够有效地利用空间,并且可以将词语或符号之间的关系编码到编码中。

3、优势:SentencePiece 在大模型领域具有以下优势:

分词效果好,能够准确地识别词语和符号的边界。
编码效率高,能够节省空间。
能够将词语或符号之间的关系编码到编码中,有利于模型学习。
因此,SentencePiece 已经被广泛应用于各大模型,例如 Google 的 BERT、GPT-3,以及阿里巴巴的 M6 等。

简单来说,SentencePiece 就是大模型领域的一个 分词和编码工具。它可以帮助大模型更好地理解和处理文本。

4、自监督训练原理

SentencePiece 的自监督训练模型原理是通过 无监督学习 的方式,学习文本的语义和结构,并根据学习结果进行分词和编码。

具体来说,SentencePiece 的训练过程可以分为以下几个步骤:

数据准备:首先需要准备一个文本语料库,语料库中的文本可以是任何类型,例如新闻文章、书籍、代码等。
模型训练:使用无监督学习算法训练 SentencePiece 模型,模型的输入是文本语料库,输出是分词后的文本。
模型评估:使用评估指标评估模型的性能,例如分词准确率、召回率等。
SentencePiece 使用的无监督学习算法是一种称为 Masked Language Modeling (MLM) 的算法。MLM 的基本思想是:将文本中的部分词语或符号进行遮蔽,然后让模型预测被遮蔽的词语或符号。通过这种方式,模型可以学习文本的语义和结构。

在 SentencePiece 中,MLM 的具体实现如下:

随机选择文本中的部分词语或符号进行遮蔽。
将被遮蔽的词语或符号替换为一个特殊符号,例如 [MASK]。
将处理后的文本输入模型,让模型预测被遮蔽的词语或符号。
通过这种方式,模型可以学习到被遮蔽词语或符号与周围词语或符号之间的关系,从而提高分词和编码的准确性。

SentencePiece 的自监督训练模型具有以下优势:

不需要人工制定分词规则,能够自动学习文本的语义和结构。
分词效果好,能够准确地识别词语和符号的边界。
编码效率高,能够节省空间。
SentencePiece 的自监督训练模型已经被广泛应用于各大模型,例如 Google 的 BERT、GPT-3,以及阿里巴巴的 M6 等。

二、TikToken 简介

Tiktoken 的功能与 SentencePiece 类似,都是用于文本的 分词 和 编码。

Tiktoken 是一个基于 BPE 算法的 快速分词器,它专门针对 GPT-4 和 ChatGPT 等大模型进行了优化。Tiktoken 的主要特点如下:

速度快:Tiktoken 的分词速度比 SentencePiece 快很多,可以满足大模型训练和推理的需求。
效果好:Tiktoken 的分词效果与 SentencePiece 相当,能够准确地识别词语和符号的边界。
易用性:Tiktoken 提供了简单的 API 接口,方便使用。
Tiktoken 与 SentencePiece 的主要区别 如下:

分词算法:Tiktoken 使用 BPE 算法进行分词,而 SentencePiece 使用的是无监督学习算法。
速度:Tiktoken 的分词速度比 SentencePiece 快很多。
模型:Tiktoken 专门针对 GPT-4 和 ChatGPT 等大模型进行了优化,而 SentencePiece 则是通用的。

速度探究
所以大家一定对为什么这么快很好奇,查阅tictoken的源码得知,tictoken对CoreBPE类进行了基于RUST的重写,包括真·多线程,regex,缓存caching,哈希各个方面的优化,具体的下面逐一解释:

3.1 regex优化
正则是耗时的大头,解决办法是用一些不那么花哨的方法,比如用 regex crate可解析的形式的regex要比寻常方法快3倍以上。

一旦明确了使用crate可解析的regex,可以选择用regex crate 或者 fancy_regex crate

regex crate 和 fancy_regex crate也有相互关系,fancy_regex使用的re.find_it会竞争re的可变缓存空间,造成性能下降,而regex的find_iter有不同的代码路径,不会造成这个问题。为此,通过给绝大部分的regex线程做一个克隆线程来避免。

3.2 threading
rayon并没有比python自带的threads和释放GIL的情况下快,所以直接用python线程计数等来完成threads

这里我多说一下,python自带的GIL是指如果没有额外操作,只是使用了类似:

3.3 caching
tokenizer中使用LRU cache是很有必要的,可以加速查找速度,作者使用了RWLock来保护cache安全,对于RWLock,全称是"reader-writer spin lock",和普通的spinlock不同,它对"read"和"write"的操作进行了区分。如果当前没有writer,那么多个reader可以同时获取这个rwlock。如果当前没有任何的reader,那么一个writer可以获取这个rwlock。

3.4 hash
作者使用了FxHashMap替代传统的HashMap达到了一定的性能提升,简单说明一下,FxHashMap的散列算法质量不高,但速度非常快,特别是对整数键而言,并且发现它的性能优于rustc内的所有其他散列算法。

以上就是tictoken进行的性能优化。

一、点乘(Dot Product)、点积 内积

点乘也称为标量积或内积,是两个等长向量之间的运算。它将两个向量的对应元素相乘,然后将乘积相加,得到一个标量值。点乘只适用于向量。

点积是点乘的另一种说法,通常在数学和物理学中使用,但在深度学习中,点乘和点积可以互换使用。

内积通常指的是点乘,是两个向量之间的运算,得到一个标量值。内积的概念也可以扩展到矩阵,称为矩阵乘法,但矩阵乘法的结果是一个矩阵,而不是一个标量。

1、对应元素相乘,求和

dot:只能张量中向量(一维)操作,结果是一个标量。比如两个embedding求相似度。

import torch
x = torch.tensor([1,2,3])
y = torch.tensor([1,1,2])
z = torch.dot(x,y)
print(z)
## 结果:tensor(9)

k = x*y
m = torch.mul(x,y) 
print(k)
print(m)

2、 对应元素相乘,不求和

*和 mul 操作是一样的,要求x,y具有相同的维度(一维向量,二维矩阵都可以)

import torch
x = torch.tensor([[3,3],[3,3]])
y = torch.tensor([[1,2],[3,4]])
k = x*y
m = torch.mul(x,y)  #x.mul(x)
print(k)
print(m)

## tensor([[ 3,  6],
           [ 9, 12]])
## tensor([[ 3,  6],
           [ 9, 12]])

3、 矩阵相乘

@和torch.mm和torch.matmul 作用一样

矩阵相乘有torch.mm和torch.matmul两个函数。其中前一个是针对二维矩阵,后一个是高维。当torch.mm用于大于二维时将报错。
a = [B,E]
b = [E,B]
c = torch.mm(a,b)
C 维度是[B,B]

4、torch.matmul重点解读

matmul 有广播机制

(1)两个 1 维,向量内积

a = torch.ones(3)
b = torch.ones(3)
print(torch.matmul(a,b))  # tensor(3.)

(2)两个 2 维,矩阵相乘

a = torch.ones(3,4)
b= torch.ones(4,3)
print(torch.matmul(a,b))  
# tensor([[4., 4., 4.],
#        [4., 4., 4.],
#        [4., 4., 4.]])

(3)一个 1 维,二个 2 维,矩阵和向量相乘

注意:相靠近的那个维数要相同,比如(7)和(7,8,5),又比如(7,8,5)和(5)

a = torch.ones(3)
b= torch.ones(3,4)
print(torch.matmul(a,b))  # tensor([3., 3., 3., 3.])

a = torch.ones(3,4)
b = torch.ones(4)
print(torch.matmul(a,b))  # tensor([4., 4., 4.])

(4)、高维情况

i)其中一个1维,另一个N维(N>2): 类似3),即需要靠近的那个维数相同,比如(7,)和(7,8,11),又比如(7,8,11)和(11,)

ii)都高于2维,那么除掉最后两个维度之外(两个数的维数满足矩阵乘法,即,(m,p)和(p,n)),剩下的纬度满足pytorch的广播机制。

a=torch.ones(5,3,4,1)
b=torch.ones(  3,1,1)
print(torch.matmul(a,b))