utils.py 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. import jieba
  2. import re
  3. from config import *
  4. import torch
  5. from model import get_padding_mask,get_subsequent_mask
  6. import sacrebleu
  7. # 中文分词
  8. def divided_zh(sentence):
  9. return jieba.lcut(sentence)
  10. # 英文分词
  11. def divided_en(sentence):
  12. # 使用正则表达式匹配单词和标点符号
  13. pattern = r'\w+|[^\w\s]'
  14. return re.findall(pattern, sentence)
  15. def get_vocab(lang='en'):
  16. if lang == 'en':
  17. file_path = EN_VOCAB_PATH
  18. elif lang == 'zh':
  19. file_path = ZH_VOCAB_PATH
  20. with open(file_path, encoding='utf-8') as file:
  21. lines = file.read()
  22. id2vocab = lines.split('\n')
  23. vocab2id = {v:k for k,v in enumerate(id2vocab)}
  24. return id2vocab, vocab2id
  25. #逐字生成预测值
  26. def batch_greedy_decode(model, src_x, src_mask, max_len=MAX_LEN):
  27. src_x= src_x.to(device)
  28. src_mask=src_mask.to(device)
  29. #获取中文词表
  30. zh_id2vocab, _ = get_vocab('zh')
  31. #encoder 输出
  32. memory = model.encoder(src_x, src_mask)
  33. # 初始化decoder 输入
  34. prob_x = torch.tensor([[SOS_ID]] * src_x.size(0))
  35. prob_x = prob_x.to(device)
  36. for _ in range(max_len):
  37. #推理时mask
  38. # prob_mask = get_padding_mask(prob_x, PAD_ID).to(device)
  39. prob_pad_mask = get_padding_mask(prob_x, PAD_ID).to(device)
  40. prob_subsqueent_mask = get_subsequent_mask(prob_x.size(1)).to(device)
  41. prob_mask = prob_pad_mask | prob_subsqueent_mask
  42. prob_mask = prob_mask != 0
  43. decoder_output = model.decoder(prob_x, prob_mask, memory, src_mask) # shape 3,1,512
  44. output = model.generator(decoder_output[:, -1, :]) #shape 3,19
  45. output = torch.softmax(output,dim=-1)
  46. predict = torch.argmax(output, dim=-1, keepdim=True)
  47. #把之前的值拼到一起
  48. prob_x = torch.concat([prob_x, predict], dim=-1)
  49. #如果预测的当前值是eos,则表示整个序列结束
  50. if torch.all(predict==EOS_ID).item():
  51. break
  52. #把预测出的索引值,转成对应的词
  53. batch_prob_text = []
  54. for prob in prob_x:
  55. prob_text = []
  56. for prob_id in prob:
  57. if prob_id == SOS_ID:
  58. continue
  59. if prob_id == EOS_ID:
  60. break
  61. prob_text.append(zh_id2vocab[prob_id])
  62. batch_prob_text.append(''.join(prob_text))
  63. return batch_prob_text
  64. def bleu_score(hyp, refs):
  65. bleu = sacrebleu.corpus_bleu(hyp, refs, tokenize='zh')
  66. return round(bleu.score, 2)
  67. if __name__ == '__main__':
  68. target = '我喜欢读书'
  69. vocabs = divided_zh(target)
  70. _, zh_vocab2id = get_vocab('zh')
  71. tokens = [zh_vocab2id.get(v, UNK_ID) for v in vocabs]
  72. print(tokens)