CUBE SUGAR CONTAINER

技術系のこと書きます。

Word2Vec 形式のファイルフォーマットについて

Word2Vec では、Skip-gram や CBOW といったタスクを学習させたニューラルネットワークの隠れ層の重みを使って単語を特徴ベクトルにエンコードする。 つまり、Word2Vec で成果物として得られるのは、コーパスの各単語に対応する特徴ベクトルになる。 今回は、単語の特徴ベクトルを永続化するために使われる、Word2Vec 形式とか呼ばれているファイルフォーマットについて調べたので書いてみる。

使った環境は次のとおり。

$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.14.6
BuildVersion:   18G4032
$ python -V
Python 3.7.7

下準備

はじめに、学習済みモデルを取得するのに使うコマンドをインストールしておく。

$ brew install gzip wget

また、動作確認に使うための Python パッケージとして gensim をインストールしておく。

$ pip install gensim

Word2Vec 形式 (バイナリ)

Word2Vec 形式と呼ばれているフォーマットには、テキスト形式とバイナリ形式の 2 種類がある。 はじめに、バイナリ形式から紹介する。 たとえば、本家 Google が配布している学習済み Word2Vec モデルはバイナリ形式になっている。

code.google.com

上記から「GoogleNews-vectors-negative300.bin.gz」というファイルをダウンロードしてこよう。 ただし、圧縮された状態で 1.5GB あるので結構時間がかかる。

ダウンロードできたら Python の REPL を起動する。

$ python

Python の gzip モジュール経由でダウンロードしたファイルを開く。

>>> import gzip
>>> f = gzip.open('GoogleNews-vectors-negative300.bin.gz', mode='rb')

バイナリ形式といっても、最初の一行は ASCII 文字列で記述されている。 ここには、スペースで区切られたコーパスの単語 (語彙) 数と、単語の特徴ベクトルの次元数が入る。 今回の学習済みモデルでは語彙が 300 万語、特徴ベクトルが 300 次元とわかる。

>>> header = f.readline()
>>> header
b'3000000 300\n'

この数字はバイナリの読み込みに使うので数値に変換して変数に入れておこう。

>>> words, veclen = [int(x) for x in header.strip().split()]
>>> words, veclen
(3000000, 300)

以降のデータには、単語と特徴ベクトルがスペース区切りで記録される。 はじめに、スペースまでを単語として読み込むための関数を用意しよう。

>>> def readword(f):
...    """単語を読み込むための関数"""
...     word = []
...     while True:
...         c = f.read(1)
...         if c == b' ':
...             break
...         if c == b'':
...             raise EOFError()
...         if c != b'\n':
...             word.append(c)
...     return b''.join(word)
... 

ファイルオブジェクトを読むと、単語として '</s>' が得られた。 いや、これ HTML のタグだから、本来は除外すべき単語だと思うんだけどね。

>>> readword(f)
b'</s>'

単語を取り出せたので、次は対応する特徴ベクトルを読み出す。 特徴ベクトルでは、それぞれの次元が倍精度浮動小数点 (32 ビット) として記録されている。 そこで、まずは読み出すべき特徴ベクトルのバイト数を計算しておこう。

>>> import numpy as np
>>> np.dtype(np.float32).itemsize
4
>>> bin_weights_len = np.dtype(np.float32).itemsize * veclen
>>> bin_weights_len
1200

今回であれば 300 次元 x 4 バイト = 1,200 バイトとなった。

計算した特徴ベクトルのバイト数を、ファイルオブジェクトから読み出す。

>>> bin_weights = f.read(bin_weights_len)

読みだしたバイト列を、NumPy を使って配列に変換しよう。 これが '</s>' という単語に対応する特徴ベクトルということ。

