当前位置:   article > 正文

BERT | (4)Bert生成句向量_pytorch_python 利用bert 生成句向量

python 利用bert 生成句向量

原文地址:Bert生成句向量(pytorch)

本文主要讲如何调用transformers这个包来提取一个句子的特征。

Transformers是TensorFlow 2.0和PyTorch的最新自然语言处理库

Transformers(以前称为pytorch-transformers和pytorch-pretrained-bert)提供用于自然语言理解(NLU)和自然语言生成(NLG)的最先进的模型(BERTGPT-2,RoBERTaXLMDistilBertXLNet,CTRL …) ,拥有超过32种预训练模型,支持100多种语言,并且在TensorFlow 2.0和PyTorch之间具有深厚的互操作性。

 

Bert

1、安装transformers库

pip install transformers

2、从transformers库中导入Bert的上面所说到的3个类

 from transformers import  BertModel, BertConfig,BertTokenizer

1、文本处理

用BertTokenizer对输入文本进行处理,从预训练模型中加载tokenizer

tokenizer = BertTokenizer.from_pretrained('bert-base-chinese')

如果不想下载,可以先把bert-base-chinese-vocab.txt 下载下来加载进去。

tokenizer = BertTokenizer.from_pretrained('bert-base-chinese-vocab.txt')

 

输入文本是两个sentence

需要在文本开头加上’[CLS]’,在每个句子后面加上’[SEP]’,这样输入到BertModel中才能被正确识别。

  1. from transformers import BartModel,BertConfig, BertTokenizer
  2. import torch
  3. # 用BertTokenizer对输入文本进行处理,从预训练模型中加载tokenizer
  4. tokenizer = BertTokenizer.from_pretrained('./bert-base-chinese/vocab.txt')
  5. text = "[CLS] 今天天气不错,适合出行。 [SEP] 今天是晴天,可以出去玩。 [SEP]"
  6. tokenized_text = tokenizer.tokenize(text) # 用tokenizer对句子分词
  7. '''
  8. 输出;print(tokenized_text)
  9. ['[CLS]', '今', '天', '天', '气', '不', '错', ',', '适', '合', '出', '行', '。',
  10. '[SEP]', '今', '天', '是', '晴', '天', ',', '可', '以', '出', '去', '玩', '。', '[SEP]']
  11. '''
  12. indexed_tokens = tokenizer.convert_tokens_to_ids(tokenized_text) #词在预训练词表中的索引列表
  13. # print(indexed_tokens)
  14. '''
  15. output:print(indexed_tokens)
  16. [101, 791, 1921, 1921, 3698, 679, 7231, 8024, 6844, 1394, 1139, 6121, 511,
  17. 102, 791, 1921, 3221, 3252, 1921, 8024, 1377, 809, 1139, 1343, 4381, 511, 102]
  18. '''
  19. #用来指定哪个是第一个句子,哪个是第二个句子,0的部分代表句子一, 1的部分代表句子二
  20. segments_ids = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
  21. #转换成PyTorch tensors
  22. tokens_tensor = torch.tensor([indexed_tokens])
  23. segments_tensors = torch.tensor([segments_ids])
  24. '''
  25. output:print(tokens_tensor)
  26. tensor([[ 101, 791, 1921, 1921, 3698, 679, 7231, 8024, 6844, 1394, 1139, 6121,
  27. 511, 102, 791, 1921, 3221, 3252, 1921, 8024, 1377, 809, 1139, 1343,
  28. 4381, 511, 102]])
  29. output:print(segments_tensors)
  30. tensor([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]])
  31. '''

tokens_tensor,segments_tensors将作为BertModel的输入。

 

输入文本是一个sentence

