「Kerasのto_categoricalの挙動ってちょっと変わってるよね」という話
今日はマニアックな話。
Kerasを使っている人なら、to_categorical関数を使ったことがある人は多いのではないかと思う。to_cateogorical関数をいつ使うかというと、正解クラスをone-hotエンコーディングして出力に与えたいときに使うことが多い。Keras 2.2.0だと以下のように動作する。
>>> from keras.utils.np_utils import to_categorical >>> to_categorical([[1, 3]], num_classes=4) array([[[0., 1., 0., 0.], [0., 0., 0., 1.]]], dtype=float32) >>> to_categorical([[1, 3]], num_classes=4).shape (1, 2, 4)
ところが、系列長が1
の入力を渡すと面白い挙動を示す。
>>> to_categorical([[1]], num_classes=4) array([[0., 1., 0., 0.]], dtype=float32) >>> to_categorical([[1]], num_classes=4).shape (1, 4)
なんと、(1, 1, 4)にならない!
では、keras.backendのone_hotはどうなのかというと、想定通りの動きを示す。
>>> import keras.backend as K >>> K.one_hot([[1]], num_classes=4) <tf.Tensor 'one_hot:0' shape=(1, 1, 4) dtype=float32> >>> K.eval(K.one_hot([[1]], num_classes=4)) array([[[0., 1., 0., 0.]]], dtype=float32)
バグなのか?と思ってソースを見たところ、理由はわからないが意図的にやっていることは間違いない。2017/11/15日のcommitで仕様が変わっている。
以下のIssueでも議論している。
理由があろうがなかろうが使用者的には困ることがある。そういうときは以下のようにnumpyのexpand_dims
を使うととりあえず解決できる。
>>> y = to_categorical([[1]], num_classes=4) >>> y.shape (1, 4) >>> y = y if len(y.shape) == 3 else np.expand_dims(y, axis=0) >>> y.shape (1, 1, 4)