2017-10-27 18 views
4

は私のKerasカスタム損失関数を見よ:Keras/Tensorflowでのスライスベースの割り当て?

def custom_loss(y_true, y_pred): 
    sqerr = (y_true - y_pred)**2 
    sqerr[:,4:-1:7] = sqerr[:,4:-1:7] * ((y_true[:,2:-1:7]-y_true[:,3:-1:7])/y_true[:,2:-1:7])**2 
    return sqerr.mean() 

しかし、「sqerr」のエラー

TypeError: 'Tensor' object does not support item assignment

でこのコードの結果は、だから私はjdehesa's answerとを含むポスト"How to do slice assignment in Tensorflow"を、読んでてnumpyの配列ではありませんGitHub page on this discussion。それで、ここで...私は今持っているもの

def custom_loss(y_true, y_pred): 
    sqerr = K.square(y_true-y_pred) 

    sqerr = tf.Variable( sqerr , validate_shape=False) 
    with tf.control_dependencies([sqerr[:,4:-1:7].assign(sqerr[:,4:-1:7] * ((y_true[:,2:-1:7]-y_true[:,3:-1:7])/y_true[:,2:-1:7])**2)]): 
     sqerr = tf.identity(sqerr) 

    return K.mean(sqerr) 

だ...しかし、それは実際にそれを使用する時間が来るとき明らかに私はそれをbotchingよ:

Traceback (most recent call last): File "my_awesome_nn.py", line 119, in setup_model

model.compile(loss=custom_loss, optimizer=opt) 

File "/opt/anaconda/envs/py35/lib/python3.5/site-packages/keras/engine/training.py", line 850, in compile

sample_weight, mask) 

File "/opt/anaconda/envs/py35/lib/python3.5/site-packages/keras/engine/training.py", line 465, in weighted

score_array = K.mean(score_array, axis=list(range(weight_ndim, ndim))) 

TypeError: 'NoneType' object cannot be interpreted as an integer

何が起こっているされ、 TFスライシングは、一般的なテンソルではなく、変数にのみ適用することが許可されているので、私は変数にキャストしています。しかし、変数にキャストすると、形状を知りたいが、その点で形状が「動的に定義されている」(つまり、最初の要素は「?」)。したがって、validate_shape = Falseを設定すると実際に変数を定義できますが、Kerasが後で必要とするディメンション情報が破棄されます。観察:

def custom_loss(y_true, y_pred): 
     sqerr = K.square(y_true-y_pred) 
     print("K.ndim(sqerr) #1 = ",K.ndim(sqerr)) 
     sqerr = tf.Variable( sqerr , validate_shape=False) 
     print("K.ndim(sqerr) #2 = ",K.ndim(sqerr)) 
     with tf.control_dependencies([sqerr[:,4:-1:7].assign(sqerr[:,4:-1:7] * ((y_true[:,2:-1:7]-y_true[:,3:-1:7])/y_true[:,2:-1:7])**2)]): 
      sqerr = tf.identity(sqerr) 

     return K.mean(sqerr) 

...出力における結果

K.ndim(sqerr)#1 = 2

K.ndim(sqerr)#2 =なし

従って後でKerasのtraining.pyコードで 'ndim = K.ndim(score_array)'と表示されている場合、Noneとなり、NoneTypeエラーになります。

誰かが必要とすることをどのように行うかについて光を当てることはできますか?私は変数に変換せずにスライスすることはできないようだが、動的形状を保持する動的形状テンソルの変数を定義することはできない。

(これは私がちょうど「真ん中の3行」上記を省略して、私のカスタムの損失は、通常のMSEことがあれば、完全に動作するコードです)

+1

あなたはより多くの関連するコードが含まれてみてくださいことはできますか?どこで 'score_array'を計算しますか?モデルの宣言とコンパイルに関するコードをもっと表示できますか? – DarkCygnus

+0

score_arrayはKerasディストリビューション内で評価されているように表示されているので、私はそれを含めることができますが、私のコードではありません。 https://github.com/fchollet/keras/blob/master/keras/engine/training.pyそしてそのモデルは、損失が組み立てられた時点ではまだ構築されていません。現在のところ、問題はスライスに必要な変数としてのキャスト、validate_shape = Falseの必要性です。テンソルの形状はその時点で「ゆるやかに定義されている」ためです。しかし、これはK.dim(sqerr)= Noneになります。私はこれを反映するために投稿を編集します... – sh37211

答えて

2

私は、スライス割り当てがこのカスタム損失を回避することができると思います。損失額をsqerr[:, 4:-1:7]に調整する場合は、損失総額から元の値を差し引き、調整後の損失額を戻すことができます。

def custom_loss_keras(y_true, y_pred): 
    # first sum up the squared error column-wise 
    sqerr = K.square(y_true - y_pred) 
    loss = K.sum(sqerr, axis=-1) 

    # subtract the loss for the sliced part 
    loss -= K.sum(sqerr[:, 4:-1:7], axis=-1) 

    # add back the adjusted loss for the sliced part 
    denominator = K.maximum(y_true[:, 2:-1:7], K.epsilon()) # handle zero-division 
    numerator = y_true[:, 2:-1:7] - y_true[:, 3:-1:7] 
    loss += K.sum(sqerr[:, 4:-1:7] * K.square(numerator/denominator), axis=-1) 

    # take average 
    ncols = K.int_shape(y_pred)[-1] 
    loss /= ncols 
    return K.mean(loss) 

あなたは、元のnumpyのバージョンと比較することによって、この機能を確認することができます。

def custom_loss_numpy(y_true, y_pred): 
    sqerr = (y_true - y_pred)**2 
    sqerr[:,4:-1:7] = sqerr[:,4:-1:7] * ((y_true[:,2:-1:7]-y_true[:,3:-1:7])/y_true[:,2:-1:7])**2 
    return sqerr.mean() 

y_true = np.random.rand(50, 1000) 
y_pred = np.random.rand(50, 1000) 

print(custom_loss_numpy(y_true, y_pred)) 
889.992075384 

print(K.eval(custom_loss_keras(K.variable(y_true), K.variable(y_pred)))) 
889.992 
+0

優れた、模範的な答え!ありがとうございました! – sh37211

関連する問題