很多时候输入文本是只有一个句子的,上面两个句子的情况只是简单提一下,下面主要是以一个句子为主。同样,先在句子前面加上’[CLS]’,后面加上’[SEP]’。一般神经网络提取文本特征是以batch为单位的,因此还需要用到一个输入input_masks,假设text是一个batch的数据。

  1. from transformers import BartModel,BertConfig, BertTokenizer
  2. import torch
  3. # 用BertTokenizer对输入文本进行处理,从预训练模型中加载tokenizer
  4. tokenizer = BertTokenizer.from_pretrained('./bert-base-chinese/vocab.txt')
  5. texts = ["[CLS] 今天天气不错,适合出行。 [SEP]",
  6. "[CLS] 今天是晴天,可以出去玩。 [SEP]"]
  7. tokens, segments, input_masks = [], [], []
  8. for text in texts:
  9. tokenized_text = tokenizer.tokenize(text) #用tokenizer对句子分词
  10. indexed_tokens = tokenizer.convert_tokens_to_ids(tokenized_text)#索引列表
  11. tokens.append(indexed_tokens)
  12. segments.append([0] * len(indexed_tokens))
  13. input_masks.append([1] * len(indexed_tokens))
  14. '''
  15. output:print(tokenized_text)
  16. ['[CLS]', '今', '天', '是', '晴', '天', ',
  17. ', '可', '以', '出', '去', '玩', '。', '[SEP]']
  18. output:print(segments)
  19. [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  20. [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
  21. output:print(segments)
  22. [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
  23. [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]
  24. '''
  25. max_len = max([len(single) for single in tokens]) # 最大的句子长度
  26. '''
  27. # segments列表全0,因为只有一个句子1,没有句子2
  28. # input_masks列表1的部分代表句子单词,而后面0的部分代表paddig,只是用于保持输入整齐,没有实际意义。
  29. # 相当于告诉BertModel不要利用后面0的部分
  30. '''
  31. for j in range(len(tokens)):
  32. padding = [0] * (max_len - len(tokens[j]))
  33. tokens[j] += padding
  34. segments[j] += padding
  35. input_masks[j] += padding
  36. #转换成PyTorch tensors
  37. tokens_tensor = torch.tensor(tokens)
  38. segments_tensors = torch.tensor(segments)
  39. input_masks_tensors = torch.tensor(input_masks)

tokens_tensor,segments_tensors,input_masks_tensors 将作为BertModel的输入。

2、构建BertModel 

在BertModel后面加上一个全连接层,能够调整输出feature的维度。

 
  1. class BertTextNet(nn.Module):
  2. def __init__(self, code_length): #code_length为fc映射到的维度大小
  3. super(TextNet, self).__init__()
  4. modelConfig = BertConfig.from_pretrained('bert-base-chinese-config.json')
  5. self.textExtractor = BertModel.from_pretrained(
  6. 'bert-base-chinese-pytorch_model.bin', config=modelConfig)
  7. embedding_dim = self.textExtractor.config.hidden_size
  8. self.fc = nn.Linear(embedding_dim, code_length)
  9. self.tanh = torch.nn.Tanh()
  10. def forward(self, tokens, segments, input_masks):
  11. output=self.textExtractor(tokens, token_type_ids=segments,
  12. attention_mask=input_masks)
  13. text_embeddings = output[0][:, 0, :]
  14. #output[0](batch size, sequence length, model hidden dimension)
  15. features = self.fc(text_embeddings)
  16. features = self.tanh(features)
  17. return features

使用pytorch_transformers本身提供的预训练BertConfig,以及加载预训练模型。

  1. config = BertConfig.from_pretrained('bert-base-chinese')
  2. self.textExtractor = BertModel.from_pretrained('bert-base-chinese', config=modelConfig)

否则还是像上面模型那样加载本地下载的预训练模型。

把输入到BertModel后得到的输出output,一般是使用它的第0维信息。

outputs[0]  # The last hidden-state is the first element of the output tuple

其中output[0][:,0,:]代表下图中的C的输出向量,参考论文Bert

