OpenAI最新套娃嵌入模型分析:256维的MTEB效果超过1536维 精华
一月份,OpenAI发布了两种新的嵌入模型:text-embedding-3-small和text-embedding-3-large。这些模型采用套娃表示学习技术(MRL:Matryoshka Representation Learning)进行训练,这使得开发者可以在嵌入中权衡性能和成本。
什么是套娃表示学习?
套娃表示学习是一种用于训练嵌入模型的技术。它允许在牺牲少量准确性的情况下换取更小的嵌入尺寸。因此,可以以更低的成本存储更多的信息,并更快地搜索它。
嵌入通过从序列末尾移除维度,并且只使用嵌入向量的子集维度来缩短。例如,你可以只使用原本具有1536维度向量的前8、16、32等维度(或任何其他维度的切片)。
与常见的向量嵌入不同,其中所有维度都同等重要,在套娃嵌入中,向量前面的维度存储的信息比后面的维度更多,后者只是添加了更多细节。可以通过尝试在多个分辨率下对图像进行分类的类比来理解这一点:较低的分辨率提供了更多高层次的信息,而较高的分辨率则添加了更多细节。
因此,检索性能随着表示大小的增加而提高。然而,OpenAI报告说,text-embedding-3-large嵌入可以缩短到256的大小,同时在MTEB基准测试上仍然优于未缩短的、大小为1536的text-embedding-ada-002嵌入。
套娃嵌入的表示大小与检索性能
MRL(Matryoshka Representation Learning,套娃表示学习)实现的魔力全部在于训练这些模型时优化的损失函数!如果之前损失函数是L,对于MRL,将损失函数分解为各个向量维度范围上的损失之和:Loss_Total = L(upto 8d) + L(upto 16d) + L(upto 32d) + ... + L(upto 2048d)。有了这个新的嵌套损失函数,模型就有动力在向量的每个子部分捕捉信息。
修改损失函数后,可以免费获得这些可截断的向量,无需任何额外成本——这几乎适用于所有损失函数,并且可以对现有的预训练模型进行微调以输出MRL向量!这意味着MRL非常容易采用并应用于预训练模型。
套娃嵌入详细分析
下面将使用来自DBpedia的100万个对象的数据集进行工作,这些对象已使用新的OpenAI套娃text-embedding-3-large模型和旧的ada-002模型进行了嵌入。这将理解信息是如何在套娃向量中与它们的非套娃前身不成比例地存储的。
在下面的分析中,从上述数据集中随机抽取了1万个向量,并绘制了每个维度上观察到的值的标准差。一个维度上看到的方差或标准差是衡量该维度相对于其他维度携带多少信息的良好指标。
显示了使用新text-emb3-large模型和旧ada-002模型嵌入的DBpedia中的10,000个随机样本,每个维度的标准差平滑值。
可以看到,标准差是维度索引的多步函数——早期维度捕获更多信息,而后面的维度捕获较少。图表还显示,OpenAI嵌入模型在维度={512d, 1024d, 1536d, 3072d}处使用了4个聚合损失函数,按照上面详细描述的MRL风格进行训练。
更有趣的是,这些步骤内的信息(512d, 1024d, 1536d, 3072d)在各个维度之间或多或少地均匀扩散。这也解释了MRL论文中的神奇发现,即你可以实际上取这些预指定块之间的维度(例如750d),仍然可以获得增量效益。
可视化套娃向量空间
还可以问一个有趣的问题:当你使用越来越多的套娃嵌入维度时,底层数据表示/向量空间会如何变化?
下面的视频中,每一帧都是使用仅使用一定数量的MRL向量维度的主成分分析(PCA)生成的3D向量空间。
从上面链接的相同数据集中取了10,000个随机样本,使用OpenAI text-embed-3-large模型进行嵌入,然后使用PCA将它们缩减到3D空间;从仅使用4个维度开始,一直到使用所有3072个维度。用越来越多的维度可视化套娃向量。
可以看到,当使用512个维度时,向量空间的结构已经被很好地定义了,在这些最初的512个维度之后,其他维度主要用于在更大的结构内收紧数据表示。
当到达2000+维度时,只看到数据点的小幅度抖动,可能是因为增量维度的贡献微乎其微,无法在前3个主成分中看到。
熟悉 OpenAI 的 Matryoshka
OpenAI 发布了两个新模型,text-embedding-3-small和,它们使用Matryoshka表示学习text-embedding-3-large技术进行训练 。这些模型的 API 支持一个参数,可以使用该参数控制生成的嵌入的长度。dimensions
如果使用相同的模型但不同的dimensions参数嵌入相同的文本,会发现较短的嵌入不是较长嵌入的截断版本。
# !pip install openai
from openai import OpenAI
openai = OpenAI()
def vectorize(text,
dimensions,
model = "text-embedding-3-small"):
text = text.lower()
return openai.embeddings.create(input = [text],
model = model,
dimensions = dimensions).data[0].embedding
example_text = "Learned representations are a central component in modern ML systems, serving a multitude of downstream tasks."
full = vectorize(example_text, dimensions = 1536)
short = vectorize(example_text, dimensions = 8)
print(full[:8])
print(short)
[-0.001463836757466197, -0.0241670124232769, 0.00683123804628849, -0.013936602510511875, 0.0320618636906147, 0.00872271228581667, 0.031053075566887856, 0.021820487454533577]
[-0.025210261344909668, -0.41620534658432007, 0.11764788627624512, -0.24001678824424744, 0.5521708130836487, 0.15022294223308563, 0.5347974300384521, 0.3757933974266052]
但是,如果检查它们的余弦相似度,会发现它们非常相似(或者由于四舍五入而甚至相等)。
from sklearn.metrics.pairwise import cosine_similarity
cosine_similarity([full[:8]], [short])
array([[1.]])
如果仔细观察,会发现嵌入实际上仅在缩放因子上有所不同(在本例中为 0.058)。
scale = full[0]/short[0]
print(scale)
print([x * scale for x in short])
print(full[:8])
0.05806511632065122
[-0.001463836757466197, -0.0241670118626955, 0.006831238201508919, -0.01393660272831134, 0.03206186249057062, 0.008722712614794586, 0.031053074983168057, 0.021820487334108546]
[-0.001463836757466197, -0.0241670124232769, 0.00683123804628849, -0.013936602510511875, 0.0320618636906147, 0.00872271228581667, 0.031053075566887856, 0.021820487454533577]
请注意 text-embedding-3-large 和 text-embedding-3-small 在默认嵌入长度的长度上有所不同:
默认尺寸text-embedding-3-small:1536
默认尺寸text-embedding-3-large:3072
此外, 当切片为相同尺寸时,它们不会产生兼容的嵌入:
large = vectorize(example_text, dimensions = 3072, model = "text-embedding-3-large")
small = vectorize(example_text, dimensions = 1536, model = "text-embedding-3-small")
print(large[:1536])
print(small)
cosine_similarity([large[:1536]], [small])
[0.011070899665355682, 0.014488349668681622, -0.021118611097335815, -0.011152755469083786, 0.011555208824574947, -0.0007622754783369601, ... ]
[-0.001463836757466197, -0.0241670124232769, 0.00683123804628849, -0.013936602510511875, 0.0320618636906147, 0.00872271228581667, ... ]
array([[-0.00149749]])
如果需要在生成嵌入维度后更改嵌入维度,则需要对嵌入维度进行规范化。OpenAI文档对此进行了更全面的解释。
本文转载自PaperAgent