大型语言模型的语义搜索(二):文本嵌入(Text Embeddings)

2024-02-25 09:20

本文主要是介绍大型语言模型的语义搜索(二):文本嵌入(Text Embeddings),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在我写的上一篇博客:关键词搜索中,我们解释了关键词搜索(Keyword Search)的技术,它通过计算问题和文档中重复词汇的数量,来搜索与问题相关的文档,常用的关键词搜索算法是Okapi BM25,简称BM25,关键词搜索算法的局限性在与它并不是根据文本本身的语义来进行文档搜索的,当文档与问题在语义上相关,但它们之间却没有重复词汇时,关键词搜索算法失效,它将无法搜索到该相关文档。为了解决这个问题,我们应该让机器理解文本本身的语义,然后根据文本的语义去搜索相关文档,这就引出了下面我们要解释的文本嵌入(Text Embeddings)的概念。

一、环境配置

我们需要安装如下的python包:

pip install cohere umap-learn altair datasets

这里简单介绍一下cohere是一家从事大模型应用开发的公司,接下来我们需要导入一些基础配置,这些基础配置主要包含cohere的api_key:

import os
import cohere
import pandas as pd
from dotenv import load_dotenv, find_dotenv#导入cohere的api_key
_ = load_dotenv(find_dotenv()) # read local .env file#创建cohere的Client
co = cohere.Client(os.environ['COHERE_API_KEY'])

这里需要说明一下的是关于COHERE_API_KEY我们需要去cohere的网站自己注册一个cohere账号然后自己创建一个自己的api_key。

二、词嵌入(Word Embedding)

要了解什么是词嵌入,我们先来看下面这个例子,我们有一个二维的网格坐标图,上面摆放了各种物品,接下来我想要将一个apple(苹果)放入到这个网格中,请选择一个合适的位置,如下图所示:

仔细观察这个网格,在左上角是各种球类,左下角是各种建筑,右下角是各种交通工具,而右上角是各种水果,很显然apple应该放入到右上角,因为它属于水果,所以apple需要远离球类,建筑,交通工具,它需要和水果类的物品放在一起,最合适的位置应该是(5,5),如下图所示:

将一个词汇放入到词向量空间中的一个合适的位置这就是所谓的词嵌入(Word Embedding) ,在上图中我们用两个数值表示一个词汇在二维平面中的位置如apple(5,5),banana(6,5),car(6,0)等,但在实际的应用中一个词汇可能需要使用几百个,甚至几千个数字来表示其在多维空间中的位置,如下图所示:

一个好的词嵌入应该具备以下一些性质:

  • 性质1:含义相似的词汇它们在多维空间中的位置应该相互接近(或者说它们有较高的相似度的分数)。
  • 性质2:含义不同的词汇它们在多维空间中的位置应该相互远离(或者说它们有较底的相似度的分数)。

词嵌入与词汇的特征的捕捉

上面介绍的关于词嵌入的例子似乎满足了性质1和性质2,但这远远还不够,因为它只捕捉了词义的相似性特征,在一般情况下我们需要捕捉词汇中的更多特征,在自然语言中,单词可以组合起来得到更复杂的含义。在数学中,数字可以相加或相减得到其他数字。我们能否构建一个词嵌入来捕获单词之间的关系,就像数字之间的关系一样?

让我们看一下四个单词:“Puppy(小狗)”、“Dog(狗)”、“Calf(小牛)”和“Cow(牛)”。这些单词之间有着明显的相关性。现在我们将在平面网格中放入单词“Puppy”、“Dog”和“Calf”,然后希望您在网格中添加单词“Cow”。现在有三个可以先选择的位置 A、B 或 C 的位置,你会选择哪一个?

您可能会将“Cow(牛)”放入到位置 A 中,因为这样它会更接近“Calf(小牛)”,因为它们都是牛,或者放到位置在 B 中,因为它是成年动物,如“Dog(狗)”,但最合理的位置应该是C ,即坐标[3,4]。因为这四个词形成的矩形平面体现了词汇之间的一些非常重要的关系。例如,这里会有两个类比。类比“小狗之于狗,就像小牛之于牛”可以理解为“从单词“Puppy(小狗)”到单词“Dog(狗)”的路径与从单词“Calf(小牛)”到单词“Cow(牛)”的路径相同”。“狗之于牛,就像小狗之于小牛”的类比也体现在这个矩形中,如下图所示:

