词的向量化和文本向量化
- 向量化
- one-hot编码
- 提前准备词表
- 不提前准备词表
- one-hot缺点
- 词向量
- 简介
- 词向量的定义和目标
- word embedding和word vector的区别
- onehot编码与词向量关系构建
- 训练方式1(基于语言模型)
- 训练方式2(基于窗口)
- CBOW模型
- SkipGram模型
- 缺点
- 缺点解决方案-Huffman树
- Huffman树构建过程:
- 缺点解决方案-负采样(negative sampling)
- 训练方式3(基于共现矩阵Glove)
- 共现矩阵
- 共现概率
- 共现概率比
- 共现矩阵训练词向量
- 总结
- 训练流程
- 存在的问题
- 词向量应用
- 1. 寻找近义词
- 2. 句向量或文本向量
- KMeans聚类
- 词向量总结
向量化
引子: 向量对于机器学习非常重要,大量的算法都需要基于向量来完成
原因:
对于机器来说,字符是没有含义的,只是有区别
只使用字符无法去刻画字与字、词与词、文本与文本之间的关系
文本转化为向量可以更好地刻画文本之间的关系
而向量化后,可以启用大量的机器学习算法,具有很高的价值
文本向量化: 文本是由词和字组成的,想将文本转化为向量,首先要能够把词和字转化为向量;并且就同一个任务或者模型,向量化的维度应该是相同的
,如果为n维,我们就称是n维语义空间。
如下图: 随机初始化向量后,通过训练,使得表示的向量可以表达词、字之间的语义关系:
one-hot编码
提前准备词表
释义:
1.首先我们会提前准备一个字表或词表,选出n个字或词;
2.然后根据词表的大小,决定向量的维度;
3.通过词的序号,在向量的对应维度上数值设为1,其余维度则为0
举例如下:
那么根据上面的编码,我们就可以将句子用向量表示:
今天不错 --> [1,0,0,1,0]
天气真不错 --> [0,1,1,1,0]
向量化文本时,也可以通过叠加,表示词频含义
今天不错不错 --》 [1,0,0,2,0]
不提前准备词表
引子: one-shot发展到后面,就考虑不准备词表,直接根据材料的字动态给生成。
举例:
假设现在有语料
- 你好吗?
- 你身体好吗?
自动的统计语料中出现的字,然后按照出现,不断的扩大向量的维度,并把新的字表示进去
:
one-hot缺点
- 如果词特别多,编码的向量维度会特别大,维度灾难,并且向量特别稀疏,只有词的地方才有值,这样会带来巨大的计算量
- 编码的向量并没有反应词与词之间的语义关系,只是做到区分不同字词的作用
词向量
简介
词向量的定义和目标
词向量,即我们希望得到一个词之间的向量能够反映语义关系的向量权重信息。
有以下三个维度
1.词义的相似性反映向量的相似性
即有三个词向量: 您好、你好、天气
有:cos(您好,你好) > cos(你好,天气)
2.向量可以通过数值的运算反应词之间的关系
即有四个向量:国王、男人、皇后、女人
有:国王 - 男人 = 皇后 - 女人
3.同时不管词表有多少词,我们希望表示词的语义空间是大小是固定的,即向量的维度相同.
word embedding和word vector的区别
简单来说,两个没有区别,我们知道词向量的作用,是将字符转化为有一定含义向量,便于后续去进行模型的计算。
在这里的区别
embedding业内更强调是将字符转为对应的向量
Word2Vec 强调的是对词向量的训练,使其具有一些特定得含义和作用,即通过向量相似度反映语义得相似度
onehot编码与词向量关系构建
即我们可以将embedding矩阵看成一个线性层
,而onehot作为编码输入,由于onehot编码得稀疏性
,以及只有对应词得序号所在下标才有值,通过和embedding的运算,就可以获取该词的向量了
示意图如下:
训练方式1(基于语言模型)
语言模型释义: 语言模型就是输入几个词,它能预测下一词;预测的下一词由它前面的n个词决定,那么就需要理解词的含义。
比如:
晴空 万里 碧波 如洗 我们 出去 玩 吧
晴空 -->万里
模型根据晴空预测出下一个词万里
本质: 这种预测本质是一个分类的问题
,即我们由一个词表,我们将前面输入的词或者一句话作为分类任务,判别它是属于词表中的词的哪一类;即可达成预测效果。根据词表分类
好处: 我们的分类任务需要标注;但是上述中,我们只需要把前面的n个词输入,将句子的下一个词做输出即可进行训练;降低了标注的工作。
训练方式2(基于窗口)
基于窗口: 如果两个词在文本中出现时,它前后出现的词相似,则这两个词相似,我们可以通过前后的词来表示中间词
如下图所示
释义: 窗口是指需要前后抓取几个词去表示目标词
CBOW模型
基于前述的思想,用窗口中的词(即目标词周围的词)来表示预测中间词
示意图如下:
模型结构:
第一层:即embedding层
第二层:即模型的pooling层
第三层:即线性层将结果转为我们需要的维度
好处:
1.相对于
基于模型的训练,结构很简单,所以训练的资源相对较小
2.相对于基于模型训练出来的embedding,训练的效果,更能体现embedding好;简单说就是,窗口训练的embedding和模型训练出来的,窗口的embedding更能表示词关系
。因为模型简单,效果更依赖于embedding
举例:
窗口:你想明白 了吗?
输入:你想了吗?
输出:明白
SkipGram模型
释义: 与CBOW模型原理类似,区别在于用中间词,去预测两边的词
示意图
举例:
窗口: 你 想 明白 了 吗
(输入,输出) :
(明白,你)(明白,想)(明白,了)(明白,吗)
缺点
在当时提出上述的训练方法时,在最后一层,即将结果映射到词表的维度,由于词表非常的大,并且输出层使用的是onehot(因为预测某个词),所以会面临维度灾难,并且会导致收敛缓慢
当然当前已经不存在这个问题了,因为由于时代的发展,机器的性能提高了很多倍,上面的就变成小kiss
缺点解决方案-Huffman树
Huffman树是对所有词进行二进制编码
,使其符合以下特点:
- 保证不同的词编码不同
- 每一个词的编码不会成为另外一个词编码的前缀(即:某个词的编码011;则不能有词的编码为0110;0111等等)
- 构造出的词编码总体长度最小,且越高频词编码越短
Huffman树构建过程:
1.我们先要将编码的词统计出词频
如下:
你 50
我 10
他 8
你们 7
我们 6
他们 3
它们 2
2.将词构建在二叉树上,将词频由低到高进行构建,先将最小的两个词频的词放到树的两个叉上,节点为两个词频的之后,下一次构建时,则将该二叉树作为一个节点进行比较
如下:
3.有第一个二叉树后,在新的词频上,再次选择最小的两个词频进行二叉树构建,将词频低的放到左侧,高的放到右侧,如果相等,就您随意。如下:
你 50
我 10
他 8
你们 7
我们 6
它们 | 他们 5
构建如下:
4.在第3步的基础上完成新的二叉树构建后,我们在这个基础上进行下一轮构建,直到所有词都在一个树上为止。如下:
你 50
它们 | 他们 | 我们 11
我 10
他 8
你们 7
继续下一轮构建
5.在得到完整的词频构建的树后,我们从初始的节点开始,往右移动一次,则编码为1;往左移动一次,则编码0;最终可以得到下面的结果
Huffman树的编码结果为:
你 1
我 010
他 001
你们 000
我们 0111
他们 01101
它们 01100
达成目标:
1.每个词的编码不同
2.每个词的编码不会成为其他词的前缀
3.词频越高编码长度越短
训练方案
原来的词向量训练中,我们采用三次,embedding、pooling层、一个线性层
困难点: 在线下层需要映射到词表的词上,也就是说线下层的参数为: embedding_size X vector_size
现在我把一个线下层任务,按照上面的Huffman树构建成多个二分类的线性层
;即原来是一次从词表中1万个词中找到预测词;现在我只需要在每层编码,判断下是往左还是往右就
可以了;其次,对于高频的词,编码的短,所有二分类计算的线下层也就少,训练的速度也就更
快
现在线下层的参数:embedding_size X 2 * 词的最长编码数
当然,上面那个例子的参数并没有减少多少;这是因为实际实现中,还需要一些工程上的优化操作。这样就可以快速训练出效果较好的词向量。
缺点解决方案-负采样(negative sampling)
引子: 我们知道词表特别大,导致最后得到预测词的分布,由于预测的分类太多了,所以存在维度爆炸的问题,对机器性能要求很高
解决: 负采样的逻辑即,我们在算预测词分布时,需要算的分类太多了;一次任务训练,其中其实只有一个词是我们要预测的,我们希望预测它的概率接近1,其他的词的概率为0
步骤:
1.如果词表有1万个词;我们正常需要计算embedding_size * 10001词
2.现在每一次训练,我找出需要预测的词,其他非预测词,我木门把它拆成1000词一份,就一个10份
3.那么原来是一次训练计算1万个词;现在我分为10次训练,每次训练计算其中的1001个词;
多出来的这一个词,就我们的要预测的词
那么我们就可以大幅降低模型训练对机器的性能要求了
注意:
上面我们训练10次举个例子,实际中并不是平均分为10份进行训练的,而是随机选择训练的词
,加上预测词训练
即随机选取非预测词的方案就是负采样。
按照词频进行随机采样,有一个经验公式
训练方式3(基于共现矩阵Glove)
释义: 共现,就是说两个词共同出现的次数
共现矩阵
示例
现在有语料:
今天 天气 不错
今天 天气 很 好
天气 很 好
天气 不错
从上面语料中,构建词表:
今天、天气、很、好、不错
我们基于共现窗口为1,即词与左右相邻词算共现:
这样就可以得到,每个词和它相邻词共同出现的次数
共现概率
释义:词(天气)出现在词(今天)周围的概率,被称为词(今天)与词的(天气)共现概率
P(天气|今天) = 2/2 = 1
公式:
共现概率比
释义: 两个共现概率的比值
价值:
共现概率比反映了一定的语义信息
a.如果词A与词B的相关性,大于词A与词C的相关性,则共享概率比 P(A|B)/P(A|C) 会较高,反之亦然
b.P(A|B)/P(A|C)共享概率比较大,或者较小
;都说明B与C有一个词和A的关系更加紧密
c.P(A|B)/P(A|C)共享概率接近1
;要么说明B与C词和A的词关系都很密切,要么都没什么关系
共现矩阵训练词向量
根据共现矩阵的价值,我们就有了新的训练词向量的目标:
1.给定三个词的词向量,Va, Vb, Vc三者的通过某个函数映射后,其比值应接近ABC的共现概率比
2.即目标为找到向量使得 f(Va, Vb, Vc) = P(A|B)/P(A|C)
3.预测数值,属于回归问题, 损失函数使用均方差;设计论文中给出的是f(Va, Vb, Vc) = (Va - Vb )·Vc
总结
训练流程
1、根据词与词之间关系的某种假设,制定训练目标,这个假设不一定完全正确,但是它代表了词与词之间的某种关系。
2、设计模型,以词向量为输入
3、随机初始化词向量,开始训练
4、训练过程中词向量作为参数不断调整,获取一定的语义信息
5、使用训练好的词向量做下游任务
存在的问题
1.词向量是“静态”的。每个词使用固定向量,没有考虑前后文
2.一词多义的情况。西瓜 - 苹果 - 华为
3.影响效果的因素非常多
维度选择、随机初始化、skip-gram/cbow/glove、分词质量、词频截断、未登录词、窗口大小、迭代轮数、停止条件、语料质量等
4.没有好的直接评价指标。常需要用下游任务来评价
词向量应用
1. 寻找近义词
输入:红烧肉
注意:
依赖分词正确,与A最接近的词是B,不代表B最接近的是A,有时也会有反义词很相似
,会有很多badcase
2. 句向量或文本向量
步骤:
1.将一句话或一段文本分成若干个词
2.找到每个词对应的词向量
3.所有词向量加和求平均或通过各种网络模型,得到文本向量
4.使用文本向量计算相似度或进行聚类等
KMeans聚类
步骤:
1.随机选择k个点作为初始质心
2.将每个点指派到最近的质心,形成k个簇,即k类
3.重新计算每个簇(类)的质心 (可以通过求平均等)
4.反复执行2-3步骤,直到质心不在发生变化
KMeans优点:
1.速度很快,可以支持很大量的数据
2.样本均匀特征明显的情况下,效果不错
KMeans缺点:
1.人为设定聚类数量
2.初始化中心影响效果,导致结果不稳定
3.对于个别特殊样本敏感,会大幅影响聚类中心位置
4.不适合多分类或样本较为离散的数据
KMeans使用技巧:
1.先设定较多的聚类类别
2.聚类结束后计算类内平均距离
3.排序后,舍弃类内平均距离较长的类别
4.计算距离时可以尝试欧式距离、余弦距离或其他距离
5.短文本的聚类记得先去重,以及其他预处理
词向量总结
1.质变:将离散的字符转化为连续的数值
2.通过向量的相似度代表语义的相似度
3.词向量的训练基于很多不完全正确的假设,但是据此训练的词向量是有意义的
4.使用无标注的文本的一种好方法