Pytorch:単語のベクトル表現をセットする(torchtext)
はじめに
Pytorchの処理で学習済みの単語分散表現(Word2Vec, Glove等)を使いたい場合がある。
直接、Embedding層にセットする場合が以下の方法で問題ない。
kento1109.hatenablog.com
前処理として、torchtext
を利用する場合はそうはいかない。
torchtext
はコーパスから単語の辞書作成、インデックス化、バッチ化、パディングなど色々と便利なことが出来る。この利便性を享受するためには、torchtext
で作成する辞書の単語とインデックスのマッピング情報を利用しなければならない。
つまり、このマッピング情報に従い、学習済みの単語分散ベクトルもマッピングさせる必要がある。
調べたところ、fasttext,Gloveなどの単語分散表現をロードする方法と、独自で作成した単語分散表現をベクトルにセットする方法の2つのがあった。
事前準備
まず、テキストからデータを読み込んで辞書を作成するところまでやっておく。
from torchtext import data, datasets TEXT = data.Field(sequential=True, use_vocab=True) pos = data.TabularDataset( path=base_path + "/word.txt",format='csv', fields=[('text', TEXT)]) TEXT.build_vocab(pos) vocab_ = TEXT.vocab len(vocab_) # 23
vocab_.itos ['<unk>', '<pad>', u'pen', u'apple', u'book', u'room', u'soccer', u'body', u'cat', u'desk', u'note', u'battle', u'bed', u'cake', u'car', u'dance', u'dog', u'girl', u'light', u'like', u'love', u'mother', u'work']
load_vectors
まず、torchtextでロード可能な単語分散表現をロードする方法。
vocab_.load_vectors("fasttext.simple.300d")
等と書くと、単語分散表現がダウンロード&ロードされる。
また、辞書内の単語が読み込んだ単語分散表現に存在すれば、対応するベクトルが辞書のインデックスとマッピングされる。
指定可能なデータに関しては以下参照
github.com
vocab_.vectors 0.0000 0.0000 0.0000 ... 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 ... 0.0000 0.0000 0.0000 -0.0547 0.6329 0.1145 ... 0.2013 -0.2333 -0.2171 ... ⋱ ... -0.1162 -0.3368 0.0646 ... -0.2396 -0.2519 -0.4972 0.1560 0.0393 -0.3019 ... -0.2278 -0.2299 -0.4250 0.3481 -0.0438 0.5359 ... 0.2223 0.3393 -0.3562 [torch.FloatTensor of size 23x300]
「辞書内の単語数×分散次元数のテンソル型行列」になっていることが分かる。
※(1,2番目(<unk>
,<pad>
)は単語分散表現に存在しないので零ベクトルとなる。)
set_vectors
次に独自で作成した単語分散表現をベクトルにセットする方法。
日本語の分散表現などを考える場合、こっちの方がよく使うと思われる。
基本的な流れは同じ。
ただし、事前にセットする単語分散表現と単語インデックスをロードしておく必要がある。
単語分散表現は、Tensor
型の行列、単語インデックスは、dict
型で定義しておく。
単語インデックスは、
dic['string'] # 10
などのように単語分散表現の行番号とマッピングさせる必要がある。
ロードの方法は任意だが、torchwordemb
を使うと、一行で両方ロードできる。
import torchwordemb w2v, vec = torchwordemb.load_word2vec_text(path + "word2vec.test.txt")
使い方は下記参照
github.com
さて、以下ように必要なデータがロードができたとする。
w2v, vec = torchwordemb.load_word2vec_text(path + "word2vec.test.txt") print(type(vec)) # <class 'torch.FloatTensor'> print(vec.size()) # torch.Size([10, 300]) print(w2v["dog"]) # 9
ちなみに、word2vec.test.txtはこんなテキストファイル。
10 300 apple 0.04656 0.21318 -0.0074364 -0.45854 ... pen -0.25539 -0.25723 0.13169 -0.042688 ... desk -0.12559 0.01363 0.10306 -0.10123 ... girl -0.076947 -0.021211 0.21271 -0.72232 soccer -0.25756 -0.057132 -0.6719 -0.3808 love 0.038466 -0.039792 0.082747 -0.38923 room -0.44399 0.12817 -0.25247 -0.18582 ... body -0.29712 0.094049 -0.096662 -0.344 ... dance 0.6947 0.22184 0.10526 0.012382 ... dog -0.001272 0.36514 -0.077363 -0.26559 ...
これを以下のようにして辞書のベクトルにセットする。
vocab_.set_vectors(stoi=w2v, vectors=vec, dim=300)
行列を確認すると、
vocab_.vectors 0.0000 0.0000 0.0000 ... 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 ... 0.0000 0.0000 0.0000 -0.2554 -0.2572 0.1317 ... -0.2329 -0.1223 0.3550 ... ⋱ ... 0.0385 -0.0398 0.0827 ... -0.3343 0.0118 0.0597 0.0000 0.0000 0.0000 ... 0.0000 0.0000 0.0000 0.0000 0.0000 0.0000 ... 0.0000 0.0000 0.0000 [torch.FloatTensor of size 23x300]
と、load_vectorsと同じように「辞書内の単語数×分散次元数のテンソル型行列」になっていることが分かる。
また、3行目は「pen」のベクトル表現であることが分かる。
念のため、辞書での「pen」のインデックスを確認すると、
vocab_.stoi['pen'] # 2
と一致していることが分かる。
(vocab_
は0から始まるので、実際は3番目)
辞書のベクトルをロードする方法・セットする方法、いずれの場合も単語分散行列はTensor型なので、これをembedding層の重みにセットできる。