Rethink AI【5】:分词与词嵌入技术

前言

计算机没有办法直接理解、存储自然语言。在AI之外的领域,字符串操作通常是以各种字符编码来进行运算的,比如ASCII码、UTF-8编码等等。在AI中,我们也需要一种利用计算机技术,将自然语言转化为计算机能够理解的表示的方法。

通常,我们会将自然语言进行两步操作——分词和词嵌入。其中,分词是指将一个句子分成若干基本单元,词嵌入则是将分割到的基本单元转化为向量。

分词

所谓分词,就是将句子变成若干基本单元,用作输入的句子处理以及输出。分词算法的要求是:

  1. 高效。算法不能太复杂。
  2. 可拓展性。要很好地兼容没有在训练数据中出现的词。

我们首先从英语分词入手,看看我们究竟要解决什么问题。想象一下,我们要对语言进行建模,就要处理一个篇章非常大的文段。

我们知道,英语是依靠空格进行单词间分隔的,那么我们依靠空格对单词进行分割如何?这是一种极其简单、易于实现的分割方法。但是,这个分词方法有很强的扩展性吗?并没有,除此之外,这个方法有个很致命的问题——同一个单词有很多种表示。比如这一句话中——“The show shows some significant things, showing the show shows lots of things.”——出现了show、shows、showing三种表示,但是它们都是由同一个词变化而来的。这种分词方法会极大扩张词表的大小,造成单词表示的膨胀。除此之外,这种分词方法会导致模型永远没法生成没见过的单词,用专业术语来说,就是没法很好处理OOV(Out-Of-Vocabulary)的情况。

针对一词多表示的问题,研究者们提出了一种新的分词算法——Subword分词。这个算法对于一个单词,会将之拆分为前缀、子词和后缀,比如show、shows、showing这三个单词在词表中,会变成show、-s、-ing三个基本单元。这个分词方法导师很好解决了一次多表示的问题,但是,对于OOV问题还是束手无策的。

那么,有人就会说了,为什么一定要用分“词”呢?像计算机一样,直接用字符表示是否可以?这便是character-level tokenization。这个方法能够很好地限制词表的大小,也能够解决OOV问题——没有一个单词不是字母组成的。一切都好,对吧?实际上,在一段时间之前,我也觉得这个方法非常好。不过,我们想一下,Transformer模型的输出是逐字符输出的,根据前面的内容预测后面的内容。如果用字符表示,那么一个文段就会占据过多的空间,没有办法很好地生成长文段。网上很多资料说,character-level tokenization没办法学习到字之间的信息——全是狗屁!只要输入够多,字之间的关系很好学习。

我们亟需一个折衷的分词方案。

这个方案就是BPE——Byte-Pair Encoding。这个算法的流程是这样的:

  1. 在每个单词后面增加一个分隔符。
  2. 用Character-level Tokenization构建一个初始词表。
  3. 计算频率最高的字符模式,将新字符融入词表。
  4. 重复3,直到下一最高频字符模式频率为1。

举个例子,我们的语料是——“The thread shows the meaning.”,首先我们将之处理为“The/thread/shows/the/meaning”。首先构建起最基础的词表:

词表 频率
t 3
h 4
e 4
r 1
a 2
d 1
s 2
o 1
w 1
m 1
n 2
i 1
g 1

随后寻找到最高频的字符模式:

词表 频率
t 3-3=0
h 4-3=1
e 4
r 1
a 2
d 1
s 2
o 1
w 1
m 1
n 2
i 1
g 1
th 3

然后:

词表 频率
h 1
e 4-2-2=0
r 1
a 2-2=0
d 1
s 2
o 1
w 1
m 1
n 2
i 1
g 1
th 3-2=1
the 2
ea 2

这便是我们的词表了:

词表 频率
h 1
r 1
d 1
s 2
o 1
w 1
m 1
n 2
i 1
g 1
th 1
the 2
ea 2

这个方法在char-level和word-level中找到了一个平衡点,只要输入语料够大,就能够学到语言的基础模式,不仅能够规避OOV问题,也能够让词表不至于过于庞大。

当然,这个分词方法对于英语非常有效,但是对于其他语言则无能为力。

于是,后来出现了一个新的分词方法——BBPE(Byte-level BPE),通过在文本的Unicode编码基础上进行BPE,支持了几乎全部的语言以及Emoji。

词嵌入

通过分词,我们将语料转化为了一些基础单元,现在我们要做的是,将这些基本单元转化为向量形式,这些向量就被叫做词向量。

一个很显然的嵌入方法是one-hot编码。比如词表中有3个词:我、爱、你。那么这三个词的向量表示为:$(1,0,0),(0,1,0),(0,0,1)$。one-hot就是指向量中只有1位是1,其它都是0。这种编码的好处是简单、方便,但是其问题也显而易见——这种编码会占用大量的空间。比如,如果一个词表很大,那么处理它的模型的参数也就很多,我们需要一种更稠密的嵌入方式。当然,one-hot编码也完全忽视了单词的语义信息。在词向量空间中,含义相近的单词,它们的向量表示也需要尽可能地靠近。

一个很重要的嵌入方式是word2vec。这种嵌入方式不仅让词向量维度变低,也能够照顾到词向量的语义信息。word2vec的两类模型是Skip-gram和CBOW(Continuous Bag-of-Words,连续词袋)。word2vec本质上是一个FFN,一个输入层为$V$维,隐藏层为$H$维,输出层为$V$维的FFN,其中$V$是词表大小,$H$是词向量目标维度。

Skip-gram模型,是借助当前位置的单个词预测周边单词,从而获得当前位置单词词向量的过程。首先,我们将单词的one-hot表示输入FFN,通过隐藏层得到词向量,然后在输出层经过Softmax函数的运算,获得$V$维向量,其中每个数字代表该数字下标所对应单词是当前单词的上下文的概率。比如输出向量的第$i$个数字是0.5,那么就代表词表中第$i$个单词是当前单词上下文的概率为0.5。

CBOW模型,是借助周边单词预测当前位置单词,从而获得当前位置单词词向量的过程。首先,将周边单词都通过隐藏层进行运算,将结果相加,通过输出层进行运算,经过Softmax得到一个向量,这个向量的最大概率下标就是预测的单词。

文章作者:
文章链接: https://www.coderlock.site/2025/08/17/Rethink-AI【5】:词嵌入技术/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 寒夜雨