在自然语言处理领域,嵌入模型(Embedding Model)和生成模型(Generative Model)虽然都处理文本,但设计目标和架构存在本质差异。传统嵌入模型如BERT采用Encoder-only架构,通过双向注意力机制让每个token都能"看到"整个句子的上下文,这种设计天然适合语义压缩任务。而GPT系列等Decoder-only模型使用自回归方式生成文本,其因果掩码(Causal Mask)机制导致信息理解呈现时间维度上的累积特性。
Encoder架构的优势:
Decoder架构的挑战:
python复制# 典型GPT类模型的注意力掩码示例
mask = torch.tril(torch.ones(seq_len, seq_len)) # 下三角矩阵
# 第i行表示第i个token只能看到前i个token的信息
这种设计导致:
关键发现:生成模型最后一层的隐藏状态虽然包含前文信息,但主要服务于下一个token预测,而非全局语义表征。这就是直接使用最后一个token向量效果受限的根本原因。
OpenAI在《Text and Code Embeddings by Contrastive Pre-Training》中提出的方法:
python复制# 获取EOS向量的关键代码
eos_position = (input_ids == tokenizer.eos_token_id).nonzero()[0,1]
eos_embedding = last_hidden_state[0, eos_position, :]
技术细节:
优缺点分析:
| 优势 | 局限性 |
|---|---|
| 实现简单 | 依赖EOS token的语义代表性 |
| 单向量计算高效 | 长文本效果下降明显 |
| 与生成目标一致 | 不同模型间一致性差 |
python复制mean_embedding = last_hidden_state.mean(dim=1)
python复制max_embedding = last_hidden_state.max(dim=1).values
论文《SGPT: GPT Sentence Embeddings for Semantic Search》提出的改进方法:
python复制# 线性加权实现
weights = torch.linspace(1, 0.5, steps=seq_len) # 递减权重
weighted_embedding = (last_hidden_state * weights).sum(dim=1)
设计原理:
实验对比结果:
| 方法 | STS-B得分 | 推理速度 |
|---|---|---|
| EOS | 58.2 | ★★★★★ |
| Mean | 63.7 | ★★★★ |
| SGPT | 71.4 | ★★★ |
分层融合策略:
python复制# 融合多层表示的实现
layer_weights = [0.1, 0.3, 0.6] # 深层权重更高
multi_layer_rep = sum(w * outputs.hidden_states[-i]
for i, w in enumerate(layer_weights, 1))
典型参数设置:
python复制with torch.inference_mode(): # 比torch.no_grad()更高效
outputs = model(input_ids)
python复制# 动态填充实现
encoded = tokenizer(batch_text, padding=True, truncation=True,
return_tensors="pt", max_length=512)
bash复制# 加载量化模型
model = GPT2Model.from_pretrained("gpt2", torch_dtype=torch.float16)
| 场景 | 推荐方案 | 原因 |
|---|---|---|
| 短文本搜索 | SGPT加权 | 捕捉关键语义 |
| 长文档检索 | 分层Mean | 保持稳定性 |
| 实时系统 | EOS向量 | 延迟最低 |
| 多语言场景 | 后接适配器 | 跨语言对齐 |
语义相似度任务:
检索任务:
问题1:不同长度文本的向量尺度不一致
python复制normalized_emb = F.layer_norm(raw_emb, (hidden_size,))
问题2:领域适应差
python复制# 添加Adapter模块
class Adapter(nn.Module):
def __init__(self, dim):
super().__init__()
self.down = nn.Linear(dim, dim//4)
self.up = nn.Linear(dim//4, dim)
def forward(self, x):
return x + self.up(self.down(x))
python复制similarity = logits / temperature # 典型值0.05-0.2
在实际项目中,我们发现在金融领域文本上,采用SGPT加权方案配合领域适配器微调,相比原始BERT方案在理财产品推荐场景中点击率提升23%。关键是在计算资源有限的情况下,这种方案只需1%的微调数据量就能达到不错的效果。