2017-03-27 113 views
1

有沒有辦法在自定義Keras丟失函數中重新定形TF張量?我正在爲卷積神經網絡定義這種自定義損失函數?在Keras損失函數裏面重塑TensorFlow張量?

def custom_loss(x, x_hat): 
    """ 
    Custom loss function for training background extraction networks (autoencoders) 
    """ 

    #flatten x, x_hat before computing mean, median 
    shape = x_hat.get_shape().as_list() 
    batch_size = shape[0] 
    image_size = np.prod(shape[1:]) 

    x = tf.reshape(x, [batch_size, image_size]) 
    x_hat = tf.reshape(x_hat, [batch_size, image_size]) 

    B0 = reduce_median(tf.transpose(x_hat)) 
    # I divide by sigma in the next step. So I add a small float32 to F0 
    # so as to prevent sigma from becoming 0 or Nan. 

    F0 = tf.abs(x_hat - B0) + 1e-10 

    sigma = tf.reduce_mean(tf.sqrt(F0/0.5), axis=0) 

    background_term = tf.reduce_mean(F0/sigma, axis=-1) 

    bce = binary_crossentropy(x, x_hat) 

    loss = bce + background_term 

    return loss 

除了計算標準binary_crossentropy額外background_term加入到損失。這個術語激勵網絡預測圖像接近批次的中位數。由於CNN的輸出是2D,reduce_median在1D陣列中效果更好,我不得不將圖像重塑爲1D陣列。當我嘗試訓練這個網絡我得到錯誤

Traceback (most recent call last): 
    File "stackoverflow.py", line 162, in <module> 
    autoencoder = build_conv_autoencoder(lambda_W, input_shape, num_filters, optimizer, custom_loss) 
    File "stackoverflow.py", line 136, in build_conv_autoencoder 
    autoencoder.compile(optimizer, loss, metrics=[mean_squared_error]) 
    File "/usr/local/lib/python3.5/dist-packages/keras/models.py", line 594, in compile 
    **kwargs) 
    File "/usr/local/lib/python3.5/dist-packages/keras/engine/training.py", line 667, in compile 
    sample_weight, mask) 
    File "/usr/local/lib/python3.5/dist-packages/keras/engine/training.py", line 318, in weighted 
    score_array = fn(y_true, y_pred) 
    File "stackoverflow.py", line 26, in custom_loss 
    x = tf.reshape(x, [batch_size, image_size]) 
    File "/usr/local/lib/python3.5/dist-packages/tensorflow/python/ops/gen_array_ops.py", line 2448, in reshape 
    name=name) 
    File "/usr/local/lib/python3.5/dist-packages/tensorflow/python/framework/op_def_library.py", line 494, in apply_op 
    raise err 
    File "/usr/local/lib/python3.5/dist-packages/tensorflow/python/framework/op_def_library.py", line 491, in apply_op 
    preferred_dtype=default_dtype) 
    File "/usr/local/lib/python3.5/dist-packages/tensorflow/python/framework/ops.py", line 710, in internal_convert_to_tensor 
    ret = conversion_func(value, dtype=dtype, name=name, as_ref=as_ref) 
    File "/usr/local/lib/python3.5/dist-packages/tensorflow/python/framework/constant_op.py", line 176, in _constant_tensor_conversion_function 
    return constant(v, dtype=dtype, name=name) 
    File "/usr/local/lib/python3.5/dist-packages/tensorflow/python/framework/constant_op.py", line 165, in constant 
    tensor_util.make_tensor_proto(value, dtype=dtype, shape=shape, verify_shape=verify_shape)) 
    File "/usr/local/lib/python3.5/dist-packages/tensorflow/python/framework/tensor_util.py", line 441, in make_tensor_proto 
    tensor_proto.string_val.extend([compat.as_bytes(x) for x in proto_values]) 
    File "/usr/local/lib/python3.5/dist-packages/tensorflow/python/framework/tensor_util.py", line 441, in <listcomp> 
    tensor_proto.string_val.extend([compat.as_bytes(x) for x in proto_values]) 
    File "/usr/local/lib/python3.5/dist-packages/tensorflow/python/util/compat.py", line 65, in as_bytes 
    (bytes_or_text,)) 
TypeError: Expected binary or unicode string, got None 

好像Keras呼籲custom_loss的TensorFlow圖進行實例化之前。這使得batch_size沒有而是實際值。有沒有適當的方法來重塑張力損失函數內的這個錯誤是可以避免的?您可以查看完整代碼here

+0

您是否嘗試過在任第一層或'Input'層定義了'batch_input_shape',而不是'input_shape'? –

+0

您可以使用'get_shape()。as_list()'後檢查'shape'的值嗎?我想'x'和'x_hat'是正確的張量,但如果你能檢查它們是正確的將極大地幫助解決問題 – DarkCygnus

回答

0

是否有重塑張量有道......

如果您正在使用Keras你應該使用K.reshape(x,shape)方法,這是tf.reshape(x,shape)的包裝,我們可以在docs看到。

我也注意到你正在使用get_shape()獲得您的張量形狀,在Keras時,你可以做到這一點與K.int_shape(x)作爲docs也提到了,像這樣:

shape = K.int_shape(x_hat) 

除此之外還有其他幾個操作您直接調用您的Tensorflow導入,而不是Keras後端(如tf.abs(),tf.reduce_mean(),tf.transpose()等)。您應該考慮在keras後端使用其相應的包裝器以統一表示法並保證更規則的行爲。另外,通過使用Keras後端,您可以使程序兼容Theano和Tensorflow,因此它是您應該考慮的一大優勢。

此外,在處理具有未定義尺寸的張量時,可能會出現一些TypeError。請看看this question,他們在這裏解釋了用未定義尺寸重塑張量的方法。另外,對於Keras中的等價物,請檢查this other問題,在答案中,我將解釋如何使用Keras和Tensorflow作爲後端。

...現在關於你的代碼。基本上,由於您有一些未定義的維度,因此您可以傳遞值-1來推斷形狀,而不管它可能的大小(在第一個鏈接問題中進行了解釋,但也可以在docs中看到)。喜歡的東西:

x = tf.reshape(x, [-1, image_size]) 

或者使用Keras後端:

x = K.reshape(x, [-1, image_size])