機械学習・自然言語処理の勉強メモ

学んだことのメモやまとめ

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層の重みにセットできる。