Неожиданное поведение from_logits в BinaryCrossentropy?

Я играю с наивной U-net, которую я развертываю на MNIST в качестве игрушечного набора данных. Я наблюдаю странное поведение в том, как from_logits аргумент работает в.

Насколько я понимаю, если в последнем слое какой-нибудь нейросети activation='sigmoid' используется, то в tf.keras.losses.BinaryCrossentropy вы должны использовать from_logits=False. Если вместо этого activation=None, тебе нужно . Любой из них должен работать на практике, хотя кажется более стабильным (например, почему сигмоидная и кроссентропия Keras / tensorflow имеет низкую точность?). В следующем примере это не так .

Итак, я поступаю следующим образом (полный код в конце этого поста):

      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

Если я прав, они должны вести себя точно так же.

Вместо этого прогноз для имеет значения пикселей до 2500 или около того (что неверно), а для model_withProbsЯ получаю значения от 0 до 1 (что верно). Вы можете проверить цифры, которые я получаю здесь

Я думал о стабильности (стабильнее), но эта проблема возникает еще до тренировки ( см. Здесь). Причем проблема именно в том, когда я прохожу from_logits=True (то есть для 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)

0 ответов

Другие вопросы по тегам