14
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

TensorFlow 使ってるときの json.dumps と numpy.float32 の罠

Posted at

背景

TensorFlow の出力を json で dump して...などとしていたときに次のようなエラーが出て、少しはまったので書く。
もしかすると常識かもしれないが、自分は知らなかった。

TypeError: Object of type 'float32' is not JSON serializable

例えば、外から API 叩いて TensorFlow で書いたモデルの出力を json にして返すようなときにはまる。

問題

  1. TensorFlow で書いたあるネットワークの出力(実数値) x の List を受け取る
  2. それを json で dump して返す ( json.dumps(x))

上記のようなシンプルな関数があったとき、実行すると下記のエラーがでた。

TypeError: Object of type 'float32' is not JSON serializable

原因

結論: json.dumpsnumpy.float32 を受け取れず、上記の例外が発生する。

計算時、変数の型は次のようになる。

  1. TensorFlow では tf.float32 で定義されている
  2. 出力は numpy の型になるので、session.run の結果 numpy.float32 の List を受け取る
  3. そのまま json.dumps の引数が numpy.float32 の List が渡り、エラーになる。

なぜこうなるかというと...

python の float はCの double なので、 64bit である。

numpy には、 numpy.float32numpy.float64 があり(16,128もある)、何も考えなければ python のデフォルトと同じ numpy.float64 が使われる。

ただし、 TensorFlow では基本的に tf.float32 を使うことが多い(最近は float16 とかも?)ため、そのまま出力すると numpy.float32 の値になる。
別に numpy.float32 でも普通の用途で困ることはないが、なぜか json.dump json.dumps では対応しておらず、エラーになった。
numpy.float64 では、自動で python の float にキャストされる?(未確認)ので問題ないようだ。

19.2. json — JSON エンコーダおよびデコーダ 及び 変換表 を見ると、デフォルトでサポートされる型の中に

int、float と int や float の派生列挙型

と書かれていて、float 32 などについては書かれていない。
派生列挙型ってなんだろう、基数が違うとかかな?
残念ながら numpy.float32 は上述の通り今の所エラーになる。

一応コードで見る

import numpy as np
pa64 = [1., 1., 1.]
npa64 = np.ones([3])
npa32 = np.ones([3], dtype=np.float32)
print('pa64: ', type(pa64[0]))
print('npa64: ', type(npa64[0]))
print('npa32: ', type(npa32[0]))
# outputs
pa64:  <class 'float'>
npa64:  <class 'numpy.float64'>
npa32:  <class 'numpy.float32'>
import json
json.dumps({'pa64': pa64[0]})
# '{"pa64": 1.0}'
json.dumps({'npa64': npa64[0]})
# '{"npa64": 1.0}'
json.dumps({'npa32': npa32[0]})
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-6-2aa16547afeb> in <module>()
----> 1 json.dumps({'npa32': npa32[0]})

~/.pyenv/versions/3.6.5/lib/python3.6/json/__init__.py in dumps(obj, skipkeys, ensure_ascii, check_circular, allow_nan, cls, indent, separators, default, sort_keys, **kw)
    229         cls is None and indent is None and separators is None and
    230         default is None and not sort_keys and not kw):
--> 231         return _default_encoder.encode(obj)
    232     if cls is None:
    233         cls = JSONEncoder

~/.pyenv/versions/3.6.5/lib/python3.6/json/encoder.py in encode(self, o)
    197         # exceptions aren't as detailed.  The list call should be roughly
    198         # equivalent to the PySequence_Fast that ''.join() would do.
--> 199         chunks = self.iterencode(o, _one_shot=True)
    200         if not isinstance(chunks, (list, tuple)):
    201             chunks = list(chunks)

~/.pyenv/versions/3.6.5/lib/python3.6/json/encoder.py in iterencode(self, o, _one_shot)
    255                 self.key_separator, self.item_separator, self.sort_keys,
    256                 self.skipkeys, _one_shot)
--> 257         return _iterencode(o, 0)
    258 
    259 def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,

~/.pyenv/versions/3.6.5/lib/python3.6/json/encoder.py in default(self, o)
    178         """
    179         raise TypeError("Object of type '%s' is not JSON serializable" %
--> 180                         o.__class__.__name__)
    181 
    182     def encode(self, o):

TypeError: Object of type 'float32' is not JSON serializable

確かに3つ目だけ落ちる。

その他

json がダメってことは、python の他のモジュールでもダメなやつがあるかも...。

また、作業中に原因が分かり float64 にキャストしてから作業していると、 float32 のときは大丈夫だったのに float64 のときは問題が発生する(例えば、確率を扱っているときは List の合計が1になるはずが、float64 にすると少しズレる (1.000000002等) になる)なんてこともあったので、少しめんどくさい。
気をつけましょう。

14
7
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
14
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?