質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Mecab

Mecabは、オープンソースの形態素解析エンジンです。 言語、辞書、コーパスに依存しない汎用的な設計を基本方針としています。 Mecabの由来は、開発者の好物である和布蕪(めかぶ)から名づけられました。

Q&A

解決済

1回答

542閲覧

文中にある特定の単語のベクトルのみを文中から抜き出したい

tako15

総合スコア11

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Mecab

Mecabは、オープンソースの形態素解析エンジンです。 言語、辞書、コーパスに依存しない汎用的な設計を基本方針としています。 Mecabの由来は、開発者の好物である和布蕪(めかぶ)から名づけられました。

0グッド

0クリップ

投稿2022/11/20 10:12

編集2022/11/22 15:18

前提

東北大版BERTを用いて、日本語文をベクトルに変換します。
そのときに、文中にある特定の単語のベクトルのみを文中から抜き出したいです。
(文中の特定の単語ベクトルを2箇所から抜き出し、それらの2単語のcos類似度を求めたいからです。)

足りない点はコメントしていただけると幸いです。

実現したいこと

東北大版BERTを用いて、text.txtの”波紋が広がり終わったあとの池の水面のような表情だ。”をBERTを用いてベクトルに変換します。

このときtext.txtを形態素解析(MeCab)をすると、
'波', '##紋', 'が', '広がり', '終わっ', 'た', 'あと', 'の', '池', 'の', '水面', 'の', 'よう', 'な', '表情', 'だ', '。'
のように分割されています。

このときの’表情’のベクトルのみを抜き出す方法を知りたいです。

発生している問題・エラーメッセージ

今のプログラムだと結果は出てきますが、aとbで新たにベクトルを作り出しており、、text.txtの文中から抜き出せていません。文中から抜き出した単語ベクトルを使えるようにしたいです。

該当のソースコード

text.txt

1波紋が広がり終わったあとの池の水面のような表情だ。

python

1# tohoku-BERT 2from transformers import BertConfig, BertModel 3from transformers import BertJapaneseTokenizer 4from transformers.models.bert_japanese import tokenization_bert_japanese 5 6config = BertConfig.from_json_file('config.json') 7config.output_hidden_states = True # 各層の情報の取り出し 8model = BertModel.from_pretrained('pytorch_model.bin', config=config) 9tknz = BertJapaneseTokenizer(vocab_file='vocab.txt', do_lower_case=False, do_basic_token 10ize=False) 11tknz.word_tokenizer = tokenization_bert_japanese.MecabTokenizer() 12 13# ここまでBERTモデルの読み込みです 14 15import torch 16import numpy as np 17from numpy.linalg import norm 18import sys 19 20# text.txtの文をベクトルに変換する 21def sentence2vec(sentence): 22 sentence = tknz.encode(sentence) 23 sentence = torch.LongTensor(sentence).unsqueeze(0) 24 vec = model(sentence) 25 vec = (vec[2][11]).to('cpu').detach().numpy().copy() 26 # 11層の出力結果をTensor型からnumpy型に変更 27 return vec 28 29 30# cos類似度を算出する 31def cos_similarity(a, b, eps=1e-8): 32 cos = np.dot(a, b) / ( norm(a) * norm(b) +eps ) 33 return cos 34 35 36#text.txtを開く 37with open(sys.argv[1], "r", encoding="utf-8") as f: 38 for sentence in f: 39 vec = sentence2vec(sentence) 40 a = "池の水面" 41 b = "表情" 42 A_vec = model(torch.LongTensor( tknz.encode(a) ).unsqueeze(0)) 43 B_vec = model(torch.LongTensor( tknz.encode(b) ).unsqueeze(0)) 44 45 A_vec = A_vec[2][11]).to('cpu').detach().numpy().copy() 46 B_vec = B_vec[2][11]).to('cpu').detach().numpy().copy() 47 cos = cos_similarity(A_vec, B_vec) 48 print(cos)