3、完整代码

 

  1. from transformers import BertModel,BertConfig, BertTokenizer
  2. import torch
  3. import torch.nn as nn
  4. # 用BertTokenizer对输入文本进行处理,从预训练模型中加载tokenizer
  5. # tokenizer = BertTokenizer.from_pretrained('./bert-base-chinese/vocab.txt')
  6. #
  7. # text = "[CLS] 今天天气不错,适合出行。 [SEP] 今天是晴天,可以出去玩。 [SEP]"
  8. # tokenized_text = tokenizer.tokenize(text) # 用tokenizer对句子分词
  9. #
  10. # '''
  11. # 输出;print(tokenized_text)
  12. # ['[CLS]', '今', '天', '天', '气', '不', '错', ',', '适', '合', '出', '行', '。',
  13. # '[SEP]', '今', '天', '是', '晴', '天', ',', '可', '以', '出', '去', '玩', '。', '[SEP]']
  14. # '''
  15. # indexed_tokens = tokenizer.convert_tokens_to_ids(tokenized_text) #词在预训练词表中的索引列表
  16. # # print(indexed_tokens)
  17. # '''
  18. # output:print(indexed_tokens)
  19. # [101, 791, 1921, 1921, 3698, 679, 7231, 8024, 6844, 1394, 1139, 6121, 511,
  20. # 102, 791, 1921, 3221, 3252, 1921, 8024, 1377, 809, 1139, 1343, 4381, 511, 102]
  21. # '''
  22. # #用来指定哪个是第一个句子,哪个是第二个句子,0的部分代表句子一, 1的部分代表句子二
  23. # segments_ids = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
  24. #
  25. # #转换成PyTorch tensors
  26. # tokens_tensor = torch.tensor([indexed_tokens])
  27. # segments_tensors = torch.tensor([segments_ids])
  28. # '''
  29. # output:print(tokens_tensor)
  30. # tensor([[ 101, 791, 1921, 1921, 3698, 679, 7231, 8024, 6844, 1394, 1139, 6121,
  31. # 511, 102, 791, 1921, 3221, 3252, 1921, 8024, 1377, 809, 1139, 1343,
  32. # 4381, 511, 102]])
  33. #
  34. # output:print(segments_tensors)
  35. # tensor([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]])
  36. # '''
  37. #
  38. # # 用BertTokenizer对输入文本进行处理,从预训练模型中加载tokenizer
  39. # tokenizer = BertTokenizer.from_pretrained('./bert-base-chinese/vocab.txt')
  40. # texts = ["[CLS] 今天天气不错,适合出行。 [SEP]",
  41. # "[CLS] 今天是晴天,可以出去玩。 [SEP]"]
  42. # tokens, segments, input_masks = [], [], []
  43. # for text in texts:
  44. # tokenized_text = tokenizer.tokenize(text) #用tokenizer对句子分词
  45. # indexed_tokens = tokenizer.convert_tokens_to_ids(tokenized_text)#索引列表
  46. # tokens.append(indexed_tokens)
  47. # segments.append([0] * len(indexed_tokens))
  48. # input_masks.append([1] * len(indexed_tokens))
  49. # '''
  50. # output:print(tokenized_text)
  51. # ['[CLS]', '今', '天', '是', '晴', '天', ',
  52. # ', '可', '以', '出', '去', '玩', '。', '[SEP]']
  53. #
  54. # output:print(segments)
  55. # [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  56. # [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
  57. #
  58. # output:print(segments)
  59. # [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
  60. # [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]
  61. #
  62. # '''
  63. # max_len = max([len(single) for single in tokens]) # 最大的句子长度
  64. #
  65. # '''
  66. # # segments列表全0,因为只有一个句子1,没有句子2
  67. # # input_masks列表1的部分代表句子单词,而后面0的部分代表paddig,只是用于保持输入整齐,没有实际意义。
  68. # # 相当于告诉BertModel不要利用后面0的部分
  69. # '''
  70. #
  71. # for j in range(len(tokens)):
  72. # padding = [0] * (max_len - len(tokens[j]))
  73. # tokens[j] += padding
  74. # segments[j] += padding
  75. # input_masks[j] += padding
  76. # #转换成PyTorch tensors
  77. # tokens_tensor = torch.tensor(tokens)
  78. # segments_tensors = torch.tensor(segments)
  79. # input_masks_tensors = torch.tensor(input_masks)
  80. # 1.构建模型
  81. class BertTextNet(nn.Module):
  82. def __init__(self, code_length): # code_length为fc映射到的维度大小
  83. super(BertTextNet, self).__init__()
  84. modelConfig = BertConfig.from_pretrained('./bert-base-chinese/bert_config.json')
  85. self.textExtractor = BertModel.from_pretrained(
  86. './bert-base-chinese/pytorch_model.bin', config=modelConfig, from_tf=True)
  87. embedding_dim = self.textExtractor.config.hidden_size
  88. self.fc = nn.Linear(embedding_dim, code_length)
  89. self.tanh = torch.nn.Tanh()
  90. def forward(self, tokens, segments, input_masks):
  91. output = self.textExtractor(tokens, token_type_ids=segments,
  92. attention_mask=input_masks)
  93. text_embeddings = output[0][:, 0, :]
  94. # output[0](batch size, sequence length, model hidden dimension)
  95. features = self.fc(text_embeddings)
  96. features = self.tanh(features)
  97. return features
  98. textNet = BertTextNet(code_length=32)
  99. # 2.数据处理
  100. # 用BertTokenizer对输入文本进行处理,从预训练模型中加载tokenizer
  101. tokenizer = BertTokenizer.from_pretrained('./bert-base-chinese/vocab.txt')
  102. texts = ["[CLS] 今天天气不错,适合出行。 [SEP]",
  103. "[CLS] 今天是晴天,可以出去玩。 [SEP]"]
  104. tokens, segments, input_masks = [], [], []
  105. for text in texts:
  106. tokenized_text = tokenizer.tokenize(text) #用tokenizer对句子分词
  107. indexed_tokens = tokenizer.convert_tokens_to_ids(tokenized_text)#索引列表
  108. tokens.append(indexed_tokens)
  109. segments.append([0] * len(indexed_tokens))
  110. input_masks.append([1] * len(indexed_tokens))
  111. max_len = max([len(single) for single in tokens]) # 最大的句子长度
  112. for j in range(len(tokens)):
  113. padding = [0] * (max_len - len(tokens[j]))
  114. tokens[j] += padding
  115. segments[j] += padding
  116. input_masks[j] += padding
  117. #转换成PyTorch tensors
  118. tokens_tensor = torch.tensor(tokens)
  119. segments_tensors = torch.tensor(segments)
  120. input_masks_tensors = torch.tensor(input_masks)
  121. # 3.提取文本特征——————
  122. text_hashCodes = textNet(tokens_tensor,segments_tensors,input_masks_tensors) #text_hashCodes是一个32-dim文本特征
  123. print(text_hashCodes)

 

