Pickle化できないオブジェクトをPickle化する
Published in
2 min readJun 14, 2018
現在、機械学習における前処理をscikit-learnのPipeline感覚でつなげてしかも保存できる処理を開発しています。
前処理には当然単語の分割といった処理も入るのですが、単語の分割に使用するTokenizer(今回はMeCab/Janome、もしくはspaCyのインスタンス)は複雑なオブジェクトで、Pickle(scikit-learn.external joblib)で保存しようとすると当然エラーになります。
Tokenizerは言語だけ指定して作成する形なので、Tokenizerを丸ごと保存するという贅沢は言わないので、saveするときは除いて、loadするときに(保存しておいた)言語を指定して作り直すということはできないか、ということで調査をしました。
Tips
この記事がとても参考になりました。
ユーザ定義クラスのpickle, unpickle処理のまとめ
この中の「__init__を呼ばないと生成できないオブジェクト」を参考に、トークナイズを行うクラスは「__init__を呼ばないと生成できない」クラスに見せかけ、__init__処理(言語を指定してTokenizerを作成する)を__reduce_ex__で行うようにしました。
- __reduce_ex__(__reduce__)ではオブジェクトのpickle/unpickleを行う方法を記述できる(イメージ的には、復元に必要な情報をreturnする)。
- __reduce__と__reduce_ex__は、整数の引数(protocol version)を取る点以外は違いがなく、__reduce_ex__が実装されている場合は__reduce_ex__が優先される
- __reduce_ex__は復元に必要な文字列かタプルを返す関数で、通常はタプルを返す。
- 何を返すべきか?はドキュメントを見ても明示されていないが、クラス/初期化に必要な変数を返すよう。pickleするときにクラス定義・初期化に必要な変数を記録しておき、unpickleするときにはそれらを読み込みコンストラクタ(__init__)を起動しインスタンスを復元する。