然而,这还不足以成为冰山一角。此处词嵌入的主要属性是两个轴(垂直和水平)它们代表不同的含义。仔细看,向右移动,小狗变成了狗,小牛变成了牛,这是随年龄的增长产生的变化。同样,向上移动会将小狗变成小牛,将狗变成牛,这是随动物体型的增大产生的变化。因此这种嵌入是在理解了单词包含的两个主要属性或特征:年龄和大小。此外,词嵌入似乎将年龄定位在横轴上,将大小定位在竖轴上。那么,你会想象“whale(鲸鱼)”这个词应该放置在什么位置?可能在“Cow(牛)”这个词上面的某个地方。如果有一个词可以形容“一条老狗”呢?这个词会出现在“dog”这个词右边的某个地方:

 一个好的词嵌入不仅能够捕获年龄和大小,还能捕获单词的更多特征。由于每个特征都是一个新轴或坐标,因此良好的嵌入模型必须为每个单词分配两个以上的坐标。例如,Cohere 嵌入模型具有与每个单词关联的 4096 个维度。不同的维度可能代表单词的一些重要属性,例如年龄、性别、大小。有些可能代表属性的组合。但还有一些可能代表人类可能无法理解的晦涩属性。但总而言之,词嵌入可以被视为将人类语言(单词)翻译成计算机语言(数字)的好方法。

下面我们来看看如何在python中如何实现词嵌入,这里我们会使用cohere的词嵌入模型embed-english-v2.0,不过仍然还有很多开源的embedding模型可以使用,比如我之前博客中多次使用的bge的embedding模型,它不仅支持英文也能支持中文。不过这里我们出于演示的目的我们使用的是仅支持英文的cohere的词嵌入模型embed-english-v2.0,下面我们首先创建一个包含3个单词的dataframe:

import pandas as pdthree_words = pd.DataFrame({'text':['joy','happiness','potato']})three_words

这里我们有3个单词:“joy”、“happiness”、“potato”, 接下来我们调用cohere的embedding模型对这3个单词进行向量化,并查看每个词向量的长度:

three_words_emb = co.embed(texts=list(three_words['text']),model='embed-english-v2.0').embeddingsword_1 = three_words_emb[0]
word_2 = three_words_emb[1]
word_3 = three_words_emb[2]print(len(word_1))
print(len(word_2))
print(len(word_3))

这里我们看到每个词向量的长度都是4096,也就是说在cohere中一个英文单词可以由4096个维度特征来表示,下面我们看看词向量的具体向量值是多少:

word_1[:10]

这里我们查看了“word_1”前10个维度的值,它们都是由0附近的浮点数组成。

二、句子嵌入(Sentence Embeddings)

词嵌入看起来非常有用,但实际上,人类语言比简单的一堆单词放在一起要复杂得多。一个单词摆放在一个句子中的不同位置可能给这个句子带来不同的含义,句子要比单词更能清晰的表达出人类语言的含义,句子嵌入就像单词嵌入一样,只不过它以连贯的方式将每个句子与充满数字的向量相关联。这里所说的连贯性是指它满足与词嵌入类似的属性。例如,内容相似的句子被分配给相似的向量,不同的句子被分配给不同的向量,最重要的是,向量的每个坐标都标识了句子的一些(无论是清晰的还是模糊的)属性:

在上图中句子“Hello, how are you?”与句子“Hi, how's it going?”在英语中都表示朋友见面时相互打招呼的意思,因此这两个句子含义相同它们会被分配相似的向量值。而cohere的embedding模型采用“transformers”, “attention ”机制以及其他一些尖端算法,它会将一个句子转换成4096个维度的向量。下面我们来看看如何在python中实现cohere的Sentence Embeddings:

