# Summary
1. SGPT
2. GTE-Qwen系列
3. Qwen3 Embedding & Reranker
# Cues
# Notes
## 2.4.2 嵌入模型
> ### AI 速览
> 本文讨论了生成式自回归模型不适合做嵌入模型的原因,以及若用生成式LLM做embedding的几种方式和相关训练要点。关键要点包括:
> 1. **生成式自回归模型的局限**:生成式自回归模型在训练中用casual mask进行next token prediction,使output对prompt的理解分散在多个隐藏状态中,不适合做嵌入模型。
> 2. **EOS-Hidden方式**:OpenAI在《Text and Code Embeddings by Contrastive Pre-Training》中,用EOS标记对应的最后一层隐藏层向量作为整个文档的嵌入表示,假设生成EOS前模型理解了整个文档上下文。
> 3. **(Max) Pooling Hidden方式**:Pooling Hidden将文档所有词的最后一层隐藏层向量求平均获得嵌入表示;Max Pooling Hidden对这些向量进行最大池化,捕捉最显著语义特征。
> 4. **Weighted Hidden方式**:SGPT提出的方法,因Casual Mask使序列靠后token包含更多信息,故用加权的hidden states赋予靠后token更高权重。
> 5. **训练要点**:LLM使用这些embedding方式时,需通过对比学习等方法训练,以克服各向异性问题,提升表现效果。
背景:生成式自回归模型不适合做嵌入模型,因为它们在训练中使用casual mask进行next token prediction的模式使得output对prompt的理解分散在多个隐藏状态中。
如果一定要用生成式LLM做embedding呢,有以下的方式:
- EOS-Hideen: OpenAI《Text and Code Embeddings by Contrastive Pre-Training》使用 EOS(End of Sentence)标记对应的最后一层隐藏层向量作为整个文档的嵌入表示。这种方法的基本假设是,由于GPT 是一个生成式模型,因此在生成EOS之前,模型需要对整个文档的上下文信息有一个很好的理解。因此,EOS 对应的隐藏向量包含了整个文档的语义信息。
* **Max Pooling Hidden**:对所有词的最后一层隐藏层向量进行最大池化。即在每个维度上,选择具有最大值的向量元素。这种方法可以捕捉到文档中最显著的语义特征。
* **Weighted Hidden**:
这是 SGPT 提出的方法,由于Casual Mask的存在,序列中靠后的token包含了更多关于整个序列的信息,因此用加权的hidden states赋予靠后的token更高的权重,这种方法可以更好地利用GPT模型的自回归特性:
$
v = \sum_{i=1}^{S} w_i h_i \quad \text{where} \quad w_i = \frac{i}{\sum_{j=1}^{S} j}
$
<small>where S is the sequence length, h_i the i-th hidden state and v the query or document embedding.</small>
```python
import torch
from transformers import GPT2Tokenizer, GPT2Model
# 加载 GPT-2 模型和分词器
model_name = "gpt2"
tokenizer = GPT2Tokenizer.from_pretrained(model_name)
model = GPT2Model.from_pretrained(model_name)
# 输入文本
text = "This is an example sentence."
# 对输入文本进行编码
# 注意:实际应用中应添加 EOS token
input_ids = tokenizer.encode(text, return_tensors="pt")
# 获取模型的输出
with torch.no_grad():
outputs = model(input_ids)
# 提取最后一层隐藏层向量
last_hidden_state = outputs.last_hidden_state
# 获取 EOS 标记的 ID
eos_token_id = tokenizer.eos_token_id
# 寻找 EOS 标记在输入序列中的位置 (此示例未显式添加EOS,仅作演示)
# 实际应用中,应确保EOS token在序列中
# eos_position = (input_ids == eos_token_id).nonzero(as_tuple=True)[1].item()
# 假设我们取最后一个token的向量作为近似表示
eos_hidden_vector = last_hidden_state[0, -1, :]
print("Last token's hidden vector:", eos_hidden_vector)
```
当然,即使LLM使用这些embedding方式,也必须通过对比学习等方法进行训练才会使得表现效果更好,克服各向异性的问题(参考 [2.1.1 预训练任务综述](#)),这也是这一章介绍不同模型(训练方法)的原因。