嵌入 (opens new window)是数据的数值表示,捕捉了单词或短语的语义本质。这些嵌入被编码为高维向量,可以在各种数据应用中进行高效处理。嵌入可以根据所使用的模型而有所不同。如果使用不同的模型生成,相同的文本可能具有不同的嵌入。虽然文本数据是主要关注的对象,但嵌入不仅限于文本信息;它们也可以应用于图像、图形和其他数据类型。
在向量数据库 (opens new window)的背景下,嵌入更具价值;我们可以对它们应用基本的相似性/距离度量,以检查一对文本(或其他数据)的相似性或不相似性,我们还可以使用它们找到最相关的样本等。它们的使用非常重要,而不需要太多的背景知识。
在本博客中,我们将探讨如何使用流行的模型(如 OpenAI、Jina 和 Bedrock)生成和使用嵌入。MyScale 的 EmbedText() 函数提供了一种简化的方法来处理嵌入,特别是在处理大规模数据时。通过利用这个工具,您可以将基于嵌入的搜索和其他文本处理能力无缝集成到您的应用程序中,同时受益于 MyScale 的性能和经济性。
# 嵌入模型
传统上,我们有一些经典的嵌入模型,如 Word2Vec (opens new window)、GloVe (opens new window) 和 LSA (opens new window)。后来,它们逐渐被基于 RNN/LSTM 的模型取代。变压器的无与伦比的能力带来了另一个范式转变,现在变压器是嵌入的事实标准模型。为了生成嵌入,我们可以采用一些方法:
- 训练模型:如果您有足够的计算资源,或者可能存在数据隐私等问题,本地训练是一个不错的选择。在这里,训练不一定意味着从头开始训练一个模型,还包括微调(我们大多数时间都这样做)。一旦训练完成,我们就可以使用这个模型来生成嵌入。
- 使用预训练模型:通常情况下,我们不需要为嵌入训练或甚至微调一个模型。有一组标准模型在大多数情况下用于嵌入生成,如 GPT 系列、一些 SLM(如 Phi 系列、Titan、Llama 和 Falcon 等)。
对于预训练模型,我们有一些选择。如果您喜欢在本地运行它们(推理不一定需要 GPU,所以普通笔记本电脑就可以),HuggingFace 模型是一个很好的选择。另一方面,我们也有很多云服务提供这些嵌入模型。OpenAI、Cohere 和 Jina 是一些很好的例子。这些服务有用的另一个原因是一些最先进的模型不可用(如 GPT-4 系列)。
# 在 HuggingFace 上使用模型
许多变压器模型托管在Hugging Face (opens new window)上,包括用于嵌入的模型。要使用 Hugging Face 模型,我们需要调用相应的模型和分词器。这些模型可能需要一些时间来下载。一旦下载完成,它们将保留在缓存中,并可以使用 PyCharm 的 Hugging Face 控制台进行管理。
from transformers import AutoModel, AutoTokenizer
modelName = "TencentBAC/Conan-embedding-v1"
tokenizer = AutoTokenizer.from_pretrained(modelName)
model = AutoModel.from_pretrained(modelName)
text = "All human beings are born free and equal in dignity and rights. They are endowed with reason and conscience and should act towards one another in a spirit of brotherhood."
inputs = tokenizer(text, return_tensors="pt")
tokenEmbeddings = model(**inputs).last_hidden_state
将这些令牌嵌入转换为句子嵌入将非常有用。
sentenceEmbedding = tokenEmbeddings.mean(dim=1)
sentenceEmbedding[0]
使用 Hugging Face 生成嵌入非常好,但在某些情况下可能会有些麻烦,比如:
- 资源有限:通常情况下,Hugging Face 模型不占用太多空间(平均 1 GB),但如果您的磁盘或内存不足,可能不可行。
- 某些模型不可用:虽然很多模型都托管在 Hugging Face 上,但仍然有一些模型托管在专用服务上(例如 GPT-4 很快就会想到,但还有其他一些)。
为了远程使用这些模型,我们使用不同的服务,如 OpenAI、Amazon Bedrock、Cohere 等。我们可以与 MyScale 一起使用它们,正如我们将看到的那样。
# 使用 MyScale 获取嵌入
正如我们所讨论的,嵌入是向量数据库应用的核心。MyScale 提供了一个名为 EmbedText 的功能,可以使用包括 OpenAI、Cohere、Jina 等在内的多种服务来计算嵌入(目前仅支持文本)。这种集成非常有帮助,因为它简化了将文本转换为向量的过程。它支持高吞吐量的自动批处理,对实时搜索和批处理都很有用。这个函数需要一些关键参数:
text
:我们希望计算嵌入的文本字符串。例如,'Thou canst not then be false to any man.'
。provider
:嵌入模型提供者的名称(目前支持 8 个,不区分大小写)。例如,OpenAI
。api_key
:相应提供者帐户的 API 密钥。它由服务直接提供,与 MyScale 无关。
注意:所有这些嵌入服务都是基于令牌使用费用计算的,因此避免重复计算相同的嵌入非常重要。相反,一旦生成,应将嵌入保存在数据库中以便高效重用。
除了这些参数,我们还有一个可选参数 base_url
(大多数提供者不需要)。
# 使用 OpenAI 模型
以下代码片段展示了如何使用 EmbedText()
来使用 OpenAI 的嵌入:
SELECT EmbedText('<input-text>', 'openAI', '', '<Access Key>', '{"model":"text-embedding-3-small", "batch_size":"50"}')
这里还有 API URL、输出向量维度和用户 ID 的可选参数。OpenAI 提供了 3 个嵌入模型,Ada-002 和 Embedding-3(小型和大型)。正如您所看到的,大型版本产生了一个 3072 维的嵌入向量,具有更好的分辨率,在处理较大文档时非常有用。
模型 | 描述 | 输出维度 |
---|---|---|
text-embedding-3-large | 对英语和非英语任务都非常有能力的嵌入模型 | 3,072 |
text-embedding-3-small | 在第二代 Ada 嵌入模型的基础上提高了性能 | 1,536 |
text-embedding-ada-002 | 最强大的第二代嵌入模型,替代了 16 个第一代模型 | 1,536 |
为了展示即使是较小的模型的能力,让我们拿一大段文本(整个章节)并生成它的嵌入。
service_provider = 'OpenAI'
textInput = 'We will leave Danglars struggling with the demon of hatred, and\\r\\nendeavoring to insinuate in the ear of the shipowner some evil...' #truncated here deliberately
parameters = {'sampleString': textInput, 'serviceProvider': service_provider}
x = client.query("""
SELECT EmbedText({sampleString:String}, {serviceProvider:String}, '', 'sk-xxxxxxxx', '{"model":"text-embedding-3-small", "batch_size":"50"}')
""", parameters=parameters)
print(x.result_rows[0][0])
注意:EmbedText()
可以处理长达 5600 个字符的文本。
这里我们将 result_rows[0][0]
作为使用 result_rows
直接获取会带来不必要的列表和元组嵌套。
# 使用 Bedrock 模型
Amazon Bedrock 提供了许多基础模型供用户使用。在使用任何模型之前,您需要先获取它的访问权限(这非常简单)。然后,我们可以直接从 MyScale 中调用它:
SELECT EmbedText('<input-text>', 'Bedrock', '', '<SECRET_ACCESS_KEY>', '{"model":"amazon.titan-embed-text-v1", "region_name":"us-east-1", "access_key_id":"ACCESS_KEY_ID"}')
以下示例将进一步说明。
client.command("""
CREATE TABLE IF NOT EXISTS EmbeddingsCollection (
id UUID,
sentences String, -- 用于存储文本数据的文本字段
embeddings Array(Float32),
--CONSTRAINT check_data_length CHECK length(embeddings) = 1536
) ENGINE = MergeTree()
ORDER BY id;
""")
EmbeddingsCollection
很快就会有帮助,因为我们将在其中保存生成的嵌入。我们将获取一些随机的文本样本并计算它们的嵌入。
service_provider = 'Bedrock'
embeddingModel = 'amazon.titan-embed-text-v1'
embeddingsList = []
for i in range(500, 1000, 30):
randomLine = hamletLines[i]
parameters = {'sampleString': randomLine, 'serviceProvider': service_provider, 'model': embeddingModel}
if len(randomLine) < 30: #忽略太小的段落。
continue
else:
x = client.query("""
SELECT EmbedText({sampleString:String}, {serviceProvider:String}, '', '12PXA8xxxxxxxxxxx', '{"model":"amazon.titan-embed-text-v1", "region_name":"us-east-1", "access_key_id":"AKIxxxxxxxx"}')
""", parameters=parameters)
_id = client.query("""SELECT generateUUIDv4()
""")
embeddingsList.append((_id.result_rows[0][0], randomLine, x.result_rows[0][0]))
正如您所看到的,我们在附加时采用了与提取嵌入向量相同的 UUID(UUID 是单个对象)。现在,这个 embeddingsList
可以插入到表中,并进一步用于许多任务,如相似性搜索等。
# 使用 Jina 模型
Jina 是一个相对较新的服务。要使用 Jina 服务,我们可以指定输入文本、访问密钥和模型。MyScale 中的默认模型是 jina-embeddings-v2-base-en
,它返回 768 维的嵌入,与其他模型相比分辨率较低。
SELECT EmbedText('<input-text>', 'jina', '', '<access key>', '{"model":"jina-embeddings-v2-base-en"}')
这里是一个例子。正如您所看到的,它几乎与我们使用其他提供者时所做的一样。EmbedText()
允许我们封装提供者,感觉上我们使用的是更多或更少相同的服务。
service_provider = 'jina'
textInput = "The Astronomer's Telegram (ATel) is an internet-based short-notice publication service for quickly disseminating information on new astronomical observations.[1][2] Examples include gamma-ray bursts,[3][4] gravitational microlensing, supernovae, novae, or X-ray transients, but there are no restrictions on content matter. Telegrams are available instantly on the service's website, and distributed to subscribers via email digest within 24 hours' #truncated here deliberately"
parameters = {'sampleString': textInput, 'serviceProvider': service_provider}
x = client.query("""
SELECT EmbedText({sampleString:String}, {serviceProvider:String}, '', 'jina_faxxxxxxx', '{"model":"jina-embeddings-v2-base-en"}')
""", parameters=parameters)
x.result_rows[0][0]
# 使用 MyScale 处理嵌入
我们已经知道如何使用 EmbedText()
获取这些嵌入,现在让我们看看如何使用它们。由于生成这些嵌入需要一些成本,我们必须在生成后立即将它们保存在数据库中。这在 MyScale 中非常简单。创建一个表并将嵌入插入其中。
client.command("""
CREATE TABLE IF NOT EXISTS EmbeddingsCollection (
id UUID,
sentences String, -- 用于存储文本数据的文本字段
embeddings Array(Float32),
--CONSTRAINT check_data_length CHECK length(embeddings) = 1536
) ENGINE = MergeTree()
ORDER BY id;
""")
由于我们已经有了 ID、输入文本和相应嵌入的数据帧。我们可以简单地调用 itertuples()
并使用相应的方法插入它。
df_records = list(df.itertuples(index=False, name=None))
client.insert("EmbeddingsCollection", df_records, column_names=["id", "sentences", "embeddings"])
现在有了表中的数据,我们可以添加向量索引。这个索引很快就会在相似性搜索中有用。
client.command("""
ALTER TABLE EmbeddingsCollection
ADD VECTOR INDEX cosine_idx embeddings
TYPE MSTG
('metric_type=Cosine')
""")
# 效率
完成了主要工作后,很容易看出嵌入为什么如此有用,以及 MyScale 为什么如此高效。例如,在整本书中执行一些搜索只需几秒钟的时间,展示了 MyScale 的效率和速度。
service_provider = 'jina'
queryString = "
parameters = {'sampleString': queryString, 'serviceProvider': service_provider}
x = client.query("""
SELECT EmbedText({sampleString:String}, {serviceProvider:String}, '', 'jina_faxxxxxxx', '{"model":"jina-embeddings-v2-base-en"}')
""", parameters=parameters)
queryEmbeddings = x.result_rows[0][0]
results = client.query(f"""
SELECT id, sentences, embeddings,
distance(embeddings, {queryEmbeddings}) as dist
FROM BookEmbeddings
ORDER BY dist LIMIT 3
""")
df = pd.DataFrame(results.result_rows)
使用传统的 NLP 模型,这样的快速处理将是具有挑战性的。此外,MyScale 的功能不仅限于文本;它还可以处理图像和其他数据类型的嵌入,为应用程序开辟了多种可能性。
由此我们得到了前 3 的结果:
凭借这些显著的优势——嵌入模型的无缝集成、令人印象深刻的性能和成本节省——MyScale 被证明是任何数据驱动应用程序的强大平台。
# 结论
通过利用 MyScale 的 EmbedText()
函数,我们演示了如何将流行的嵌入模型(如 OpenAI、Bedrock 和 Jina)无缝集成到您的应用程序中。在 MyScale 中直接生成和处理嵌入不仅简化了您的工作流程,而且在处理大规模数据时也能提供出色的性能。
例如,在几秒钟内通过一个超过 800 页的书执行相似性搜索展示了 MyScale 的效率和速度。这样的快速处理在传统的 NLP 模型中将是具有挑战性的。此外,MyScale 的功能不仅限于文本;它还可以处理图像和其他数据类型的嵌入,为应用程序开辟了多种可能性。
MyScale 的独特之处不仅在于其性能,还在于其经济性。与其他向量数据库不同,MyScale 提供了出色的灵活性和功能,而不需要昂贵的价格。即使扩展到管理 8000 万个向量,成本仍然非常低,8 个 Pod 的运行费用每小时不到 0.10 美元。
这种经济性使 MyScale 成为初创公司和已建立的企业的理想选择,而不会损害财务。实质上,MyScale 使您能够充分发挥嵌入的潜力,为现代数据应用提供了强大、可扩展和经济实惠的解决方案。