比較兩個向量的相似度_比較不同語境下BERT生成的詞向量相似度
阿新 • • 發佈:2021-01-22
技術標籤:比較兩個向量的相似度
我們都體會到了BERT預訓練模型的強大,主要一點就是它可以動態生成句向量,根據不同的上下文而得到不同的句向量,當然也可以得到詞向量,但是如果我想比較不同語境下的詞向量該怎麼做呢?比如這兩句話“在手機品牌中,我喜歡蘋果”和“在水果中,我喜歡蘋果”中“蘋果”一詞的相似度,顯然,此“蘋果”非彼“蘋果”,如果我直接將這兩句話輸入給bert-as-service,它輸出的是這兩句話的句向量,如果我們想驗證“蘋果”這個詞向量的話,我們可以這麼做。
下面的程式碼只需要把預訓練模型地址更改就可以執行:
import torch from pytorch_pretrained_bert import BertTokenizer,BertModel text0 = '水果中很多對人有好處,比如蘋果' #句子0 text1 = '外國手機有很多都不錯,比如蘋果' #句子1 text2 = '我喜歡在飯吃不同水果,比如蘋果' #句子2 marked_text0 = '[CLS]' + text0 + '[SEP]' #因為BERT的輸入是按照[CLS]和[SEP]來區分句子的,所以加上 marked_text1 = '[CLS]' + text1 + '[SEP]' marked_text2 = '[CLS]' + text2 + '[SEP]' tokenizer = BertTokenizer('/home/zhu/BERT-BiLSTM-CRF-NER-master/chinese_L-12_H-768_A-12/vocab.txt') #載入你的預訓練詞表地址 tokenized_text0 = tokenizer.tokenize(marked_text0) #將輸入按照BERT的處理方式進行分割 tokenized_text1 = tokenizer.tokenize(marked_text1) tokenized_text2 = tokenizer.tokenize(marked_text2) # print(tokenized_text0) indexed_tokens = tokenizer.convert_tokens_to_ids(tokenized_text0) #將字元對映到id indexed_tokens1 = tokenizer.convert_tokens_to_ids(tokenized_text1) indexed_tokens2 = tokenizer.convert_tokens_to_ids(tokenized_text2) # for tup in zip(tokenized_text0,indexed_tokens): # print(tup) segments_ids = [1] * len(tokenized_text0) #segment_id是用來區分句子的,這裡我們的輸入是一句話一句話的輸入,所以都標成1即可。 segments_ids1 = [1] * len(tokenized_text1) segments_ids2 = [1] * len(indexed_tokens2) tokens_tensor = torch.tensor([indexed_tokens]) #將輸入轉換成張量的形式 segments_tensors = torch.tensor([segments_ids]) tokens_tensor1 = torch.tensor([indexed_tokens1]) segments_tensors1 = torch.tensor([segments_ids1]) segments_tensors2 = torch.tensor([segments_ids2]) tokens_tensor2 = torch.tensor([indexed_tokens2]) model = BertModel.from_pretrained('/home/zhu/BERT-BiLSTM-CRF-NER-master/chinese_L-12_H-768_A-12') #載入預訓練模型地址 model.eval() #這裡是驗證模型,可以節省很多不必要的反向傳播 with torch.no_grad(): #將輸入傳入模型,得到每一層的輸出資訊,這裡的encoded_layers為12層,可以列印驗證 encoded_layers,_ = model(tokens_tensor,segments_tensors) with torch.no_grad(): encoded_layers1,_ = model(tokens_tensor1,segments_tensors1) with torch.no_grad(): encoded_layers2,_ = model(tokens_tensor2,segments_tensors2) # print(len(encoded_layers)) batch_i = 0 #因為我們就輸入一句話,所以batch的批大小為1,從0開始索引 token_embeddings = [] for token_i in range(len(tokenized_text0)): #這裡是將一句話中每個字元的每一層資訊新增到token_embedding集合中 hidden_layers = [] for layer_i in range(len(encoded_layers)): vec = encoded_layers[layer_i][batch_i][token_i] hidden_layers.append(vec) token_embeddings.append(hidden_layers) token_embeddings1 = [] for token_i in range(len(tokenized_text1)): hidden_layers1 = [] for layer_i in range(len(encoded_layers1)): vec = encoded_layers1[layer_i][batch_i][token_i] hidden_layers1.append(vec) token_embeddings1.append(hidden_layers1) token_embeddings2 = [] for token_i in range(len(tokenized_text2)): hidden_layers2 = [] for layer_i in range(len(encoded_layers2)): vec = encoded_layers2[layer_i][batch_i][token_i] hidden_layers2.append(vec) token_embeddings2.append(hidden_layers2) # 有了一句話的每一層輸出資訊後,我們可以制定如何去拼接這些資訊,這裡我們選擇將最後四層輸出層的資訊想加 #concatenated_last_4_layers = [torch.cat((layer[-1],layer[-2],layer[-3],layer[-4]),0) for layer in token_embeddings] summed_last_4_layers = [torch.sum(torch.stack(layer)[-4:],0) for layer in token_embeddings] #concatenated_last_4_layers1 = [torch.cat((layer[-1],layer[-2],layer[-3],layer[-4]),0) for layer in token_embeddings1] summed_last_4_layers1 = [torch.sum(torch.stack(layer)[-4:],0) for layer in token_embeddings1] #concatenated_last_4_layers2 = [torch.cat((layer[-1],layer[-2],layer[-3],layer[-4]),0) for layer in token_embeddings2] summed_last_4_layers2 = [torch.sum(torch.stack(layer)[-4:],0) for layer in token_embeddings2] # print(sentence_embedding[0].shape[0]) # for i,x in enumerate(tokenized_text0): # print(i,x) # for i,x in enumerate(tokenized_text1): # print(i,x) # for i,x in enumerate(tokenized_text2): # print(i,x) token_0 = (summed_last_4_layers[14] + summed_last_4_layers[15]) / 2 #找到蘋果兩個字元的索引,並相加取平均值得到我們最終“蘋果”的詞向量 token_1 = (summed_last_4_layers1[14] + summed_last_4_layers1[15]) / 2 token_2 = (summed_last_4_layers2[14] + summed_last_4_layers2[15]) / 2 from sklearn.metrics.pairwise import cosine_similarity print(cosine_similarity(token_0.reshape(1,-1),token_1.reshape(1,-1))[0][0],'0和1') print(cosine_similarity(token_0.reshape(1,-1),token_2.reshape(1,-1))[0][0],'0和2') print(cosine_similarity(token_1.reshape(1,-1),token_2.reshape(1,-1))[0][0],'1和2')
執行結果如上圖所示,很明顯三句話中蘋果的相似度比較相對來說符合常理,雖然蘋果手機和水果蘋果也有著75%的相似度,個人認為句式的影響也很重要。