>>> word_weights = np.frombuffer(bin_weights, dtype=np.float32)
>>> word_weights
array([ 1.1291504e-03, -8.9645386e-04,  3.1852722e-04,  1.5335083e-03,
        1.1062622e-03, -1.4038086e-03, -3.0517578e-05, -4.1961670e-04,
       -5.7601929e-04,  1.0757446e-03, -1.0223389e-03, -6.1798096e-04,
...(snip)...
       -9.8419189e-04, -5.4931641e-04, -1.5487671e-03,  1.3732910e-03,
       -6.0796738e-05, -8.2397461e-04,  1.3275146e-03,  1.1596680e-03,
        5.6838989e-04, -1.5640259e-03, -1.2302399e-04, -8.6307526e-05],
      dtype=float32)

以降は同様に単語と特徴ベクトルが交互に記録されている。 たとえば、もう一単語読み出すと 'in' という単語が得られた。 あとは、語彙の数だけ繰り返せば良いことがわかる。

>>> readword(f)
b'in'

念のため gensim を使って答え合わせをしよう。 学習済みモデルを読み込む。 この処理には数分単位で時間がかかる。

>>> import gensim
>>> model = gensim.models.KeyedVectors.load_word2vec_format('GoogleNews-vectors-negative300.bin.gz', binary=True)

読み込んだモデルを使って '</s>' に対応する特徴ベクトルを得る。

>>> model.wv['</s>']
array([ 1.1291504e-03, -8.9645386e-04,  3.1852722e-04,  1.5335083e-03,
        1.1062622e-03, -1.4038086e-03, -3.0517578e-05, -4.1961670e-04,
       -5.7601929e-04,  1.0757446e-03, -1.0223389e-03, -6.1798096e-04,
...(snip)...
       -9.8419189e-04, -5.4931641e-04, -1.5487671e-03,  1.3732910e-03,
       -6.0796738e-05, -8.2397461e-04,  1.3275146e-03,  1.1596680e-03,
        5.6838989e-04, -1.5640259e-03, -1.2302399e-04, -8.6307526e-05],
      dtype=float32)

すると、先ほど手動で読みだした数値と一致していることがわかる。

Word2Vec 形式 (テキスト)

続いてはテキスト形式について紹介する。 ただし、バイナリ形式に比べると非常に単純なので説明は一瞬でおわる。 なお、テキスト形式の Word2Vec モデルとして、あまり良いものが見当たらなかったので Facebook の fastText を使うことにした。

次のコマンドを使って配布されているモデルの先頭 3 行を読み出そう。

