赞
踩
原文地址:Bert生成句向量(pytorch)
本文主要讲如何调用transformers这个包来提取一个句子的特征。
Transformers是TensorFlow 2.0和PyTorch的最新自然语言处理库
Transformers(以前称为pytorch-transformers和pytorch-pretrained-bert)提供用于自然语言理解(NLU)和自然语言生成(NLG)的最先进的模型(BERT,GPT-2,RoBERTa,XLM,DistilBert,XLNet,CTRL …) ,拥有超过32种预训练模型,支持100多种语言,并且在TensorFlow 2.0和PyTorch之间具有深厚的互操作性。
1、安装transformers库
pip install transformers
2、从transformers库中导入Bert的上面所说到的3个类
from transformers import BertModel, BertConfig,BertTokenizer
用BertTokenizer对输入文本进行处理,从预训练模型中加载tokenizer
tokenizer = BertTokenizer.from_pretrained('bert-base-chinese')
如果不想下载,可以先把bert-base-chinese-vocab.txt 下载下来加载进去。
tokenizer = BertTokenizer.from_pretrained('bert-base-chinese-vocab.txt')
需要在文本开头加上’[CLS]’,在每个句子后面加上’[SEP]’,这样输入到BertModel中才能被正确识别。
- from transformers import BartModel,BertConfig, BertTokenizer
- import torch
-
- # 用BertTokenizer对输入文本进行处理,从预训练模型中加载tokenizer
- tokenizer = BertTokenizer.from_pretrained('./bert-base-chinese/vocab.txt')
-
- text = "[CLS] 今天天气不错,适合出行。 [SEP] 今天是晴天,可以出去玩。 [SEP]"
- tokenized_text = tokenizer.tokenize(text) # 用tokenizer对句子分词
-
- '''
- 输出;print(tokenized_text)
- ['[CLS]', '今', '天', '天', '气', '不', '错', ',', '适', '合', '出', '行', '。',
- '[SEP]', '今', '天', '是', '晴', '天', ',', '可', '以', '出', '去', '玩', '。', '[SEP]']
- '''
- indexed_tokens = tokenizer.convert_tokens_to_ids(tokenized_text) #词在预训练词表中的索引列表
- # print(indexed_tokens)
- '''
- output:print(indexed_tokens)
- [101, 791, 1921, 1921, 3698, 679, 7231, 8024, 6844, 1394, 1139, 6121, 511,
- 102, 791, 1921, 3221, 3252, 1921, 8024, 1377, 809, 1139, 1343, 4381, 511, 102]
- '''
- #用来指定哪个是第一个句子,哪个是第二个句子,0的部分代表句子一, 1的部分代表句子二
- 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]
-
- #转换成PyTorch tensors
- tokens_tensor = torch.tensor([indexed_tokens])
- segments_tensors = torch.tensor([segments_ids])
- '''
- output:print(tokens_tensor)
- tensor([[ 101, 791, 1921, 1921, 3698, 679, 7231, 8024, 6844, 1394, 1139, 6121,
- 511, 102, 791, 1921, 3221, 3252, 1921, 8024, 1377, 809, 1139, 1343,
- 4381, 511, 102]])
- output:print(segments_tensors)
- 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]])
- '''
tokens_tensor,segments_tensors将作为BertModel的输入。
很多时候输入文本是只有一个句子的,上面两个句子的情况只是简单提一下,下面主要是以一个句子为主。同样,先在句子前面加上’[CLS]’,后面加上’[SEP]’。一般神经网络提取文本特征是以batch为单位的,因此还需要用到一个输入input_masks,假设text是一个batch的数据。
- from transformers import BartModel,BertConfig, BertTokenizer
- import torch
-
- # 用BertTokenizer对输入文本进行处理,从预训练模型中加载tokenizer
- tokenizer = BertTokenizer.from_pretrained('./bert-base-chinese/vocab.txt')
- texts = ["[CLS] 今天天气不错,适合出行。 [SEP]",
- "[CLS] 今天是晴天,可以出去玩。 [SEP]"]
- tokens, segments, input_masks = [], [], []
- for text in texts:
- tokenized_text = tokenizer.tokenize(text) #用tokenizer对句子分词
- indexed_tokens = tokenizer.convert_tokens_to_ids(tokenized_text)#索引列表
- tokens.append(indexed_tokens)
- segments.append([0] * len(indexed_tokens))
- input_masks.append([1] * len(indexed_tokens))
- '''
- output:print(tokenized_text)
- ['[CLS]', '今', '天', '是', '晴', '天', ',
- ', '可', '以', '出', '去', '玩', '。', '[SEP]']
- output:print(segments)
- [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
- output:print(segments)
- [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
- [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]
- '''
- max_len = max([len(single) for single in tokens]) # 最大的句子长度
-
- '''
- # segments列表全0,因为只有一个句子1,没有句子2
- # input_masks列表1的部分代表句子单词,而后面0的部分代表paddig,只是用于保持输入整齐,没有实际意义。
- # 相当于告诉BertModel不要利用后面0的部分
- '''
-
- for j in range(len(tokens)):
- padding = [0] * (max_len - len(tokens[j]))
- tokens[j] += padding
- segments[j] += padding
- input_masks[j] += padding
- #转换成PyTorch tensors
- tokens_tensor = torch.tensor(tokens)
- segments_tensors = torch.tensor(segments)
- input_masks_tensors = torch.tensor(input_masks)
tokens_tensor,segments_tensors,input_masks_tensors 将作为BertModel的输入。
在BertModel后面加上一个全连接层,能够调整输出feature的维度。
- class BertTextNet(nn.Module):
- def __init__(self, code_length): #code_length为fc映射到的维度大小
- super(TextNet, self).__init__()
-
- modelConfig = BertConfig.from_pretrained('bert-base-chinese-config.json')
- self.textExtractor = BertModel.from_pretrained(
- 'bert-base-chinese-pytorch_model.bin', config=modelConfig)
- embedding_dim = self.textExtractor.config.hidden_size
-
- self.fc = nn.Linear(embedding_dim, code_length)
- self.tanh = torch.nn.Tanh()
-
- def forward(self, tokens, segments, input_masks):
- output=self.textExtractor(tokens, token_type_ids=segments,
- attention_mask=input_masks)
- text_embeddings = output[0][:, 0, :]
- #output[0](batch size, sequence length, model hidden dimension)
-
- features = self.fc(text_embeddings)
- features = self.tanh(features)
- return features
使用pytorch_transformers本身提供的预训练BertConfig,以及加载预训练模型。
- config = BertConfig.from_pretrained('bert-base-chinese')
- 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
- from transformers import BertModel,BertConfig, BertTokenizer
- import torch
- import torch.nn as nn
-
-
- # 用BertTokenizer对输入文本进行处理,从预训练模型中加载tokenizer
- # tokenizer = BertTokenizer.from_pretrained('./bert-base-chinese/vocab.txt')
- #
- # text = "[CLS] 今天天气不错,适合出行。 [SEP] 今天是晴天,可以出去玩。 [SEP]"
- # tokenized_text = tokenizer.tokenize(text) # 用tokenizer对句子分词
- #
- # '''
- # 输出;print(tokenized_text)
- # ['[CLS]', '今', '天', '天', '气', '不', '错', ',', '适', '合', '出', '行', '。',
- # '[SEP]', '今', '天', '是', '晴', '天', ',', '可', '以', '出', '去', '玩', '。', '[SEP]']
- # '''
- # indexed_tokens = tokenizer.convert_tokens_to_ids(tokenized_text) #词在预训练词表中的索引列表
- # # print(indexed_tokens)
- # '''
- # output:print(indexed_tokens)
- # [101, 791, 1921, 1921, 3698, 679, 7231, 8024, 6844, 1394, 1139, 6121, 511,
- # 102, 791, 1921, 3221, 3252, 1921, 8024, 1377, 809, 1139, 1343, 4381, 511, 102]
- # '''
- # #用来指定哪个是第一个句子,哪个是第二个句子,0的部分代表句子一, 1的部分代表句子二
- # 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]
- #
- # #转换成PyTorch tensors
- # tokens_tensor = torch.tensor([indexed_tokens])
- # segments_tensors = torch.tensor([segments_ids])
- # '''
- # output:print(tokens_tensor)
- # tensor([[ 101, 791, 1921, 1921, 3698, 679, 7231, 8024, 6844, 1394, 1139, 6121,
- # 511, 102, 791, 1921, 3221, 3252, 1921, 8024, 1377, 809, 1139, 1343,
- # 4381, 511, 102]])
- #
- # output:print(segments_tensors)
- # 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]])
- # '''
- #
-
- # # 用BertTokenizer对输入文本进行处理,从预训练模型中加载tokenizer
- # tokenizer = BertTokenizer.from_pretrained('./bert-base-chinese/vocab.txt')
- # texts = ["[CLS] 今天天气不错,适合出行。 [SEP]",
- # "[CLS] 今天是晴天,可以出去玩。 [SEP]"]
- # tokens, segments, input_masks = [], [], []
- # for text in texts:
- # tokenized_text = tokenizer.tokenize(text) #用tokenizer对句子分词
- # indexed_tokens = tokenizer.convert_tokens_to_ids(tokenized_text)#索引列表
- # tokens.append(indexed_tokens)
- # segments.append([0] * len(indexed_tokens))
- # input_masks.append([1] * len(indexed_tokens))
- # '''
- # output:print(tokenized_text)
- # ['[CLS]', '今', '天', '是', '晴', '天', ',
- # ', '可', '以', '出', '去', '玩', '。', '[SEP]']
- #
- # output:print(segments)
- # [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
- # [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
- #
- # output:print(segments)
- # [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
- # [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]
- #
- # '''
- # max_len = max([len(single) for single in tokens]) # 最大的句子长度
- #
- # '''
- # # segments列表全0,因为只有一个句子1,没有句子2
- # # input_masks列表1的部分代表句子单词,而后面0的部分代表paddig,只是用于保持输入整齐,没有实际意义。
- # # 相当于告诉BertModel不要利用后面0的部分
- # '''
- #
- # for j in range(len(tokens)):
- # padding = [0] * (max_len - len(tokens[j]))
- # tokens[j] += padding
- # segments[j] += padding
- # input_masks[j] += padding
- # #转换成PyTorch tensors
- # tokens_tensor = torch.tensor(tokens)
- # segments_tensors = torch.tensor(segments)
- # input_masks_tensors = torch.tensor(input_masks)
-
-
-
- # 1.构建模型
- class BertTextNet(nn.Module):
- def __init__(self, code_length): # code_length为fc映射到的维度大小
- super(BertTextNet, self).__init__()
-
- modelConfig = BertConfig.from_pretrained('./bert-base-chinese/bert_config.json')
- self.textExtractor = BertModel.from_pretrained(
- './bert-base-chinese/pytorch_model.bin', config=modelConfig, from_tf=True)
- embedding_dim = self.textExtractor.config.hidden_size
-
- self.fc = nn.Linear(embedding_dim, code_length)
- self.tanh = torch.nn.Tanh()
-
- def forward(self, tokens, segments, input_masks):
- output = self.textExtractor(tokens, token_type_ids=segments,
- attention_mask=input_masks)
- text_embeddings = output[0][:, 0, :]
- # output[0](batch size, sequence length, model hidden dimension)
-
- features = self.fc(text_embeddings)
- features = self.tanh(features)
- return features
-
- textNet = BertTextNet(code_length=32)
-
- # 2.数据处理
- # 用BertTokenizer对输入文本进行处理,从预训练模型中加载tokenizer
- tokenizer = BertTokenizer.from_pretrained('./bert-base-chinese/vocab.txt')
- texts = ["[CLS] 今天天气不错,适合出行。 [SEP]",
- "[CLS] 今天是晴天,可以出去玩。 [SEP]"]
- tokens, segments, input_masks = [], [], []
- for text in texts:
- tokenized_text = tokenizer.tokenize(text) #用tokenizer对句子分词
- indexed_tokens = tokenizer.convert_tokens_to_ids(tokenized_text)#索引列表
- tokens.append(indexed_tokens)
- segments.append([0] * len(indexed_tokens))
- input_masks.append([1] * len(indexed_tokens))
-
- max_len = max([len(single) for single in tokens]) # 最大的句子长度
-
- for j in range(len(tokens)):
- padding = [0] * (max_len - len(tokens[j]))
- tokens[j] += padding
- segments[j] += padding
- input_masks[j] += padding
- #转换成PyTorch tensors
- tokens_tensor = torch.tensor(tokens)
- segments_tensors = torch.tensor(segments)
- input_masks_tensors = torch.tensor(input_masks)
-
- # 3.提取文本特征——————
- text_hashCodes = textNet(tokens_tensor,segments_tensors,input_masks_tensors) #text_hashCodes是一个32-dim文本特征
- 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. 那我就设置吧!
- self.textExtractor = BertModel.from_pretrained(
- './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就是一个坑!!!!
借同学服务器跑出来的结果:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。