1

我正在玩一个天真的 U-net,我将其作为玩具数据集部署在 MNIST 上。我在from_logits论证的工作方式中看到了一种奇怪的行为tf.keras.losses.BinaryCrossentropy

据我了解,如果在任何神经网络的最后一层activation='sigmoid'使用,那么tf.keras.losses.BinaryCrossentropy你必须使用from_logits=False. 如果相反activation=None,您需要from_logits=True. 它们中的任何一个都应该在实践中工作,尽管from_logits=True看起来更稳定(例如,为什么 Keras/tensorflow 的 sigmoid 和交叉熵精度低?)。在以下示例中不是这种情况

所以,我unet的做法如下(完整代码在这篇文章的末尾):

def unet(input,init_depth,activation):
    # do stuff that defines layers
    # last layer is a 1x1 convolution
    output = tf.keras.layers.Conv2D(1,(1,1), activation=activation)(previous_layer) # shape = (28x28x1)
    return tf.keras.Model(input,output)

现在我定义了两个模型,一个在最后一层激活:

input = Layers.Input((28,28,1))
model_withProbs = unet(input,4,activation='sigmoid')
model_withProbs.compile(loss=tf.keras.losses.BinaryCrossentropy(from_logits=False),
    optimizer=tf.keras.optimizers.Adam()) #from_logits=False since the sigmoid is already present

一个没有

model_withLogits = unet(input,4,activation=None)
model_withLogits.compile(loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
    optimizer=tf.keras.optimizers.Adam()) #from_logits=True since there is no activation

如果我是对的,他们应该有完全相同的行为。

相反,预测的model_withLogits像素值高达 2500 左右(这是错误的),而model_withProbs我得到的值介于 0 和 1 之间(这是正确的)。你可以看看我在这里得到的数字

我考虑过稳定性问题(from_logits=True更稳定),但这个问题甚至在训练之前就出现了(见这里)。此外,问题正是当我通过from_logits=True(即 for model_withLogits)时,所以我认为稳定性无关紧要。

有人知道为什么会这样吗?我在这里缺少任何基本的东西吗?

后脚本:代码

重新利用 MNIST 进行分割。

我加载 MNIST:

(x_train, labels_train), (x_test, labels_test) = tf.keras.datasets.mnist.load_data()

我通过将所有非零值设置为一个来将 MNIST 重新用于分割任务x_train

x_train = x_train/255 #normalisation 
x_test = x_test/255 
Y_train = np.zeros(x_train.shape)  #create segmentation map
Y_train[x_train>0] = 1   #Y_train is zero everywhere but where the digit is drawn

unet

def unet(input, init_depth,activation):

  conv1 = Layers.Conv2D(init_depth,(2,2),activation='relu', padding='same')(input)
  pool1 = Layers.MaxPool2D((2,2))(conv1)
  drop1 = Layers.Dropout(0.2)(pool1)

  conv2 = Layers.Conv2D(init_depth*2,(2,2),activation='relu',padding='same')(drop1)
  pool2 = Layers.MaxPool2D((2,2))(conv2)
  drop2 = Layers.Dropout(0.2)(pool2)

  conv3 = Layers.Conv2D(init_depth*4, (2,2), activation='relu',padding='same')(drop2)
  #pool3 = Layers.MaxPool2D((2,2))(conv3)
  #drop3 = Layers.Dropout(0.2)(conv3)

  #upsampling
  up1 = Layers.Conv2DTranspose(init_depth*2, (2,2), strides=(2,2))(conv3)
  up1 = Layers.concatenate([conv2,up1])
  conv4 = Layers.Conv2D(init_depth*2, (2,2), padding='same')(up1)

  up2 = Layers.Conv2DTranspose(init_depth,(2,2), strides=(2,2), padding='same')(conv4)
  up2 = Layers.concatenate([conv1,up2])
  conv5 = Layers.Conv2D(init_depth, (2,2), padding='same' )(up2)

  last = Layers.Conv2D(1,(1,1), activation=activation)(conv5)


  return tf.keras.Model(inputs=input,outputs=last)
4

0 回答 0