有一天,一个出售身世的老板问我:你能解说下“词向量”吗?
经过攀谈得知,老板是做保险业务的。他发现用户会咨询许多手册上的根底问题,这需求业务员一对一进行回复。所以,他想让体系自动回复,从而削减本钱。
老板手里有许多行业材料,但做了几个版别都不如意。上一个版别是经过字符串匹配完成的。这种办法,问不到要害词,体系就答不上。比方,问“高血压”,体系能给出答案。问“三高”,就找不到了。所以,他们只能去后台将“三高”做相关。但是,词海苍茫,此伏彼起。
这个版别,技能人员说采用了词向量,老板想知道这是啥?靠不靠谱?
下面,我就来完成一个问答匹配的例子,然后再详解操作过程、原理。
一、实战作用演示
我在教育行业行走,不懂保险……就拿教育产品来举例吧。
假定咱们有这么一个问答知识库:
- “找回暗码流程阐明”
- “怎样检查我的错题记载”
- “Sorry, an error occurred!”
- ……
用户要找他的错题本,或许会有以下几种问法:
- “我的错题从哪里能够检查?”
- “怎样找到我做错的标题”
- “我没做对的标题怎样查找”
有些问法,甚至不包含“错题”,仅仅说“没做对的标题”。咱们看看,从知识库里能找到吗?
以下是全部代码,用python完成:
# 加载模型
from text2vec import SentenceModel, semantic_search
model = SentenceModel("text2vec")
# 以下是体系的知识库
corpus = [
"找回暗码流程阐明",
"怎样检查我的错题记载",
"Sorry, an error occurred!"]
corpus_embeddings = model.encode(corpus)
# 以下是用户的问题
queries = [
"我的错题从哪里能够检查?",
"怎样找到我做错的标题",
"我没做对的标题怎样查找"]
for query in queries:
query_embedding = model.encode(query)
# 将问题经过模型从知识库匹配,取前3条
hits = semantic_search(query_embedding, corpus_embeddings, top_k=3)
print("\n问题:", query, "\n最优前3条:")
hits = hits[0]
for hit in hits:
print(corpus[hit['corpus_id']], "({:.2f})".format(hit['score']))
运转一下,检查成果:
问题: 我的错题从哪里能够检查?
最优前3条:
怎样检查我的错题记载 (0.84)
Sorry, an error occurred! (0.46)
找回暗码流程阐明 (0.43)
问题: 怎样找到我做错的标题
最优前3条:
怎样检查我的错题记载 (0.80)
Sorry, an error occurred! (0.48)
找回暗码流程阐明 (0.46)
问题: 我没做对的标题怎样查找
最优前3条:
怎样检查我的错题记载 (0.75)
Sorry, an error occurred! (0.48)
找回暗码流程阐明 (0.47)
能够看出,即使发问的要害字不一样,也能够匹配出预期的成果。
咱们能够经过semantic_search
这个办法,对文本进行匹配度核算,实验可得:
问题: 怎样检查我的错题记载
匹配得分:
我的错题从哪里能够检查? (0.84)
怎样找到我做错的标题 (0.80)
我没做对的标题怎样查找 (0.75)
找回暗码流程阐明 (0.44)
……
到这儿,老板们能够回了:词向量比字符串的作用要好,请相信你们的技能。
假如你还想实际操作一下,能够继续往下看。
二、操作过程讲解
上面示例用到了一个text2vec
(文本转向量)类库。
项目开源地址是:github.com/shibing624/… 。
里边有更多的信息,比方它说:
“可免费用做商业用途。请在产品阐明中附加text2vec的链接和授权协议。”
首要,咱们安装它:
pip install torch
pip install -U text2vec
这一步,对应示例代码中的from text2vec import ……
,表明导入类库并调用功用。
然后,咱们需求下载它的模型权重。它能这么智能,是由于项目作者做了许多根底工作。咱们是站在巨人膀子上做事情,需求先把巨人搬到家里来。
模型下载地址:huggingface.co/shibing624/…
假如你只运用(推理),不练习,下载图中标记的4个文件就够了。
下载之后,新建了一个text2vec
(叫啥都行)文件夹,将模型权重仿制进去。
这个文件夹的地址,对应示例代码中,模型文件的加载路径:
model = SentenceModel("text2vec")
小提示:我放在代码的同级目录。你放D盘也行,那代码对应为
SentenceModel("D:\text2vec")
。
最后,新建一个main.py
文件,将示例代码仿制进去,就能运转了。
到这儿,功用应急的小伙伴们能够撤了:这个类库确实能够,简略解决文本匹配的问题。
假如你想进一步问个为什么,能够再继续往下看。
三、技能原理剖析
词向量是大言语模型的必经之路。一问一答之间,尽显词向量的身影。
下面的流程图,便是一个根据本地文档库问答的开源项目。
项目地址是:github.com/imClumsyPan…
这儿面有15个流程,其中3处涉及到了Vector(词向量)。别的还有两处的Embedding,是将文本转为向量的操作,这也和向量有关。
依托于词向量,咱们能够完成从文档中找答案。我把上一篇博客《怎样告知后端身世的领导,前端需求难完成》导入知识库,然后问它文中的问题。它是能回答出来的。
好了,不卖关子了,开始聊聊词向量。
3.1 词向量
词向量难了解的当地不在于“词”,而在于“向量”。
向量,初中数学就开始学。简略来说,便是一个具有“方向”和“巨细”的变量。
上图所示,两人拉车。一个向左,一个向右。瘦子力气小,胖子力气大。力是向量,它有方向和巨细。
向量之间是能够核算的。
有一个著名的平行四边形法则:向量a和向量b一起使劲,作用等同于向量c。
你能够拿拉车的例子来复原:a和b两个人拉车的作用,等同于c一个人。
3.2 维度
上面说的向量是二维向量,也便是有x、y两个维度。
其实也有三维向量。它具有x、y、z三个维度。
2维向量用(x, y)来表明。3维向量用(x, y, z)来表明。一个向量,有几个维度,就有几个维度的数据来描绘它。
所以,你到底想表达什么?
我想表达,其实咱们的词汇也是能用维度来表达的。
3.3 嵌入
来,访问这个地址:projector.tensorflow.org/
上图是10000个词汇,经过200个维度的描绘处理后,投射到3维空间所出现的视觉作用。
下面,咱们随机捕捉一个词man。
咱们发现在这个语料的星系中,能和man产生相关的词语有5778个。
其中有“son”、“uncle”、“father”、“king”这些词。这或许是从人物维度来剖析的,看它们都凑一堆儿。
别的也有“girls”、“love”、“woman”、“angry”这些词,这是啥?man的喜好?
总归,他们之间是有相关的。下面我带我们走进和“他”有关的国际。
能做到如上这些的根底,便是由于这些词汇被向量化了。
man这个词是一个200维度的向量。假如用数据来表明,它应该是这样的:
[5.82528770e-01, 1.65926769e-01, -8.73286307e-01, 1.16382980e+00
-8.05581883e-02, -2.68993825e-01, -5.55128217e-01, -7.28500545e-01
1.19629860e-01, 3.96491200e-01, -5.55124357e-02, ……-2.47849301e-02]
不省掉的话,得有200位数据。
这种将词汇向量化的操作,咱们叫“Embedding”,翻译成中文叫“嵌入”。
“嵌入”这个翻译太硬,我只能解说得软一些:便是给词找一个好的归宿,将它嵌入到适宜的方位。
正是经过Embedding将文本变成了向量。而向量又能进行数学核算。所以,当咱们用多种办法来发问时,到模型这儿一核算,发现是同一个东西,这才完成了殊途同归。
- 比方将“单”界说为1,将“双”、“对”界说为2。你问AI模型:“我单身,又找了一个单身。我俩加一起叫啥?”。AI模型说:“成双成对!”
- 再比方,做如下界说:“男人”(1,0),“权力”(0,1),国王(1,1)。你问AI模型:“我和国王的差异是什么?”。AI模型说:“国王有权力!”
你感觉,哇,好奇特。模型心里想,切,这不便是1+1=2吗?!
上面说到的text2vec
这个开源模型,它所做的便是将文本转为向量。这一步是NLP的基石,十分要害。能否给词汇做好Embedding,决定了AI模型的根本了解力。
假如你要想看一个词的向量值,能够这么操作:
from text2vec import SentenceModel
# 从目录加载离线模型
model = SentenceModel("text2vec")
# 将文本向量化
embeddings = model.encode(['男人'])
print(embeddings.shape, embeddings)
输出成果为:
embeddings.shape: (1, 768)
embeddings: [[ 5.82528770e-01 1.65926769e-01 5.58118522e-01
2.97882259e-02 -3.88074875e-01 7.49602675e-01
-9.67679083e-01 …… -2.47849301e-02]]
embeddings.shape
是数据的形状,这儿表明维度。这框架给每段embedding的文本赋予了768个维度。后边是这768个维度数据的具体值。
前面的那个语料“星云图”,仅仅个学惯用的Demo。下面这个更多、更广,更震慑。
要对这么多数据进行核算,可不是像“1+1=2”这么轻松,其实不简略。
3.4 类似度核算
向量之间的类似度,有许多种核算办法,下面讲一个余弦类似度。
它经过核算两个向量间夹角的余弦值,来评价两者的类似度。
余弦!又来一个数学名词。下面发张图,帮我们温习一下。
看上图,可知:
- 角A变小,c朝向b不断下滑,两者方向共同时,b/c=1。
- 角A变大,c向上抬,b不断变小,两者笔直时,b为0,b/c=0。
- 角A继续变大,成为钝角,直到两者方向相反,b/c=-1。
来个动图,生动地表达目的。
为何要选择这个余弦公式来做类似度的评判?
通俗地讲,便是看两个向量是否一条心:
- 方向共同时,函数值为1。
- 方向相反时,函数值为-1。
- 当方向越来越偏离时,它的函数值也越来越小。
看!它真的是很适宜。
利用text2vec
中的cos_sim
办法,就能够轻松完成余弦类似度的核算。
from text2vec import SentenceModel, cos_sim
# 从目录加载模型
model = SentenceModel("text2vec")
# 转为向量
emb1 = model.encode(["我的错题从哪里能够检查"])
emb2 = model.encode(["怎样检查错题记载"])
# 利用cos_sim核算类似度
cosine_scores = cos_sim(emb1, emb2)
print("Score: {:.2f}".format(cosine_scores[0][0]))
试了两个,成果还行。
[我的错题从哪里能够检查] VS [怎样检查错题记载] Score: 0.79
[我的错题从哪里能够检查] VS [Python是编程言语] Score: 0.24
请注意,余弦类似度是有缺点的:它只评判向量的方向,不重视向量的长度。
这会导致什么问题呢?答案是:重视性质,忽视数量。
举个例子,假如某网店有甲乙丙三个顾客评分如下:
顾客 | 物流快递 | 商品描绘 | 售后服务 |
---|---|---|---|
甲 | 10 | 8 | 6 |
乙 | 7 | 8 | 9 |
丙 | 4 | 2 | 0 |
假如用余弦类似度进行核算,算法会以为丙和甲是一类人。
what?为啥?
由于余弦类似度只重视方向,不重视数值。
甲和丙的方向是共同的:物流快递最好,售后服务最差。它重视的是一种趋势。
假如换一种核算办法,比方欧氏距离。那么它会以为顾客甲和顾客乙是一类人,由于他们的评分距离挨近,都是好评。
上图,从视点来看,A和B更近;从距离看,A和C更近。
好了,今日就说这么多。
上面说的一大堆,其实是专业范畴里一笔带过的内容。我是从里边摘芝麻当冬瓜看,小题大做。
我在做AI的科普工作,这篇文章是 全民AI方案 的第3期。
- 第1期:《尝试你的第一个AI程序》
- 第2期:《文本摘要的完成原理》
但凡您有一丁点儿听不懂,请反应给我。听不懂,必定是我的问题。
我是@TF男孩,一个遍及AI知识的民科IT男。