# 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 预训练任务综述](#)),这也是这一章介绍不同模型(训练方法)的原因。