sentences = pd.DataFrame({'text':['Where is the world cup?','The world cup is in Qatar','What color is the sky?','The sky is blue','Where does the bear live?','The bear lives in the the woods','What is an apple?','An apple is a fruit',]})sentences

这里我们生成了一组句子,这组句子由4个问题和4个答案组成,显然问题答案与问题之间是相互关联的,下面我们对这些句子进行向量化处理,然后我们查看以下这些句子向量的前3个维度的向量值:

emb = co.embed(texts=list(sentences['text']),model='embed-english-v2.0').embeddings# Explore the 10 first entries of the embeddings of the 3 sentences:
for e in emb:print(e[:3])

 下面我们来查看一下每个句子向量的长度:

for e in emb:print(len(e))

这里我们看到8个句子的向量长度都是4096,接下来我们对些句子向量进行可视化,我们通过UMAP(uniform manifold approximation and projection)算法对句子向量的4096个维度进行降维后画出句子向量的散点图,UMAP算法是近年来新出现的一种相对灵活的非线性降维算法,目前在统计遗传学等领域也有了较为广泛的应用。接下来我们首先定义一个绘图函数,然后我们会利用这个绘图函数来画出这8个句子向量的散点图,当我们单击图中的某个点时将会看到对应的句子内容:

import umap
import altair as altdef umap_plot(text, emb):cols = list(text.columns)reducer = umap.UMAP(n_neighbors=2)umap_embeds = reducer.fit_transform(emb)df_explore = text.copy()df_explore['x'] = umap_embeds[:,0]df_explore['y'] = umap_embeds[:,1]# Plotchart = alt.Chart(df_explore).mark_circle(size=60).encode(x=#'x',alt.X('x',scale=alt.Scale(zero=False)),y=alt.Y('y',scale=alt.Scale(zero=False)),tooltip=cols#tooltip=['text']).properties(width=700,height=400)return chartchart = umap_plot(sentences, emb)
chart.interactive()

从输出图像上看,句子内容相关的向量点都相互靠的很近,而句子内容不相关的点都相互远离。这也进一步说明句子嵌入能更好的从语义上识别内容相关的句子。

三、文章嵌入

上面我们介绍了单一句子嵌入,同样我们也可以实现多个句子的嵌入,即文章嵌入,接下来我们导入一个已做嵌入的维基百科文章的数据集,然后对文章向量进行可视化:

import pandas as pdwiki_articles = pd.read_pickle('wikipedia.pkl')
wiki_articles

 接下来我们根据该数据集的emb字段来绘制散点图,图中的每一个点表示wiki_articles的一个text,不过首先我们需要定义一个绘图函数umap_plot_big,在函数中我们调用umap的降维算法将原先的4096个维度降到两个维度,这样我们才能在二维平面中画出散点图:

import numpy as npdef umap_plot_big(text, emb):cols = list(text.columns)reducer = umap.UMAP(n_neighbors=100)umap_embeds = reducer.fit_transform(emb)df_explore = text.copy()df_explore['x'] = umap_embeds[:,0]df_explore['y'] = umap_embeds[:,1]# Plotchart = alt.Chart(df_explore).mark_circle(size=60).encode(x=#'x',alt.X('x',scale=alt.Scale(zero=False)),y=alt.Y('y',scale=alt.Scale(zero=False)),tooltip=cols#tooltip=['text']).properties(width=700,height=400)return chartarticles = wiki_articles[['title', 'text']]
embeds = np.array([d for d in wiki_articles['emb']])chart = umap_plot_big(articles, embeds)
chart.interactive()

当我们单击图中某个点时将会看到对应的title 和 text:

四、总结

单词和句子嵌入是大型语言模型(LLM)的主要工作。它们是大多数语言模型的基础构件,它通过捕获了单词、语义和语言细微差别之间的许多关系,并将其转换为有关相应数字,从而将人类语言(单词)翻译为计算机能理解的语言(数字)。

 

这篇关于大型语言模型的语义搜索(二):文本嵌入(Text Embeddings)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/745053

相关文章

