如何用GPT-2计算词嵌入与句嵌入?代码正确性求验证
你的GPT-2词嵌入与句嵌入计算逻辑分析
词嵌入部分:逻辑正确
你提取outputs[0]作为词嵌入的做法没问题。GPT2Model的outputs[0]就是模型最后一层的隐藏状态,形状为(batch_size, seq_len, hidden_size),每个位置对应输入序列中对应token的上下文嵌入,完全符合词嵌入的需求。
句嵌入部分:存在两处关键问题
直接取word_embedding[:, -1, :]作为句嵌入的逻辑有漏洞,同时你的padding方式也不符合GPT-2的tokenizer规范,具体问题如下:
1. 手动padding的错误
GPT2Tokenizer默认没有专门的pad token,你直接用[0]填充的话,0对应的是GPT-2的<|endoftext|>(结束符),模型会把这些填充的0当成真实的输入token处理,导致隐藏状态计算失真。正确的做法是先给tokenizer指定pad token,再用tokenizer自带的批量编码方法处理,自动完成padding。
2. 句嵌入提取的错误
如果序列被padding,[:, -1, :]取到的是填充位置的隐藏状态,而不是原句子最后一个有效token的状态。必须借助attention_mask来定位每个序列的真实末尾位置,提取对应嵌入。
修正后的代码
from transformers import GPT2Tokenizer, GPT2Model import torch tokenizer = GPT2Tokenizer.from_pretrained('gpt2') # 给GPT2Tokenizer指定pad token(复用eos token) tokenizer.pad_token = tokenizer.eos_token model = GPT2Model.from_pretrained('gpt2') captions = ["example caption", "example bird", "the bird is yellow has red wings", "hi", "very good"] # 用tokenizer批量编码,自动生成input_ids和attention_mask encoded_input = tokenizer( captions, padding=True, truncation=True, return_tensors='pt' ) outputs = model(**encoded_input) word_embedding = outputs[0].contiguous() # 利用attention_mask找到每个序列的真实最后一个token位置 # attention_mask中1表示有效token,0表示padding # 计算每个序列的有效长度,再减1得到最后一个有效token的索引 seq_lengths = torch.sum(encoded_input['attention_mask'], dim=1) - 1 # 提取每个序列对应位置的隐藏状态作为句嵌入 sentence_embedding = word_embedding[torch.arange(word_embedding.size(0)), seq_lengths, :].contiguous()
额外说明
- 如果你的场景允许忽略padding的影响(比如所有句子长度一致),句嵌入取最后一个位置也能勉强用,但实际应用中几乎都会遇到长度不一致的情况,必须用attention_mask处理。
- GPT-2的隐藏状态本身是上下文相关的,所以提取的词嵌入和句嵌入都带有上下文信息,符合大部分NLP任务的需求。
内容的提问来源于stack exchange,提问作者user23180808
相关产品推荐
相关产品推荐

