Embeddings

Embedding Model 是一种将高维的数据(例如文本、图像或音频)转换为低维向量表示的机器学习模型。这种低维向量表示通常被称为embedding(嵌入),并且这些向量可以捕捉数据中的语义或特征关系,使得相似的对象在向量空间中更加接近。

Embedding 是自然语言处理(NLP)、计算机视觉等领域中广泛使用的技术,主要用于将离散的输入数据(如单词、句子或图像)转换为稠密的、连续的向量,以便在神经网络等模型中进行处理。

嵌入模型将输入数据表示为一组浮点数向量。向量表示捕捉了数据的关键特征和模式,并用于后续任务中的相似度计算、分类、聚类等任务。例如,在 NLP 中,单词嵌入(word embedding)模型将每个单词表示为一个实数向量。通过这个表示,可以用向量之间的相似度(如欧几里得距离或余弦相似度)来表示单词之间的关系。

image-20241004194411669

示例

使用 amazon.titan-embed-text-v1 模型,可以生成高质量的Embedding

import boto3
import json


client = boto3.client(service_name="bedrock-runtime", region_name="us-west-2")

# 定义要嵌入的文本
fact = "The first moon landing was in 1969."  # 输入的句子,用于生成文本嵌入


# 调用 Bedrock 服务的模型进行文本嵌入
response = client.invoke_model(
    body=json.dumps(
        {
            "inputText": fact,  # 输入文本,需要生成嵌入的内容
        }
    ),
    modelId="amazon.titan-embed-text-v1",  # 使用的模型 ID,生成文本嵌入的 Titan 模型
    accept="application/json",  
    contentType="application/json",  
)

response_body = json.loads(response.get("body").read())
# 从响应中获取嵌入向量
print(response_body.get("embedding"))  # 打印生成的文本嵌入向量

结果:

[0.11376953125, 0.1767578125, 0.08740234375, 0.177734375, -0.1484375, 0.61328125, -0.1181640625, -0.0004329681396484375, 0.66796875, -0.08154296875, 0.51953125, 0.51953125, 0.376953125, -0.8203125, 0.08349609375, -0.09521484375, -0.43359375, 1.125, 0.57421875, 0.353515625, 0.37890625, -0.2109375, -0.390625, -0.7421875, -0.8046875, -0.99609375, -0.00689697265625, -0.87890625, 0.04931640625, 0.2177734375, -0.92578125, -0.55078125, -0.48046875, 0.62109375, -0.625, -0.69140625, -0.0830078125, 0.2138671875, -0.0003662109375, -0.40625, 0.98828125, -0.7421875, 1.2734375, -0.54296875, -0.62890625, -0.0208740234375, 0.06640625, 0.0059814453125, -0.01904296875, -0.0712890625, -0.212890625, -0.0216064453125, 0.349609375, -0.796875, 0.25390625, 0.73828125, 0.44140625, -0.65625, -0.765625, -0.625, -0.88671875, -0.73046875, 0.3125, -0.265625, -0.10107421875, 0.306640625, 0.7421875, 0.11962890625, -0.10693359375, -0.56640625, 0.302734375, 0.921875, 0.37109375, 0.050048828125, -0.09033203125, 0.154296875, 0.2236328125, -0.91015625, 0.1806640625, -0.0225830078125, -0.44140625, -0.380859375, -0.1904296875, 0.51171875,……]
  • 嵌入向量通常是一个固定长度的高维向量(例如 512 维或 768 维)。
  • 维度的大小由模型的结构决定,反映了模型可以捕获语义特征的能力。

从Titan的说明来看,它会返回1536维度的Embedding:

image-20241116061119021

无论传入的文本长度是多大,如果在最后打印Embedding长度,会发现输出1536:

response_body = json.loads(response.get("body").read())
print(response_body.get("embedding"))  # 打印生成的文本嵌入向量
print(len(response_body.get("embedding")))  # 输出1536

