Help us understand the problem. What is going on with this article?

numpy.load()で`Object arrays cannot be loaded when allow_pickle=False`が発生する場合の対処法

More than 1 year has passed since last update.
  • numpy 1.16.3 以降

現象

Pythonコードの例

np.load('/path/to/file.npy')

発生するエラーの例

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-37-1db66562b57b> in <module>
----> 1 np.load('tmp.npy')

~/venv/aep/lib/python3.7/site-packages/numpy/lib/npyio.py in load(file, mmap_mode, allow_pickle, fix_imports, encoding)
    451             else:
    452                 return format.read_array(fid, allow_pickle=allow_pickle,
--> 453                                          pickle_kwargs=pickle_kwargs)
    454         else:
    455             # Try a pickle

~/venv/aep/lib/python3.7/site-packages/numpy/lib/format.py in read_array(fp, allow_pickle, pickle_kwargs)
    720         # The array contained Python objects. We need to unpickle the data.
    721         if not allow_pickle:
--> 722             raise ValueError("Object arrays cannot be loaded when "
    723                              "allow_pickle=False")
    724         if pickle_kwargs is None:

ValueError: Object arrays cannot be loaded when allow_pickle=False

原因

numpy v1.16.3 より、numpy.load()関数の挙動が変更されたため。

変更前 変更後
allow_pickleオプションの省略時のデフォルト値はTrue allow_pickleオプションの省略時のデフォルト値はFalse

解決方法

後述するセキュリティ上の懸念がないことを確認した上で、以下のようにallow_pickleオプションを指定してやれば良い。

np.load('/path/to/file.npy', allow_pickle=True)

解説

numpy行列とdtype

numpy行列(np.ndarray)は数値だけでなく文字列やPythonオブジェクトを格納することができる。格納された値の種類は、dtypeという属性へと反映されている。

numpy v1.16.0の脆弱性

Pythonオブジェクトが含まれたnumpy行列(をシリアライズしたファイル)をnp.load()によってでシリアライズする際に、悪意のあるコードを実行できてしまうという脆弱性が報告されている。(ただしこの脆弱性に関しては反論がある)

そこでv1.16.3より、np.load()のデフォルトの挙動が前述したように変更され、dtypeがPythonオブジェクトである場合に、allow_pickle=FalseならばValueErrorをスローするようになった。
より安全サイドへ倒すための仕様変更と言える。

セキュリティ上の懸念

当然のごとく、信頼できないファイルに対してnp.load(allow_pickle=True)してはいけない。前節で述べたように、任意のコードを実行できてしまう可能性がある。

Jupyter等によるデータ整形や機械学習など、アドホックなコードなら普通は問題ない1。注意すべきはPythonを用いたアプリケーション開発者である。

NGな例

ユーザからアップロードされたファイルに対してnp.load(allow_pickle)する

OKな例

システム内でシリアライズしたファイルをnp.load(allow_pickle)する

これってBreaking Change じゃないの?

アプリケーションの挙動が変わってしまうので、当然Breaking Change(後方互換性のない変更)だと思う。

Pythonの数値計算系のライブラリには、デフォルト値の変更ならセーフみたいな風潮があるかもしれない。2リビジョンアップだから大丈夫でしょう、とか思っていたら痛い目に合う。
他の言語から参入したアプリケーションエンジニアはよく注意されたい。


  1. 悪意のある同僚(?)からもらった*.npyファイルなら問題ある。 

  2. 他の例としてはsklearn.ensemble.RandomForestClassifiern_estimatorのデフォルト値など 

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away