当前位置: 首页 > article >正文

transformer学习笔记-词嵌入embedding原理

.在学习transformer的时候,可以看到,输入通常需要对词token进行embedding处理,如果没有先了解embedding的原理可能会有疑问,这个embedding,到底怎么来的,怎么就把一个token 变成一个矩阵,这个矩阵到底暗藏了哪些信息。总不能随便给一个token配一个矩阵,self-attention机制就能处理吧?肯定不是的,接下来我们来尝试理解下embedding的奥秘。

一、词嵌入embedding基本原理

在机器学习领域,机器无法直接对自然语言、图片、语音等数据直接处理,往往需要对其进行编码,这里我们只讨论自然语言领域的词token编码。

1.1、one-hot编码

假设我们现在有一个词库(词汇表),里面有五个词[ I , love , programming , in, Python ],我们通过索引下标将其标识出来分别对应
[1, 2, 3, 4 , 5],但是这样的表示方法,基本很难帮助我们去发现他们之间的关系,比如相似性、多义性,所以我们引入向量空间,帮助我们更好表示不同词token,one-hot就是其中一种:
在这里插入图片描述
对于单个词token,比如:I,[ 1, 0, 0, 0, 0] 是个1* n的矩阵, n的值与词汇表中的词token个数相等。

可以看到,当m个token构成的m*n矩阵,起码有如下问题
1、随着词汇量增多,矩阵的维度(n的个数),占用空间将会特别大;
2、矩阵过于稀疏,元素含0太多,无法有效进行矩阵计算(两个矩阵一算内积全是0),比如计算相似性(余弦相似性);

聪明的人类发明了词嵌入embedding解决以上问题。

1.2、embedding编码

对于一个n维(也就是n列)的one-hot编码(),通过一个n*v嵌入矩阵,将n维向量转成v维向量。
在这里插入图片描述
假设这个嵌入矩阵是5 * 3的矩阵,然后对love 和in两个词embedding编码:
在这里插入图片描述

可以发现:
1、嵌入矩阵的行,就是词汇库的词token个数,列就是词token embedding后的维度(列数).,也就是v维向量。
2、one-hot矩阵的中token向量 1所在的位置,就是对应嵌入矩阵的第几行,也就是通过one-hot的index从嵌入矩阵查表。
3、实际上,就是通过嵌入矩阵的变换,将one-hot五维空间,投影到embedding三维空间。

我们如何理解这个embedding矩阵?
盲人摸象的故事我们都听过,每个盲人摸到大象的不同位置,对大象的形容就不一样,但是把不同位置的的形容合并到一起,大致就能说明大象的整体特征:
大象 = 鼻子长 + 耳朵大 + 高大 + 牙齿长]
回到嵌入矩阵,假设不同的列代表不同的特征,同时他也是在三维空间里的坐标如:(1.1,0.2,0.5)
在这里插入图片描述

以苹果为例:在不同场景中可能不一样,可能是水果、可能是手机、也可能是容貌相关的苹果肌。
假设特征1:是水果、特征2:是手机、特征3:是面貌,嵌入矩阵第一行代表苹果,那么

苹果 = 1.1水果 +0.2手机 +0.5*面貌

也就是说,embedding矩阵的每个元素,代表每个特征的权重,
当然我们也可以将其投射到三维空间中,通过位置关系,表示不同词token之间的相似性和关联度,通常我们采用余弦相似性原理:
在这里插入图片描述
也就是两个向量的夹角越小越相似。
回到上面苹果的例子,苹果向量跟水果、手机、面貌的向量位置,决定了在当前预料环境,苹果更可能表示的是哪个特征,也就是词token在空间中的位置,依赖不同语义场景的上下文关系。

实际上,当某一维度的语料越多,词token在空间中的位置就越往该维度调整(夹角越小),位置越靠近。

上面只是对高维稀疏空间投影到低维空间,同样更低维的向量的特征可能被压缩到一起,也可以通过嵌入矩阵将其投射到高维空间,将压缩到一起的特征分离。

那么我们怎么得到这个嵌入矩阵。

二、词嵌入矩阵训练

词嵌入矩阵是通过特定的词嵌入算法训练得到,比如word2vec、FastText、GloVe等,本文我们通过word2vec,大致了解嵌入矩阵的训练过程。

word2vec包含两种算法,一种是C-bow,一种是Skip-Gram,C-bow通过上下文预测目标词,而Skip-Gram通过目标词预测上下文。
当然,此处我们也只了解C-bow的原理,体会下如何得到嵌入矩阵。

在这里插入图片描述
C-bow主要通过上下文去预测中间位置的token,比如当窗口大小为1,以 love和in 两个词预测中间的programming,如果窗口大小为2,则已I 、love和in、Python四个词预测中间的词。具体的预测流程也是通过一个神经网络来实现:

在这里插入图片描述
预测通过 I ,love,in,Python,得到目标值programming
输入层:
输入层的每个词token是以one-hot编码的向量,也就是1*n的矩阵,图中为省空间,竖排展示,实际计算式按[1,0,0,0,0]横向的方式计算。
以上图为例:
分别将I、love、in、Python四个词token的one-hot编码输入嵌入矩阵