$ wget -qO - https://dl.fbaipublicfiles.com/fasttext/vectors-crawl/cc.en.300.vec.gz | gzip -d | head -n 3
2000000 300
, 0.1250 -0.1079 0.0245 -0.2529 0.1057 -0.0184 0.1177 -0.0701 -0.0401 -0.0080 0.0772 -0.0226 0.0893 -0.0487 -0.0897 -0.0835 0.0200 0.0273 -0.0194 0.0964 0.0875 0.0098 0.0453 0.0155 0.1462 0.0225 0.0448 0.0137 0.0570 0.1764 -0.1072 -0.0826 0.0173 0.1090 0.0207 -0.1271 0.2445 0.0375 -0.0209 -0.0445 0.0540 0.1282 0.0437 0.0588 0.0984 0.0539 0.0004 0.1290 0.0242 -0.0120 -0.0480 0.0346 -0.0664 -0.0330 -0.0625 -0.0708 -0.0579 0.1738 0.4448 0.0370 -0.1001 -0.0032 0.0359 -0.0685 -0.0361 0.0070 0.1316 -0.0945 -0.0610 0.0178 -0.0763 -0.0192 0.0033 0.0056 0.1878 -0.0754 -0.0095 0.0446 -0.0588 0.0244 -0.0251 -0.0493 0.0308 -0.0359 -0.1884 -0.0988 0.1887 0.0459 -0.0816 -0.1524 -0.0375 -0.0692 0.0427 -0.0471 -0.0086 -0.2190 -0.0064 0.0877 -0.0074 -0.1400 -0.0156 0.0161 0.1040 -0.1445 -0.0719 -0.0144 -0.0293 -0.0126 0.0619 -0.0373 -0.1471 -0.2552 -0.0685 0.2892 -0.0275 0.0436 0.0311 0.0249 0.0142 0.0403 0.1729 0.0023 -0.0255 -0.0212 0.0701 -0.0727 0.0279 0.1151 -0.0394 -0.0962 -0.0598 -0.0459 -0.0326 -0.2317 0.0945 0.0110 -0.2511 0.1087 -0.0699 0.0359 0.0208 -0.0536 0.0478 0.0178 0.0095 0.0354 -0.7726 -0.0790 0.0472 0.0584 -0.1013 0.0448 -0.1202 0.0376 0.0510 -0.0616 0.4321 0.0179 0.0263 0.0271 0.0473 -0.0951 -0.2261 0.0261 0.0262 -0.0235 -0.0369 -0.1655 -0.0697 0.0122 -0.0303 0.0427 0.0787 -0.0360 0.0206 -0.0068 0.1257 0.0447 -0.0776 -0.1122 -0.0291 0.4654 0.1010 0.4440 0.0095 0.1312 0.0766 0.0873 -0.0878 -0.0296 0.0046 0.0416 -0.0134 0.0571 -0.0109 -0.0655 0.0082 -0.0563 -0.0830 -0.0550 -0.0688 0.0091 -0.0677 -0.1001 0.0200 -0.0979 0.1134 -0.0188 0.0136 0.0782 0.0207 0.0133 -0.0492 -0.0139 0.0123 0.0360 0.1249 0.0503 0.0015 0.1246 -0.0897 -0.0121 -0.0182 0.2245 -0.0313 -0.1596 0.0073 -0.0772 -0.0830 -0.0716 0.0112 0.0218 0.1245 -0.0361 0.0312 0.0652 0.0560 0.0670 0.0709 -0.0248 0.0449 -0.1296 0.1408 -0.0359 1.1585 0.0027 0.0185 0.0549 0.1367 0.2742 -0.0472 -0.0414 -0.0548 -0.0911 -0.0015 -0.1613 0.0179 -0.0040 0.0610 0.0559 0.1138 0.2978 -0.1511 -0.0079 -0.0838 0.0296 -0.1041 0.1627 -0.0670 0.0504 -0.0420 -0.0020 0.1840 0.0596 0.0448 0.0989 -0.2157 -0.0117 0.2142 -0.1672 -0.0444 0.2045 -0.4620 -0.0482 0.0688 -0.0304 0.0478 0.1583 0.0920 0.0949 0.0650 -0.0398 -0.1376 -0.0436 0.0578 0.0188 0.0148 0.2305 -0.0696 -0.0215
the -0.0517 0.0740 -0.0131 0.0447 -0.0343 0.0212 0.0069 -0.0163 -0.0181 -0.0020 -0.1021 0.0059 0.0257 -0.0026 -0.0586 -0.0378 0.0163 0.0146 -0.0088 -0.0176 -0.0085 -0.0078 -0.0183 0.0088 0.0013 -0.0938 0.0139 0.0149 -0.0394 -0.0294 0.0094 -0.0252 -0.0104 -0.2213 -0.0229 -0.0089 -0.0322 0.0822 0.0021 0.0282 0.0072 -0.0091 -0.0352 -0.0178 -0.0706 0.0630 -0.0092 -0.0223 -0.0056 0.0515 -0.0307 0.0436 -0.0110 -0.0555 0.0089 -0.0673 0.0105 0.0574 0.0099 -0.0283 0.0470 0.0053 0.0030 0.0007 0.0443 0.0069 -0.0334 0.0091 -0.0076 0.0066 0.0917 0.0311 0.0543 0.0282 -0.0200 -0.0334 0.0053 0.0364 0.2249 0.0928 -0.0123 0.0086 -0.0599 0.0676 0.0402 0.0012 0.0464 -0.0437 0.0059 0.0917 -0.0412 -0.0151 -0.0231 0.0095 0.0588 0.0279 0.0647 -0.0568 -0.0130 0.0474 0.0354 -0.0121 -0.0077 -0.1306 0.0134 -0.0506 0.0111 0.0119 -0.0221 0.0394 0.0221 0.0245 0.0039 0.1146 0.0228 -0.0468 -0.0459 -0.0189 0.0076 -0.0302 -0.0348 -0.0289 -0.0399 0.0245 -0.0102 0.0578 -0.0388 -0.0117 -0.0304 0.2466 -0.0111 0.0356 0.0046 0.2094 -0.1022 0.0336 0.0688 -0.0708 0.0269 -0.0423 0.0077 -0.0267 0.0072 0.0035 0.0351 -0.0063 -0.4462 0.0105 -0.0120 -0.0449 -0.1696 0.0504 0.0930 -0.0044 -0.0041 0.0322 0.2026 0.0613 -0.0295 0.0228 -0.0190 0.0173 0.1480 -0.0175 -0.0125 0.0687 0.0333 -0.0303 0.0428 0.0051 0.0228 0.0104 0.0731 0.0079 -0.0051 0.0543 -0.0325 0.0512 0.0288 -0.0586 -0.0000 0.0493 0.0166 -0.0143 0.0359 0.0543 -0.0005 -0.0589 0.0162 -0.0222 -0.0199 0.0235 -0.0678 0.0179 0.0033 0.0114 0.0473 -0.0443 0.0323 0.0195 -0.0647 0.3388 0.0699 -0.0215 -0.0244 -0.0034 -0.0034 -0.0622 0.0123 0.0375 -0.0197 0.0241 -0.0877 0.0201 -0.0061 -0.0256 -0.0191 -0.0264 0.0190 -0.0422 0.0251 0.0825 -0.0096 0.1288 0.0621 0.0538 0.0189 0.0422 0.1803 -0.0010 -0.0328 -0.0559 -0.0157 0.0490 0.0352 -0.0417 0.0159 -0.0766 -0.0657 0.0497 0.0102 0.1471 -0.0711 -0.1469 0.4737 -0.0169 -0.0051 0.0159 0.0550 -0.0634 -0.0210 0.0122 0.0269 0.0060 0.0664 0.0106 -0.0705 -0.0207 -0.0784 -0.0291 -0.0283 -0.1568 -0.0393 0.0050 0.0204 -0.0026 0.0436 0.0279 -0.0393 0.0367 -0.0042 -0.0156 -0.0733 -0.1637 0.0652 -0.0062 -0.0650 -0.1984 -0.0411 -0.1534 0.0020 0.0133 -0.2364 -0.0528 -0.0042 -0.0447 0.0112 -0.0332 -0.0550 0.0013 0.0169 -0.0439 -0.0578 0.0223 -0.0777 -0.0432 -0.0251 0.2370 0.0004 -0.0042

先頭の行は、バイナリ形式と同じでコーパスの語彙数と特徴ベクトルの次元数になっている。 そして、以降は各行が単語と特徴ベクトルを表している。 最初の列が単語で、以降はスペース区切りで特徴ベクトルが浮動小数点の文字列として記録されている。

テキスト形式はとても単純なので、答え合わせをする必要もないかな。 ちなみに、単語の特徴ベクトルはモデルや配布元によってフォーマットがかなりバラバラ。 ここで紹介した Word2Vec 形式は、たくさんあるフォーマットのひとつに過ぎない。

いじょう。

ゼロから作るDeep Learning ❷ ―自然言語処理編

ゼロから作るDeep Learning ❷ ―自然言語処理編

  • 作者:斎藤 康毅
  • 発売日: 2018/07/21
  • メディア: 単行本(ソフトカバー)