Неожиданное поведение 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)