嵌入矩阵:
嵌入矩阵的行数与输入向量的列数相等,n列的输入矩阵,对应的嵌入向量就是n行,嵌入矩阵的维度v,也就是嵌入矩阵的列数,因此嵌入矩阵是一个n*v的矩阵。
图中的四个嵌入矩阵其实是同一个,图中为了表示每个词token单独计算词向量,此处我们使用上面的例子,我们初始化一个 5*3 的嵌入矩阵:(假设下图中的元素值都是随机生成的)
在这里插入图片描述
通过嵌入矩阵的变换,得到四个嵌入向量:I [1.1, 0.2 ,0.5],love [-1.7, 0.8 ,0.1],in [0.1, 0.9 ,-0.3],Python[1.3, -0.4 ,0.8]
在这里插入图片描述

隐藏层:
隐藏层对上下文中的嵌入向量求和取平均值,
这里,我们对得到四个对应的嵌入向量 ,求和再平均:
在这里插入图片描述
得到矩阵[0.2 ,0.375, 0.275]
然后在通过一个v*n的矩阵(一般使用嵌入矩阵的转置)然后通过softmax函数计算词库中每个词的概率分布
在这里插入图片描述
输出层
得到词汇表中每个词的概率输出,概率最大的词即为预测的值,此处0.5最高,对应第三个词programming。
但是预测值与真实值相差较大,那么需要根据损失函数反向传播调整嵌入矩阵。可以参考:transformer学习笔记-神经网络原理第二章和第三章。
经过多轮的反向传播调整后,得到最终的嵌入矩阵。

注意: 通过word2vec生成词嵌入,是比较固定的,因为一旦嵌入矩阵训练完成,除非重新训练,否则就是不变的了,因此在不同语境的句子中,同一个词的词嵌入是一样的,即便这个词嵌入同时包含了不同语境下的信息。因此word2vec在处理多义词场景效果不是很好,基于transformer架构的bert模型更擅长此类场景,bert可以动态结合上下文生成词嵌入。
学习完transformer的机制后,有机会我们再深入学习bert模型原理。本文主要为了通过word2vec更好理解我们为什么需要embedding。

三、示例代码

gensim已经封装了c-bow和skip-gram两种算法的实现,以下是示例代码,感兴趣的小伙伴也可以尝试自己实现一个。

import numpy as np
from gensim.models import Word2Vec
from gensim.utils import simple_preprocess

# 准备数据
sentences = [
    "I love programming in Python",
    "Python is a powerful language",
    "JavaScript is also popular",
]

# 预处理数据
processed_sentences = [simple_preprocess(sentence,min_len=1,max_len=16) for sentence in sentences]

# 训练Word2Vec模型 (c-bow)
model = Word2Vec(sentences=processed_sentences, vector_size=4, window=2, min_count=1, workers=4)
#(skip-gram)
#model = Word2Vec(sentences=processed_sentences, vector_size=4, window=2, min_count=1, workers=4, sg=1)
# 获取词向量
word_vector = model.wv['python']
print(word_vector)

word1 = 'python'
word2 = 'language'

# 使用most_similar方法找到与这两个词最相似的词
similar_words1 = model.wv.most_similar(word1, topn=5)
similar_words2 = model.wv.most_similar(word2, topn=5)

print(f"与 {word1} 最相似的词:")
for word, similarity in similar_words1:
    print(f"{word}: {similarity}")

print(f"\n与 {word2} 最相似的词:")
for word, similarity in similar_words2:
    print(f"{word}: {similarity}")

http://www.kler.cn/a/419272.html

相关文章:

  • Linux下的三种 IO 复用
  • 【青牛科技】2K02 电动工具专用调速电路芯片描述
  • qml项目创建的区别
  • 牛客-尼科彻斯定理、整型数组合并
  • javaScript数据类型存储
  • [OpenHarmony5.0][Docker][环境]OpenHarmony5.0 Docker pull线上镜像方式构建编译环境
  • Y20030012基于php+mysql的药店药品信息管理系统的设计与实现 源码 配置 文档
  • ECharts柱状图-极坐标系下的堆叠柱状图,附视频讲解与代码下载
  • 基于Java实现的潜艇大战游戏
  • 数据集搜集器(百科)008
  • 容器化与 Kubernetes:现代应用的编排与管理
  • LwIP协议栈 基础知识介绍
  • 电商项目高级篇06-缓存
  • 前端将echarts的图和element表格 一起导出到excel中
  • el-tree的使用及控制全选、反选、获取选中
  • 韩顺平 一周学会Linux | Linux 实操篇-组管理和权限管理
  • 根据后台数据结构,构建搜索目录树
  • openssl 基本命令使用方法
  • Oracle之提高PLSQL的执行性能
  • 三十二:网络爬虫的工作原理与应对方式
  • ASP网络安全讲述
  • 易速鲜花聊天客服机器人的开发(上)
  • 一体化数据安全平台uDSP 入选【年度创新安全产品 TOP10】榜单
  • Ubuntu 22.04 LTS vs Ubuntu 24.04 LTS:深度剖析,哪个版本更胜一筹?
  • ORB-SLAM2源码学习:LocalMapping.cc: LocalMapping::MapPointCulling剔除不合格的地图点
  • 使用 Docker 容器创建一个 Web 服务器:从入门到实践