webdevqa.jp.net

各要素を計量するためのKerasのカスタム加重損失関数

単純な加重損失関数を作成しようとしています。

たとえば、入力次元が100 * 5で、出力次元も100 * 5です。同じ次元のウェイトマトリックスもあります。

次のようなもの:

import numpy as np
train_X = np.random.randn(100, 5)
train_Y = np.random.randn(100, 5)*0.01 + train_X

weights = np.random.randn(*train_X.shape)

カスタム損失関数の定義

def custom_loss_1(y_true, y_pred):
    return K.mean(K.abs(y_true-y_pred)*weights)

モデルの定義

from keras.layers import Dense, Input
from keras import Model
import keras.backend as K

input_layer = Input(shape=(5,))
out = Dense(5)(input_layer)
model = Model(input_layer, out)

既存のメトリックを使用したテストは正常に機能します

model.compile('adam','mean_absolute_error')
model.fit(train_X, train_Y, epochs=1)

カスタム損失関数を使用したテストが機能しない

model.compile('adam',custom_loss_1)
model.fit(train_X, train_Y, epochs=10)

次のスタックトレースを提供します。

InvalidArgumentError (see above for traceback): Incompatible shapes: [32,5] vs. [100,5]
 [[Node: loss_9/dense_8_loss/mul = Mul[T=DT_FLOAT, _device="/job:localhost/replica:0/task:0/device:CPU:0"](loss_9/dense_8_loss/Abs, loss_9/dense_8_loss/mul/y)]]

番号32はどこから来たのですか?

Kerasテンソルとして重みを使用した損失関数のテスト

def custom_loss_2(y_true, y_pred):
    return K.mean(K.abs(y_true-y_pred)*K.ones_like(y_true))

この機能が仕事をしているようです。したがって、おそらく、重み行列としてKerasテンソルが機能することを示唆しています。そこで、損失関数の別のバージョンを作成しました。

損失関数の試行3

from functools import partial

def custom_loss_3(y_true, y_pred, weights):
    return K.mean(K.abs(y_true-y_pred)*K.variable(weights, dtype=y_true.dtype))

cl3 = partial(custom_loss_3, weights=weights)  

Cl3を使用してデータを近似すると、上記と同じエラーが発生します。

InvalidArgumentError (see above for traceback): Incompatible shapes: [32,5] vs. [100,5]
     [[Node: loss_11/dense_8_loss/mul = Mul[T=DT_FLOAT, _device="/job:localhost/replica:0/task:0/device:CPU:0"](loss_11/dense_8_loss/Abs, loss_11/dense_8_loss/Variable/read)]]

私は何が欠けているのだろうか! Kerasでsample_weightの概念を使用できました。しかし、その後、入力を3Dベクトルに再形成する必要があります。

このカスタム損失関数は本当に些細なものであるはずだと思いました。

12
Nipun Batra

_model.fit_では、デフォルトでバッチサイズは32であり、これがこの数の元です。ここで何が起こっているのですか:

  • _custom_loss_1_では、テンソルK.abs(y_true-y_pred)の形状は_(batch_size=32, 5)_で、numpy配列weightsの形状は_(100, 5)_です。次元が一致せず、ブロードキャストを適用できないため、これは無効な乗算です。

  • _custom_loss_2_では、同じ形状の_(batch_size=32, 5)_の2つのテンソルを乗算しているため、この問題は存在しません。

  • _custom_loss_3_では、weightsをKeras変数に変換しても形が変わらないため、問題は_custom_loss_1_と同じです。


PDATE:各トレーニングサンプルの各要素に異なる重みを与えたいようです。したがって、weights配列の形状は_(100, 5)_でなければなりません。この場合、重みの配列をモデルに入力し、損失関数内でこのテンソルを使用します。

_import numpy as np
from keras.layers import Dense, Input
from keras import Model
import keras.backend as K
from functools import partial


def custom_loss_4(y_true, y_pred, weights):
    return K.mean(K.abs(y_true - y_pred) * weights)


train_X = np.random.randn(100, 5)
train_Y = np.random.randn(100, 5) * 0.01 + train_X
weights = np.random.randn(*train_X.shape)

input_layer = Input(shape=(5,))
weights_tensor = Input(shape=(5,))
out = Dense(5)(input_layer)
cl4 = partial(custom_loss_4, weights=weights_tensor)
model = Model([input_layer, weights_tensor], out)
model.compile('adam', cl4)
model.fit(x=[train_X, weights], y=train_Y, epochs=10)
_
12
rvinas