You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Longformer或HuggingFace模型生成固定长度长文档嵌入?

解决长文本固定长度文档嵌入的方案

一、修改现有Longformer代码生成固定长度嵌入

你当前得到的last_hidden_state是序列中每个token的嵌入,所以长度随输入文本变化。要得到单个固定长度的文档嵌入,有两种直接处理方式:

1. 提取<[BOS_never_used_51bce0c785ca2f68081bfa7d91973934]>token的隐藏状态

Longformer(和大多数Transformer模型)的第一个token是<[BOS_never_used_51bce0c785ca2f68081bfa7d91973934]>,它的隐藏状态经过训练,本身就是整个输入序列的聚合表示,维度固定为模型的隐藏层大小(此处为768)。修改代码如下:

tokenizer = LongformerTokenizer.from_pretrained("allenai/longformer-base-4096")
model = LongformerModel.from_pretrained("allenai/longformer-base-4096")
encoded_input = tokenizer(text_dataset[0], return_tensors="pt", max_length=4096, truncation=True, padding=True)
output = model(**encoded_input)
# 提取<[BOS_never_used_51bce0c785ca2f68081bfa7d91973934]>token的嵌入,维度为 [1, 768]
doc_embedding = output.last_hidden_state[:, 0, :]
print(doc_embedding.size())  # 输出 torch.Size([1, 768])

2. 对序列嵌入做池化操作

如果觉得<[BOS_never_used_51bce0c785ca2f68081bfa7d91973934]>token的表示不够全面,可以对整个序列的隐藏状态做池化,将变长序列压缩为固定长度向量:

  • 均值池化:取所有token嵌入的平均值
doc_embedding = torch.mean(output.last_hidden_state, dim=1)
  • 最大池化:取所有token嵌入的最大值
doc_embedding = torch.max(output.last_hidden_state, dim=1)[0]

二、处理超4k tokens的长文本(2K-12K)

Longformer-base的最大上下文是4096,对于超过这个长度的文本,需要先拆分再聚合:

  1. 将文本按4096 token的窗口拆分(可选择重叠或不重叠)
  2. 对每个窗口生成嵌入(用上述方法)
  3. 对所有窗口的嵌入做二次池化(均值/最大),得到最终固定长度的文档嵌入

示例代码(简化版):

def split_long_text(text, tokenizer, max_len=4096):
    tokens = tokenizer.encode(text, add_special_tokens=False)
    # 拆分成长度为max_len-2的chunk(预留位置给特殊token)
    chunks = [tokens[i:i+max_len-2] for i in range(0, len(tokens), max_len-2)]
    # 给每个chunk解码回文本并添加特殊token
    chunk_texts = [tokenizer.decode(chunk) for chunk in chunks]
    return chunk_texts

long_text = text_dataset[0]
chunk_texts = split_long_text(long_text, tokenizer)

# 生成每个chunk的嵌入
chunk_embeddings = []
for chunk in chunk_texts:
    encoded = tokenizer(chunk, return_tensors="pt", max_length=4096, truncation=True, padding=True)
    output = model(**encoded)
    chunk_emb = output.last_hidden_state[:, 0, :]
    chunk_embeddings.append(chunk_emb)

# 聚合所有chunk嵌入得到最终文档嵌入
doc_embedding = torch.mean(torch.cat(chunk_embeddings, dim=0), dim=0).unsqueeze(0)
print(doc_embedding.size())  # 输出 torch.Size([1, 768])

三、其他替代方案

1. 使用Sentence-BERT长文本模型

Sentence-transformers库提供了专门针对长文本的预训练模型,直接输出固定长度的文档嵌入,无需手动处理:

from sentence_transformers import SentenceTransformer
model = SentenceTransformer("sentence-transformers/allenai-longformer-base-4096")
doc_embedding = model.encode(text_dataset[0], convert_to_tensor=True)
print(doc_embedding.size())  # 输出 torch.Size([768])

该模型支持最长4096 token,超过长度会自动拆分并聚合。

2. 使用支持更长上下文的Transformer模型

  • Longformer-large-16384:支持16384 token,可直接处理12K文本,取<[BOS_never_used_51bce0c785ca2f68081bfa7d91973934]>或池化得到固定嵌入
  • LLaMA-2-7B-32K:扩展支持32K token,生成的嵌入质量较高

3. 文档级预训练模型

比如facebook/dpr-ctx_encoder-single-nq-base,是专门为文档检索训练的编码器,输出固定长度的文档嵌入,适配长文本场景。

内容的提问来源于stack exchange,提问作者Asim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 19:50:32