Pickleは便利なのでよく使います。だって便利なんだもの。結構でかいファイルでもそれなりに速いので、なんでもPickleで保存するのがいいと思っていましたが、 そうでもないようです。やっぱりそうでした。
最近、自然言語処理にはまっていて、下記のサイトから学習済みのWord2Vecをダウンロードして読みこませてみました。なんか、テキストファイルじゃないとダメらしく、読み込みにめちゃくちゃ時間がかかったので、とりあえず、漬物と、ライブラリのsave/loadの両方で保存して速度を計ってみました。
検索したらすぐ出てきますが、データはここからいただきました。
学習には、めちゃくちゃ時間がかかったろうに。マジ感謝。
こういう人がいるおかげで、我々一般市民は、CPUをアホみたいに回すことなく機械学習に触れられ、温暖化の低減にもつながるんですねー。へたをすると、Wikipedia2Vecの人たちの方がグレタより、環境意識が高そうですね!というわけで、お役立ち情報はここまで(タグに自然言語処理をいれたのは、このリンクのためだけです)。
さて、gensimで外部から学習済みのモデルを読み込む場合、KeyedVectorsという、読み出しに特化して効率化されたデータ形式を使うようで、いただいたデータもそのフォーマットになっているようでした。
ちなみに、データは解凍しないと読めないそうです。というわけで、おもむろに回答して、APIを使って読み込んでみます。
from gensim.models import KeyedVectors
model = KeyedVectors.load_word2vec_format('enwiki_20180420_100d.txt')
でかいデータはHDDに保存することにしているので、それが災いしたのかもしれませんが、結構、それなりに時間がかかりました(数分)。で、これを何回も読むのは、北極に生息する白クマさんに対する脅威になり得ると判断したため(そして、インフレでエネルギー価格も上がっていることだし)、バイナリー・フォーマットとして、再度保存しなおしました。ところが、gensimのマニュアルを見てみると、saveというメソッドがちゃんとあるではないですか。というわけで、保存するならそれを使うのがベスト、と思われたのですが、pickleに絶対的な信頼を置いていた私は、「まー、そんなに違わないしょ!」などと余計なことを考えて両方で保存して読みだすという実験をしてみました。
<追記>
pickleに思わぬぬれぎぬを着せてしまったので、内容を撤回しました!!!いい加減に書くからこういうことになるんですね。どうやら、続けて実験したのでスラッシングが起きてて、遅くなっただけの模様です。一度Pythonのプロセスを終了→再起動して再度試したところ、全然遅くなかったです!
結論:なんでも漬物にしていいようです。
>>> def bar():
print(datetime.now())
with open('en_wiki_100d.pickle','rb') as fd:
a = pickle.load(fd)
print(datetime.now())
return a
>>> model=bar()
2022-07-12 14:45:21.011313
2022-07-12 14:45:55.910009
プロセスを再起動すると、APIのsave/loadでもこんなもんです。
def load_model():
print(datetime.now())
model = KeyedVectors.load('en_wiki_100d.bin')
print(datetime.now())
return model
model = load_model()
2022-07-12 14:54:30.494890
2022-07-12 14:55:14.950091
>>>
<追記ここまで>
保存にかかった時間はたいして変わらないのですが…
>>> model.save('en_wiki_100d.bin')
>>>
>>> from datetime import datetime
>>> def foo():
print(datetime.now())
a = KeyedVectors.load('en_wiki_100d.bin')
print(datetime.now())
return a
>>> modelA=foo()
2022-07-12 14:10:05.879484
2022-07-12 14:11:02.816150
>>>
>>> def bar():
print(datetime.now())
with open('en_wiki_100d.pickle','rb') as fd:
a = pickle.load(fd)
print(datetime.now())
return a
>>> modelB=bar()
2022-07-12 14:12:06.455831
2022-07-12 14:17:34.547221
Traceback (most recent call last):
File "<pyshell#526>", line 1, in <module>
modelB=bar()
File "<pyshell#525>", line 5, in bar
print(datetime.now())
File "D:\WPy64-3740\python-3.7.4.amd64\lib\site-packages\idlexlib\idlefork\idlelib\PyShell.py", line 1344, in write
return self.shell.write(s, self.tags)
KeyboardInterrupt
圧倒的な差が出ました。Pickleはずーっと待ってても全然読み込めないので、読み込みを断念しました。まあ、当たり前か。というわけで、何でもかんでも漬物というのは良くないようです。
<注意>
この結論は早とちりでした。全然ウソです。Pickleでも遅くはなりませんでした。好きなほうを使えばいいと思います。(追記を参照のこと)
<注意終わり>
<注意2>
とはいえ、やっぱりダメなケースがあるようです。100次元でうまくいったので、じゃ300次元でとおもって300次元のデータを漬物にしようと思ったら…「4GB以上のファイルは無理っす」と例外を吐いて死亡しているのを確認しました。えー!でも、私んちのPythonは64bitだぜぃ?だめ?
Python 3.7.4 (tags/v3.7.4:e09359112e, Jul 8 2019, 20:34:20) [MSC v.1916 64 bit (AMD64)] on win32
というわけで、4GBを越えるファイルだと漬物にできないというケースがあるようです。