2017-11-17 19 views
1

私はDLとKerasを初めて使用しており、現在Kerasでソベルフィルタベースのカスタム損失関数を実装しようとしています。Kerasを使用してカスタムソベルフィルタベースの損失関数を実装する方法

考え方は、ソーベルフィルタリングされた予測とソーベルフィルタリングされたグランドトゥルース画像の平均二乗損失を計算することです。

これまでのところ、私のカスタム損失関数は次のようになります。この損失関数を使用して

from scipy import ndimage 

def mse_sobel(y_true, y_pred): 

    for i in range (0, y_true.shape[0]): 
     dx_true = ndimage.sobel(y_true[i,:,:,:], 1) 
     dy_true = ndimage.sobel(y_true[i,:,:,:], 2) 
     mag_true[i,:,:,:] = np.hypot(dx_true, dy_true) 
     mag_true[i,:,:,:] *= 1.0/np.max(mag_true[i,:,:,:]) 

     dx_pred = ndimage.sobel(y_pred[i,:,:,:], 1) 
     dy_pred = ndimage.sobel(y_pred[i,:,:,:], 2) 
     mag_pred[i,:,:,:] = np.hypot(dx_pred, dy_pred) 
     mag_pred[i,:,:,:] *= 1.0/np.max(mag_pred[i,:,:,:]) 

    return(K.mean(K.square(mag_pred - mag_true), axis=-1)) 

は、このエラーにつながる:私はy_true.shapeだけNoneを返すこと、が分かったデバッガを使用して

in mse_sobel 
for i in range (0, y_true.shape[0]): 
TypeError: __index__ returned non-int (type NoneType) 

- 大丈夫。私はこのfor i in range (0,1):のように見えるようにした例1ためにy_true.shapeを交換する場合でも、別のエラーが発生します。

in sobel 
axis = _ni_support._check_axis(axis, input.ndim) 

in _check_axis 
raise ValueError('invalid axis') 
ValueError: invalid axis 

をここで、私は軸が無効であると思われる理由がわからないのですか?

誰も私がその損失機能を実装する方法を理解するのに役立つことができますか? ありがとうございました!

答えて

2

ケラスバックエンドまたはテンソルフロー/ theano/cntk関数を使用して、テンソル演算で損失を作成する必要があります。これがバックプロパゲーションを維持する唯一の方法です。 numpy、scipyなどを使用すると、グラフが破損します。ここで

#this contains both X and Y sobel filters in the format (3,3,1,2) 
#size is 3 x 3, it considers 1 input channel and has two output channels: X and Y 
sobelFilter = K.variable([[[[1., 1.]], [[0., 2.]],[[-1., 1.]]], 
         [[[2., 0.]], [[0., 0.]],[[-2., 0.]]], 
         [[[1., -1.]], [[0., -2.]],[[-1., -1.]]]]) 
、場合には、各入力チャンネル用のフィルタを繰り返し機能あなたのイメージはRGBです以上を有する:フィルタの定義

import keras.backend as K 

のはkerasバックエンドをインポートしてみましょう1チャンネル以上。 (3,3,inputChannels, 2):これはちょうど、各入力チャンネルのためのソーベルフィルタを複製します

def expandedSobel(inputTensor): 

    #this considers data_format = 'channels_last' 
    inputChannels = K.reshape(K.ones_like(inputTensor[0,0,0,:]),(1,1,-1,1)) 
    #if you're using 'channels_first', use inputTensor[0,:,0,0] above 

    return sobelFilter * inputChannels 

をそして、これは損失関数である:

def sobelLoss(yTrue,yPred): 

    #get the sobel filter repeated for each input channel 
    filt = expandedSobel(yTrue) 

    #calculate the sobel filters for yTrue and yPred 
    #this generates twice the number of input channels 
    #a X and Y channel for each input channel 
    sobelTrue = K.depthwise_conv2d(yTrue,filt) 
    sobelPred = K.depthwise_conv2d(yPred,filt) 

    #now you just apply the mse: 
    return K.mean(K.square(sobelTrue - sobelPred)) 

は、モデルでこの損失を適用します。

model.compile(loss=sobelLoss, optimizer = ....) 

私の経験では、統合されたソベルフィルタsqrt(X² + Y²)を計算すると、恐ろしい結果と結果の画像はチェスボードのように聞こえる。しかし、あなたがしたい場合:

def squareSobelLoss(yTrue,yPred): 

    #same beginning as the other loss 
    filt = expandedSobel(yTrue) 
    squareSobelTrue = K.square(K.depthwise_conv2d(yTrue,filt)) 
    squareSobelPred = K.square(K.depthwise_conv2d(yPred,filt)) 

    #here, since we've got 6 output channels (for an RGB image) 
    #let's reorganize in order to easily sum X² and Y²: change (h,w,6) to (h,w,3,2) 
    #caution: this method of reshaping only works in tensorflow 
    #if you do need this in other backends, let me know 
    newShape = K.shape(squareSobelTrue) 
    newShape = K.concatenate([newShape[:-1], 
           newShape[-1:]//2, 
           K.variable([2],dtype='int32')]) 

    #sum the last axis (the one that is 2 above, representing X² and Y²)      
    squareSobelTrue = K.sum(K.reshape(squareSobelTrue,newShape),axis=-1) 
    squareSobelPred = K.sum(K.reshape(squareSobelPred,newShape),axis=-1) 

    #since both previous values are already squared, maybe we shouldn't square them again? 
    #but you can apply the K.sqrt() in both, and then make the difference, 
    #and then another square, it's up to you...  
    return K.mean(K.abs(squareSobelTrue - squareSobelPred)) 
+0

うわー、どのような完璧な答え/解決策。ご協力いただきありがとうございます。 –

関連する問題