LoginSignup
3
2

More than 3 years have passed since last update.

privateでないAPIがscikit-learn v0.24で削除されたために、unpickleできない経験をしました

Posted at

scikit-learn v0.22 より前に作ったMultiLabelBinarizerが、scikit-learn v0.24以降の入った環境でunpickleできないことを示します。
ちょっとハマった身から言えること:pickleする環境とunpickleする環境のバージョン違いにはご注意ください

環境

macOS
Python 3.7.3

手順

scikit-learn 0.22より前

scikit-learn-0.21.3

ドキュメントのExamplesを用います
https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.MultiLabelBinarizer.html#sklearn.preprocessing.MultiLabelBinarizer

experiment.py

import pickle

from sklearn.preprocessing import MultiLabelBinarizer

mlb = MultiLabelBinarizer()
mlb.fit_transform([{'sci-fi', 'thriller'}, {'comedy'}])
print(list(mlb.classes_))

with open("mlb_021.pkl", "wb") as fout:
    pickle.dump(mlb, fout)
$ python experiment.py
['comedy', 'sci-fi', 'thriller']
$ python -q

対話モードでunpickleします。

>>> import pickle
>>> with open("mlb_021.pkl", "rb") as fin:
...   mlb = pickle.load(fin)
...
>>> list(mlb.classes_)
['comedy', 'sci-fi', 'thriller']
>>> mlb.transform([['sci-fi', 'comedy']])
array([[1, 1, 0]])
>>> type(mlb)
<class 'sklearn.preprocessing.label.MultiLabelBinarizer'>

scikit-learn 0.24以降

pip install -U scikit-learnで0.24.0が入りました。

対話モードでunpickleを試みます(エラーになります)。

>>> import pickle
>>> with open("mlb_021.pkl", "rb") as fin:
...   mlb = pickle.load(fin)
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ModuleNotFoundError: No module named 'sklearn.preprocessing.label'

原因

以下のIssueへの対応でモジュールをprivateにしています。
https://github.com/scikit-learn/scikit-learn/issues/9250

rename file.py into _file.py

それにより、sklearn/preprocessing/label.py(sklearn.preprocessing.label)はsklearn/preprocessing/_label.py(sklearn.preprocessing._label)とrenameされました。
https://github.com/scikit-learn/scikit-learn/commit/15d5ef04df21f1d8db6583c74d1869c3fad36970#diff-e4f17cabd1bed4babf2fbfb7a31a3d955563e0267e8c310fa61629e722a64488

対処法

0.24まで上げなければunpickleはできます(後述するように自己責任でお願いします)。
pip install -U 'scikit-learn<0.24'で0.23.2をインストール。

>>> import pickle
>>> with open("mlb_021.pkl", "rb") as fin:
...   mlb = pickle.load(fin)
...

このとき、バージョン0.24でremoveされるとwarningも出ています。

/.../env/lib/python3.7/site-packages/sklearn/utils/deprecation.py:143: FutureWarning: The sklearn.preprocessing.label module is deprecated in version 0.22 and will be removed in version 0.24. The corresponding classes / functions should instead be imported from sklearn.preprocessing. Anything that cannot be imported from sklearn.preprocessing is now part of the private API.
warnings.warn(message, FutureWarning)

ドキュメントでも通知されていました!
https://scikit-learn.org/dev/whats_new/v0.22.html#clear-definition-of-the-public-api

実際、MultiLabelBinarizertypeを確認すると、renameされた_label.pyを使っています(0.23.2で確認)。

>>> from sklearn.preprocessing import MultiLabelBinarizer
>>> mlb = MultiLabelBinarizer()
>>> type(mlb)
<class 'sklearn.preprocessing._label.MultiLabelBinarizer'>

なお、scikit-learnのバージョンが違うことのWarningも出ますので、文面にあるように自己責任でお願いします。

/.../env/lib/python3.7/site-packages/sklearn/base.py:334: UserWarning: Trying to unpickle estimator MultiLabelBinarizer from version 0.21.3 when using version 0.23.2. This might lead to breaking code or invalid results. Use at your own risk.
UserWarning)

メモ

pip install -Udocs)にバージョン込みで指定すると、パッケージのバージョンを自由に変えられます(--upgradeオプションですが、ダウングレードもできます)。
👉バージョン指定の仕方について
https://pip.pypa.io/en/stable/user_guide/#understanding-your-error-message

TODO:pickleの仕組みを今よりももう少し理解したいです

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2