使用Cosine计算两个文本的相似性

在计算两个向量的相似性时,余弦相似性(cosine similarity) 是一种常用的方法,因为它专注于向量的方向,而忽略了向量的大小。

余弦相似性通过计算两个向量夹角的余弦值来衡量它们的相似性:

image-20241116062212493

在很多实际场景中,向量的大小可能并不重要,而方向才是语义相关性的关键。

比如两个嵌入向量:

  • [1,2,3]
  • [2,4,6] 它们的方向完全一致,但大小不同(第二个是第一个的 2 倍)。在这种情况下,使用余弦相似性可以正确判断它们完全相似 (cos⁡θ=1)。

如果使用欧几里得距离(Euclidean Distance),大小的差异会导致两者被认为是不相似。

另外余弦相似性的计算只需要点积和模长,公式简单且计算效率高。对大规模数据集和高维向量,可以利用硬件加速(如 GPU)或库(如 NumPy)高效计算。

方法 特性 缺点
欧几里得距离 衡量两点间的绝对距离 对向量大小敏感,可能无法反映语义关系
余弦相似性 专注方向,不受大小影响 只考虑方向,可能忽略大小的影响
点积 衡量相似性并包含大小信息 难以直接解释相似性程度
Jaccard 相似性 专注于集合间的交集与并集的比例 对于稀疏高维向量,计算可能不高效

余弦相似性是一种简单、高效、适合高维语义比较的相似性衡量方法,它的优势在于忽略大小,专注于向量方向,因此特别适合处理文本嵌入、图像特征等需要关注语义而非绝对值的场景。

使用python计算不同文本向量的Cosine:

import boto3
import json


def dotProduct(embedding1: list, embedding2: list):
    return sum([embedding1[i] * embedding2[i] for i in range(len(embedding1))])

# 定义cosine函数
def cosineSimilarity(embedding1: list, embedding2: list):
    dotProductValue = dotProduct(embedding1, embedding2)
    magnitude1 = dotProduct(embedding1, embedding1) ** 0.5
    magnitude2 = dotProduct(embedding2, embedding2) ** 0.5
    return dotProductValue / (magnitude1 * magnitude2)


client = boto3.client(service_name='bedrock-runtime', region_name="us-west-2")

# 我们将计算下面每一个句子的Embedding
facts = [
    'The first computer was invented in the 1940s.',
    'John F. Kennedy was the 35th President of the United States.',
    'The first moon landing was in 1969.',
    'The capital of France is Paris.',
    'Earth is the third planet from the sun.',
]
# 使用cosine对比它们与facts的相似性
newFact = 'I like to play computer games'
question = 'Who is the president of USA?'

def getEmbedding(input: str):
    response = client.invoke_model(
        body=json.dumps({
            "inputText": input,
        }),
        modelId='amazon.titan-embed-text-v1',
        accept='application/json',
        contentType='application/json')

    response_body = json.loads(response.get('body').read())
    return response_body.get('embedding')

factsWithEmbeddings = []

for fact in facts:
    factsWithEmbeddings.append({
        'text': fact,
        'embedding': getEmbedding(fact)
    })

newFactEmbedding = getEmbedding(question)

similarities = []

for fact in factsWithEmbeddings:
    similarities.append({
        'text': fact['text'],
        'similarity': cosineSimilarity(fact['embedding'], newFactEmbedding)
    })

print(f"Similarities for fact: '{question}' with:")
similarities.sort(key=lambda x: x['similarity'], reverse=True)
for similarity in similarities:
    print(f"  '{similarity['text']}': {similarity['similarity']:.2f}")

结果:

image-20241116062924632

这说明对于Who is the president of USA,最相关的fact是 'John F. Kennedy was the 35th President of the United States.': 0.47

如果查找跟I like to play computer games最相关的fact,结果是The first computer was invented in the 1940s.

image-20241116063049074