補足情報(FW/ツールのバージョンなど)

python3.10.4

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2022/11/21 08:57 編集

.
quickquip

2022/11/21 00:42

vocab.txt を読みこんでおけばいいんじゃないですか? が私の中での回答の筆頭候補でした 「AのようなB の A と B を探してくる方法が分からない」という質問にも読めますが……、正直何を質問したいのか伝わってないです。 書き間違えているだけなのかもしれませんが、 > cos類似度は例文で考えると、”池”と”表情”、”の”と”表情”、”水面”と”表情”の3つのcos類似度の平均をとり、それを”池の水面”と”表情”のcos類似度にします。 の部分は、その操作が何を意味するのかまったく分からなかったです
tako15

2022/11/22 02:53

申し訳ありません。自分自身でもわからなくなっており、何を一番伝えたいか、何を解決したいか曖昧なまま質問してしまいました。改めて一から考えてみると、cos類似度は最終的な出力結果というだけで、今回の一番の疑問とはさほど関係ありませんでした。質問内容を修正させていただきます。
guest

回答1

0

ベストアンサー

「"池の水面"をトークナイズした結果が元の文と同じになる」という前提下ではありますが、
・a と b を tknz.encode した結果から特殊トークンを取り除く
・文をtknz.encode した結果からaやbと同じ長さの部分列を取り出していく
・一致するか調べる
をすればよいと思います。

部分列を取るのはmore_itertools.windowedが楽でしょう。

plain

1>>> from transformers import BertConfig, BertModel 2>>> from transformers import BertJapaneseTokenizer 3>>> from transformers.models.bert_japanese import tokenization_bert_japanese 4>>> config = BertConfig.from_json_file('config.json') 5>>> config.output_hidden_states = True # 各層の情報の取り出し 6>>> model = BertModel.from_pretrained('pytorch_model.bin', config=config) 7>>> tknz = BertJapaneseTokenizer(vocab_file='vocab.txt', do_lower_case=False, do_basic_tokenize=False) 8>>> tknz.word_tokenizer = tokenization_bert_japanese.MecabTokenizer() 9 10>>> s = tknz.encode('波紋が広がり終わったあとの池の水面のような表情だ。') 11>>> a = tknz.encode('池の水面') 12>>> b = tknz.encode('表情') 13 14>>> s 15[2, 3202, 7076, 862, 20696, 13094, 881, 13985, 896, 3156, 896, 21414, 896, 11169, 892, 18731, 882, 829, 3] 16 17>>> a 18[2, 3156, 896, 21414, 3] 19 20>>> b 21[2, 18731, 3] 22 23>>> a_sub = tuple(a[1:-1]) # [CLS] と [SEP] を取り除く。windowed から出てくるのがタプルなのでタプルにする 24>>> b_sub = tuple(b[1:-1]) 25 26>>> from more_itertools import windowed 27 28>>> a_index = None 29 30>>> for i, sub_sequence in enumerate(windowed(s, len(a_sub))): 31... if sub_sequence == a_sub: 32... a_index = i 33... break 34 35>>> b_index = None 36 37>>> for i, sub_sequence in enumerate(windowed(s, len(b_sub))): 38... if sub_sequence == b_sub: 39... b_index = i 40... break 41 42>>> a_index 439 44 45>>> b_index 4615

bのベクトルは該当部分を抜けばいいですね。

plain

1>>> import torch 2>>> s_vec = model(torch.LongTensor(s).unsqueeze(0))[2][11].to('cpu').detach().numpy().copy() 3>>> b_vec = s_vec[0, b_index, :]

aのベクトルは、ナイーブには該当部分の平均をとるとかでしょうか……。あまり自信はないですが

plain

1>>> a_vec = s_vec[0, a_index:a_index+len(a_sub), :].mean(axis=0)

とかでしょうか。(よい書き方かどうか分かりません)

投稿2022/11/22 06:18

quickquip

総合スコア11029

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問