python 如何使用GPT-2计算单词和句子嵌入?

s2j5cfk0  于 2024-01-05  发布在  Python
关注(0)|答案(1)|浏览(165)

我正在编写一个程序,它使用GPT-2计算单词和句子嵌入,特别是GPT2Model类。对于单词嵌入,我在将input_ids(形状为batch size x seq len)转发给GPT2Model类后提取最后一个隐藏状态outputs[0]。至于句子嵌入,我在序列的末尾提取单词的隐藏状态。这是我尝试过的代码:

  1. from transformers import GPT2Tokenizer, GPT2Model
  2. import torch
  3. tokenizer = GPT2Tokenizer.from_pretrained('gpt2')
  4. model = GPT2Model.from_pretrained('gpt2')
  5. captions = ["example caption", "example bird", "the bird is yellow has red wings", "hi", "very good"]
  6. encoded_captions = [tokenizer.encode(caption) for caption in captions]
  7. # Pad sequences to the same length with 0s
  8. max_len = max(len(seq) for seq in encoded_captions)
  9. padded_captions = [seq + [0] * (max_len - len(seq)) for seq in encoded_captions]
  10. # Convert to a PyTorch tensor with batch size 5
  11. input_ids = torch.tensor(padded_captions)
  12. outputs = model(input_ids)
  13. word_embedding = outputs[0].contiguous()
  14. sentence_embedding = word_embedding[ :, -1, : ].contiguous()

字符串
我不确定我对单词和句子嵌入的计算是否正确,有人能帮我确认一下吗?

b4qexyjb

b4qexyjb1#

以下是修改后的代码,用于计算句子和单词嵌入:

  1. from transformers import GPT2Tokenizer, GPT2Model
  2. import torch
  3. tokenizer = GPT2Tokenizer.from_pretrained('gpt2')
  4. tokenizer.pad_token = tokenizer.eos_token
  5. model = GPT2Model.from_pretrained('gpt2')
  6. captions = [
  7. "example caption",
  8. "example bird",
  9. "the bird is yellow has red wings",
  10. "hi",
  11. "very good"
  12. ]
  13. # Tokenize and pad sequences
  14. encoded_captions = tokenizer(
  15. captions,
  16. return_tensors='pt',
  17. padding=True,
  18. truncation=True
  19. )
  20. input_ids = encoded_captions['input_ids']
  21. # Forward pass to get embeddings
  22. with torch.no_grad():
  23. outputs = model(input_ids)
  24. # Extract embeddings
  25. word_embeddings = outputs.last_hidden_state
  26. # Mask to ignore padding tokens
  27. masked_word_embeddings = word_embeddings * encoded_captions.attention_mask.unsqueeze(-1).float()
  28. # Sum pooling considering only non-padding tokens
  29. sentence_embeddings = masked_word_embeddings.sum(dim=1)
  30. # Normalize by the count of non-padding tokens
  31. sentence_embeddings /= encoded_captions.attention_mask.sum(dim=1, keepdim=True).float()

字符串
一些相关事实:
1.正如你所说,单词嵌入是最后一个隐藏的输出。如果你打印输出,你会看到5个向量(句子的数量),长度为7(句子列表中的最大标记数),形状为768(模型维度)。

  1. word_embeddings.shape
  2. >> torch.Size([5, 7, 768])


这意味着有些句子有不存在的标记的嵌入,所以我们需要屏蔽输出,只考虑存在的标记
1.掩码是在单词向量中不存在的标记位置乘以零(或者任何特殊值,但零更被接受和有用,因为它使值为空)。注意掩码对于处理可变长度序列和确保填充标记不参与嵌入至关重要。

  1. print(masked_word_embeddings)
  2. >> tensor([[[-0.2835, -0.0469, -0.5029, ..., -0.0525, -0.0089, -0.1395],
  3. [-0.2636, -0.1355, -0.4277, ..., -0.3552, 0.0437, -0.2479],
  4. [ 0.0000, -0.0000, 0.0000, ..., 0.0000, -0.0000, -0.0000],
  5. ...,
  6. [ 0.0000, -0.0000, 0.0000, ..., 0.0000, -0.0000, -0.0000],
  7. [ 0.0000, -0.0000, 0.0000, ..., 0.0000, -0.0000, -0.0000],
  8. [ 0.0000, -0.0000, 0.0000, ..., 0.0000, -0.0000, -0.0000]],
  9. ...


1.通常情况下,句子嵌入计算为屏蔽词嵌入的总和、平均值或最大值。这取决于您的用例。

  • 平均值更适合可变长度:
  1. sentence_embeddings = masked_word_embeddings.mean(dim=1)

  • Sum旨在对相关部分施加重要性:
  1. sentence_embeddings = masked_word_embeddings.max(dim=1)


它有很多技术,这取决于嵌入如何执行你的任务。我会选择一种方法,最大化我认为相似的向量之间的余弦相似度。例如:如果总和比平均值更相似,它可能更合适。
1.此外,我建议你通过句子中的标记数量来规范化值。因此,通过这种规范化,较大的句子往往具有较低的向量值。这是为了嵌入句子中标记数量的信息。它可以防止一个句子的4个标记与整本书之间的相似度得分很高,这是没有意义的。

展开查看全部

相关问题