leooon
@leooon (玲央 石崎)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

関数の引数で受け取った値を、one hotへ変換したい。

解決したいこと

one hotに変換したい。
「該当するコード」に記載している関数の引数である、'y_hat'をone_hotに変換したいです。
解決策を教えていただきたいです。

発生している問題

「該当するコード」の関数内で、y_hatをone hotへ変換しているつもりですが、うまくできません。
ちなみに、yはone_hotへ変換することができています。

該当するソースコード

オリジナルの損失関数を作成しています。
config.N_CLASSESは、予測するクラス数を表していて、15587です。

def scce_with_ls(y, y_hat):
  y = tf.one_hot(tf.cast(y, tf.int32), config.N_CLASSES)
  pred = tf.math.argmax(y_hat, axis=1)
  y_hat = tf.one_hot(tf.cast(pred, tf.int32), config.N_CLASSES)
  return categorical_crossentropy(y, y_hat, label_smoothing=0.1)

入力値:y, y_hatのshapeとtype

yは、正解ラベルです。
y_hatは,各クラス(15587種)の予測確率です。

y-> shaep: (None, 1),
    type: <class 'tensorflow.python.framework.ops.Tensor'>,  

y_hat-> shape: (None, 15587)
        type: <class 'tensorflow.python.framework.ops.Tensor'>

y, y_hatへ期待する出力

y-> shape(None, 1, 15587)
y_hat-> shape(None, 1, 15587)

y, y_hatの実際の出力

y_hatがone hotへ変換されておらず、yとy_hatのshapeが合ないため、下記に記載している、エラーが発生します。

y-> shape(None, 1, 15587)
y_hat-> shape(None, 15587)

発生しているエラー分

ValueError: in user code:

    File "/usr/local/lib/python3.7/dist-packages/keras/engine/training.py", line 1021, in train_function  *
        return step_function(self, iterator)
    File "<ipython-input-395-2b3ee9814ca9>", line 16, in scce_with_ls  *
        return categorical_crossentropy(y, y_hat, label_smoothing=0.1)
    File "/usr/local/lib/python3.7/dist-packages/keras/losses.py", line 1790, in categorical_crossentropy
        y_true, y_pred, from_logits=from_logits, axis=axis)
    File "/usr/local/lib/python3.7/dist-packages/keras/backend.py", line 5083, in categorical_crossentropy
        target.shape.assert_is_compatible_with(output.shape)

    ValueError: Shapes (None, 1, 15587) and (None, 15587) are incompatible
0

3Answer

yおよびy_hatのサンプル数(shapeの None)= 3, config.N_CLASSES = 4 として実験してみました。

y_hatについて、argmaxを取ったときにshapeが "潰れて" しまいますね。すなわち、@leooon さんは(None, 15587) -> (None, 1) になることを期待しているのだと思いますが、実際は (None) になってしまっています。

Python 3.9.10 (main, Feb  4 2022, 11:07:01)
[Clang 13.0.0 (clang-1300.0.29.30)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import tensorflow as tf
>>> tf.__version__
'2.8.0'
>>> n_classes = 4
>>> y_hat = tf.constant([[0, 2, 3, 1], [4, 7, 6, 5], [11, 8, 9, 10]])
>>> y_hat.shape
TensorShape([3, 4])
>>> tf.math.argmax(y_hat, axis=1).shape
TensorShape([3])
>>> tf.one_hot(tf.math.argmax(y_hat, axis=1), n_classes).shape
TensorShape([3, 4])

yの方は想定通りですね。

>>> y = tf.constant([[3], [0], [1]])
>>> y.shape
TensorShape([3, 1])
>>> tf.one_hot(y, n_classes).shape
TensorShape([3, 1, 4])

解決策として例えば、潰れてしまったaxisを増やしてやることが考えられます。

>>> pred = tf.math.argmax(y_hat, axis=1)
>>> pred.shape
TensorShape([3])
>>> pred = tf.expand_dims(pred, axis=-1)
>>> pred.shape
TensorShape([3, 1])
>>> tf.one_hot(pred, n_classes).shape
TensorShape([3, 1, 4])

numpyだとkeepdimsというオプション引数があり、出力にてaxisが潰れないようにできるのですが、tf.math.argmaxには同様のオプションがなさそうでした。

逆に、yのaxis=1を潰してしまうのもいいですね。

>>> y.shape
TensorShape([3, 1])
>>> y = tf.squeeze(y, axis=1)
>>> y.shape
TensorShape([3])
>>> tf.one_hot(y, n_classes).shape
TensorShape([3, 4])
2Like

Comments

  1. @leooon

    Questioner

    @mamo3gr 様

    ご丁寧に回答していただき、ありがとうございます。
    解決方法をいくつも用意してくれて、助かりました。

    ありがとうございます。

うまくできません。

とは、具体的に、どんな入力に対してどんな結果を期待していて、実際はどんな結果になってしまうのでしょうか?

ちなみに、tf.math.argmaxのキーワード引数 aixs がタイポのように見えますが…。

1Like

Comments

  1. @leooon

    Questioner

    @mamo3gr 様
    迅速な返答ありがとうございます。

    ご指摘に沿って、質問内容を編集させてもらいました。
    もう一度お目を通してもらえますか。

    よろしくお願いします。
    ps. axisはタイプミスでした。

試していないので正しくないかもしれませんが,y_trueもargmaxをとらなければならないのではないでしょうか.具体的には

def scce_with_ls(y_true, y_pred):
  y_true = tf.math.argmax(y_true, axis=1)
  y_true = tf.one_hot(tf.cast(y_true, tf.int32), config.N_CLASSES)
  y_pred = tf.math.argmax(y_pred, axis=1)
  y_pred = tf.one_hot(tf.cast(y_pred, tf.int32), config.N_CLASSES)
  return categorical_crossentropy(y_true, y_pred, label_smoothing=0.1)

ではないでしょうか.オリジナルの損失関数とおっしゃっていますが具体的に損失関数の数式を示されていないので正しいかどうかはわかりません.が,整合性を考えて上のようにするのが正しいのかと思いました.

1Like

Comments

  1. @leooon

    Questioner

    @PondVillege 様

    迅速な返答ありがとうございます。

    教えていただいたプログラムで試させてもらったのですが、エラーが表示されうまく行きませんでした。
    表示されたエラー文です。
    ```
    ValueError: in user code:
    ```
    エラー文はこの後に何千行にも及んだので、掲載はできません。

    ただ、関数のreutrnの直前に、y_true, y_predのshapeをprintで表示しました。(最下部に示します。)
    これを見ると、one hotに変換できていないように感じます。
    変換できていれば、y_true, y_pred共にshapeが '(None, 1, 15587)'になると個人的には思っていますが、どうでしょうか。

    y_trueのshape -> (None, 15587)
    y_predのshape -> (None, 15587)

Your answer might help someone💌