Go语言中nil判断的注意事项(最新推荐)

《Go语言中nil判断的注意事项(最新推荐)》本文给大家介绍Go语言中nil判断的注意事项,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1.接口变量的特殊行为2.nil的合法类型3.nil值的实用行为4.自定义类型与nil5.反射判断nil6.函数返回的

Go语言数据库编程GORM 的基本使用详解

《Go语言数据库编程GORM的基本使用详解》GORM是Go语言流行的ORM框架,封装database/sql,支持自动迁移、关联、事务等,提供CRUD、条件查询、钩子函数、日志等功能,简化数据库操作... 目录一、安装与初始化1. 安装 GORM 及数据库驱动2. 建立数据库连接二、定义模型结构体三、自动迁

Mysql中isnull,ifnull,nullif的用法及语义详解

《Mysql中isnull,ifnull,nullif的用法及语义详解》MySQL中ISNULL判断表达式是否为NULL,IFNULL替换NULL值为指定值,NULLIF在表达式相等时返回NULL,用... 目录mysql中isnull,ifnull,nullif的用法1. ISNULL(expr) → 判

Go语言代码格式化的技巧分享

《Go语言代码格式化的技巧分享》在Go语言的开发过程中,代码格式化是一个看似细微却至关重要的环节,良好的代码格式化不仅能提升代码的可读性,还能促进团队协作,减少因代码风格差异引发的问题,Go在代码格式... 目录一、Go 语言代码格式化的重要性二、Go 语言代码格式化工具:gofmt 与 go fmt(一)

Python中图片与PDF识别文本(OCR)的全面指南

《Python中图片与PDF识别文本(OCR)的全面指南》在数据爆炸时代,80%的企业数据以非结构化形式存在,其中PDF和图像是最主要的载体,本文将深入探索Python中OCR技术如何将这些数字纸张转... 目录一、OCR技术核心原理二、python图像识别四大工具库1. Pytesseract - 经典O

苹果macOS 26 Tahoe主题功能大升级:可定制图标/高亮文本/文件夹颜色

《苹果macOS26Tahoe主题功能大升级:可定制图标/高亮文本/文件夹颜色》在整体系统设计方面,macOS26采用了全新的玻璃质感视觉风格,应用于Dock栏、应用图标以及桌面小部件等多个界面... 科技媒体 MACRumors 昨日(6 月 13 日)发布博文,报道称在 macOS 26 Tahoe 中

HTML5 搜索框Search Box详解

《HTML5搜索框SearchBox详解》HTML5的搜索框是一个强大的工具,能够有效提升用户体验,通过结合自动补全功能和适当的样式,可以创建出既美观又实用的搜索界面,这篇文章给大家介绍HTML5... html5 搜索框(Search Box)详解搜索框是一个用于输入查询内容的控件,通常用于网站或应用程

Python实现精准提取 PDF中的文本,表格与图片

《Python实现精准提取PDF中的文本,表格与图片》在实际的系统开发中,处理PDF文件不仅限于读取整页文本,还有提取文档中的表格数据,图片或特定区域的内容,下面我们来看看如何使用Python实... 目录安装 python 库提取 PDF 文本内容:获取整页文本与指定区域内容获取页面上的所有文本内容获取

Go语言中泄漏缓冲区的问题解决

《Go语言中泄漏缓冲区的问题解决》缓冲区是一种常见的数据结构,常被用于在不同的并发单元之间传递数据,然而,若缓冲区使用不当,就可能引发泄漏缓冲区问题,本文就来介绍一下问题的解决,感兴趣的可以了解一下... 目录引言泄漏缓冲区的基本概念代码示例:泄漏缓冲区的产生项目场景:Web 服务器中的请求缓冲场景描述代码

Go语言如何判断两张图片的相似度

《Go语言如何判断两张图片的相似度》这篇文章主要为大家详细介绍了Go语言如何中实现判断两张图片的相似度的两种方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 在介绍技术细节前,我们先来看看图片对比在哪些场景下可以用得到:图片去重:自动删除重复图片,为存储空间"瘦身"。想象你是一个