#python #tensorflow #keras #tf.keras
Вопрос:
В моей модели у меня есть 2 функции потерь — Перекрестная энтропия и Среднее квадратическое значение. Я хочу, чтобы моя модель минимизировала обе потери, но модель минимизирует только среднеквадратичную ошибку во время обучения.
def buildGenerator(dmodel, batch=100):
inputs = Input(shape=(256,256,1))
x = Conv2D(
filters = 32,
kernel_size = 3,
padding = 'same',
strides = 1
)(inputs)
x = BatchNormalization(momentum = 0.9)(x)
x = LeakyReLU(alpha=0.2)(x)
.........................
...........................
outputs1 = Conv2D(
filters = 2,
kernel_size = 3,
padding = 'same',
strides = 1
)(x)
outputs2 = dmodel(outputs1)
model = Model(inputs = inputs, outputs = [ outputs2, outputs1], name = 'functional_model')
model.compile(
loss = ['binary_crossentropy','mse' ],
optimizer = 'Adam',
loss_weights = [1.0, 0.6],
metrics=['accuracy', 'mse']
)
return model
В этом коде dmodel-это еще одна модель. Я использую dmodel для классификации выходных данных 1, генерируемых моделью, а затем нахожу перекрестную энтропию между входными метками и выходными метками.
Вот как я тренируюсь
dmodel = buildDiscriminator()
dmodel.load_weights('./GAN/discriminator')
dmodel.trainable = False
x, y1 = getGeneratorData()
y2 = np.ones((batch, 1))
model = buildGenerator(dmodel)
model.fit(x,[y2, y1],epochs=1)
Я пробовал много вещей, таких как изменение веса потерь, изменение функций потерь, но ничего не работает. Моя модель сводит к минимуму только функцию MSE.
Я не понимаю, что я делаю не так.
Я думаю, что использование модели дискриминатора внутри генератора является проблемой, но я не уверен.
Комментарии:
1. Откуда вы знаете, что модель сводит к минимуму только MSE?
2. Я тренировал свою модель в течение нескольких часов, и точность двоичной перекрестной энтропии совершенно не менялась. Только MSE уменьшался. Я распечатал график для точности и mse. Точность была постоянной все время.
3. Это не свидетельствует о том, что модель обучается только на MSE, есть много других причин, по которым потеря может быть постоянной. Знаете ли вы, что модель на самом деле обучается потерям: 1.0 * CE 0.6 * MSE?
Ответ №1:
Я не знаю, существует ли простой синтаксис для объединения различных функций потерь, но вы можете попытаться определить собственный класс потерь. В другом потоке я нашел этот фрагмент кода, который определяет собственный класс потерь, объединяющий две другие функции потерь:
rho = 0.05
class loss_with_KLD(losses.Loss):
def __init__(self, rho):
super(loss_with_KLD, self).__init__()
self.rho = rho
self.kl = losses.KLDivergence()
self.mse = losses.MeanSquaredError(reduction=tf.keras.losses.Reduction.SUM)
def call(self, y_true, y_pred):
mse = self.mse(y_true, y_pred)
kl = self.kl(self.rho, y_pred)
return mse kl
Если вы просто замените KLDivergence на двоичную перекрестную энтропию, то это должно сработать. Кроме того, вам потребуется изменить функцию call (), поскольку эта реализация применяет две функции потерь к одному и тому же предсказанному значению y, но на самом деле вы предсказываете два разных значения y. В этом случае ваши y_true и y_pred будут содержать два значения, и вам нужно будет применить каждую функцию потерь только к одному из них. Я не знаю, легко ли можно взять один элемент из вектора (в стиле y_true[0]), но если это не так, вы можете обойти это, применив «маску» к вашим векторам, умножив их на [0, 1] или [1, 0], в зависимости от нужного вам значения. После этого вы можете использовать функцию reduce_sum (), чтобы получить одно значение и применить функцию потерь к вашим новым y_true и y_pred.
Это немного сложнее, но это должно выполнить свою работу.
Ответ №2:
Когда вы указываете 2 функции потерь, они применяются к вашим 2 различным выходам. т. Е. в вашем примере binary_crossentropy применяется к выходу 2, который имеет значение y_true всех. И является результатом необучаемой модели.
Кажется вероятным, что вы хотите вернуть одно значение из модели, так как у вас, похоже, нет меток для вывода 2. Хотя вы могли бы определить свою собственную пользовательскую функцию потерь, которая объединяет оба убытка по одному и тому же значению, я бы не советовал этого делать. Если выходное значение является предсказанием одного класса (т. Е. пиксель включен/выключен), то binary_crossentrophy имеет смысл; Если предполагается, что это дискретное значение, то mse имеет смысл.