在运行过程中出现如下的问题:

OSError: Unable to load weights from pytorch checkpoint file for './bert-base-chinese' at './bert-base-chinese/pytorch_model.bin'If you tried to load a PyTorch model from a TF 2.0 checkpoint, please set from_tf=True. 

不知道是啥子原因,但是叫我set from_tf=True. 那我就设置吧!

  1. self.textExtractor = BertModel.from_pretrained(
  2. './bert-base-chinese/pytorch_model.bin', config=modelConfig, from_tf=True)

然后接着告诉我,没有安装TensorFlow

那就装呗!装的时候又告诉我:

ERROR: Cannot uninstall 'six'. It is a distutils installed project and thus we cannot accurately determine which files belong to it which would lead to only a partial uninstall.

 找了好久,找到解决办法:

pip install six --upgrade --ignore-installed six

装好了,运行,艹!

这特么貌似是h5文件加载错误,但是我特么文件都是官方的呀?于是我往上看,发现最早的一个错误:

貌似又是TensorFlow这个坑逼框架在作妖,差了一下又是啥显卡版本与TensorFlow版本不兼容什么东西!

弄一下午,害……放弃了……TensorFlow就是一个坑!!!!

借同学服务器跑出来的结果:

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/361240
推荐阅读
相关标签
  

闽ICP备14008679号