2017-11-17 13 views
1

저는 DL과 Keras를 처음 사용하며 현재 Keras에서 sobel 필터 기반 사용자 지정 손실 함수를 구현하려고합니다.Keras를 사용하여 사용자 정의 sobel 필터 기반 손실 함수를 구현하는 방법

아이디어는 sobel 필터링 된 예측과 sobel 필터링 된 지상 진실 이미지의 평균 제곱 손실을 계산하는 것입니다.

지금까지, 내 ​​사용자 정의 손실 함수는 다음과 같습니다 y_true.shapeNone를 반환, 내가 발견 디버거를 사용

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

이 손실 함수를 사용하여

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)) 

이 오류로 연결 - 좋아. 나는이 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

keras 백엔드 또는 tensorflow/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 채널 이상.

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 

을 그리고 이것은 손실 함수입니다 : (3,3,inputChannels, 2) :이은 각 입력 채널에 대한 소벨 필터를 복제합니다

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 = ....) 

내 경험에 따르면 통합 된 sobel 필터를 계산하면 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

와우, 어떤 완벽한 답/해결책. 도와 주셔서 대단히 감사합니다. –