end0tknr's kipple - web写経開発

太宰府天満宮の狛犬って、妙にカワイイ

BERT自然言語modelによる意味的コサイン類似度

https://end0tknr.hateblo.jp/entry/20230717/1689536531

先程の上記entryの関連で、以下のurlの写経です

自然言語処理モデル(BERT)で文の意味上の類似度を計算 | GMOアドパートナーズ TECH BLOG byGMO

pip install

CONDA> pip install transformers
# 文章のベクトル化用
CONDA> pip install sentence_transformers
# 形態素解析であるmecabのラッパー
CONDA> pip install fugashi unidic-lite
CONDA> pip install ipadic

python scriptと、その実行結果

# -*- coding: utf-8 -*-
from transformers          import BertJapaneseTokenizer, BertModel
from sentence_transformers import SentenceTransformer
from sentence_transformers import models
import torch
import numpy as np

MODEL_NAME = 'cl-tohoku/bert-base-japanese-whole-word-masking'

def main():
    tokenizer = BertJapaneseTokenizer.from_pretrained(MODEL_NAME)
    model     = BertModel.from_pretrained(MODEL_NAME)

    base_text = "Spacyによれば、今日はweatherが良いですね。"
    base_vector = sentence_to_vector(model, tokenizer, base_text)
    
    target_texts  = [
        "spaCyは、pythonによる自然言語処理ライブラリです。",
        "spacyによれば、weatherは天気を表す名詞です。",
        "天気予報のとおり、今日は快晴ですね。",
        "天気予報によれば、今日の天気は雨になりそうですね。" ]
    
    print( base_text )

    for target_text in target_texts:
        target_vector = sentence_to_vector(model, tokenizer, target_text)
        # コサイン類似度
        tmp_result = torch.nn.functional.cosine_similarity(base_vector,
                                                           target_vector,
                                                           dim=0 )
        similarity = tmp_result.detach().numpy().copy()
        print(similarity, target_text)
        

# 文のベクトル化
def sentence_to_vector(model, tokenizer, sentence):
    # 文を単語に区切って数字にラベル化
    tokens = tokenizer(sentence)["input_ids"]
    # BERTモデルの処理のためtensor型に変換
    input = torch.tensor(tokens).reshape(1,-1)
    # BERTモデルに入力し文のベクトルを取得
    with torch.no_grad():
        outputs = model(input, output_hidden_states=True)
        last_hidden_state = outputs.last_hidden_state[0]
        averaged_hidden_state = \
            last_hidden_state.sum(dim=0) / len(last_hidden_state)

    return averaged_hidden_state

if __name__ == '__main__':
    main()

↑こう書くと、↓こう表示されます

Spacyによれば、今日はweatherが良いですね。
0.80075717 spaCyは、pythonによる自然言語処理ライブラリです。
0.9078393 spacyによれば、weatherは天気を表す名詞です。
0.87724173 天気予報のとおり、今日は快晴ですね。
0.9021285 天気予報によれば、今日の天気は雨になりそうですね。