Вопрос или проблема
Я пытаюсь воссоздать (в гораздо меньшей версии) систему AlphaGo Zero. Однако у меня возникают проблемы с моделью сети. Функция потерь, которую я должен реализовать, следующая:
$$l = (z – v)^2 – \pi^T log(p) + c ||\theta||^2$$
Где:
- $z$ — это метка (реальное значение между -1 и 1) одной из двух голов сети, а $v$ — это значение, предсказанное сетью.
- $\pi$ — это метка распределения вероятности всех действий, а $p$ — это распределение вероятности всех действий, предсказанное сетью.
- $c$ — это параметр регуляризации L2.
Я передаю сети список каналов (представляющих состояние игры) и массив (такого же размера, что и $\pi$ и $p$), представляющий, какие действия действительно являются действительными (путем установки 1
, если действительно, 0
в противном случае).
Как видно, функция потерь использует как целевые значения, так и предсказания сети для вычисления. Но после обширного поиска, при реализации своей пользовательской функции потерь, я могу передавать только параметры y_true
и y_pred
, хотя у меня есть две “y_true” и две “y_pred”. Я пытался использовать индексацию, чтобы получить эти значения, но я уверен, что это не работает.
Моделирование сети и пользовательская функция потерь находится в коде ниже:
def custom_loss(y_true, y_pred):
# Я уверен, что это не работает
output_prob_dist = y_pred[0]
output_value = y_pred[1]
label_prob_dist = y_true[0]
label_value = y_pred[1]
mse_loss = K.mean(K.square(label_value - output_value), axis=-1)
cross_entropy_loss = K.dot(K.transpose(label_prob_dist), output_prob_dist)
return mse_loss - cross_entropy_loss
def define_model():
"""Реализация модели нейронной сети с использованием Keras + Tensorflow."""
state_channels = Input(shape = (5,5,6), name="States_Channels_Input")
valid_actions_dist = Input(shape = (32,), name="Valid_Actions_Input")
conv = Conv2D(filters=10, kernel_size=2, kernel_regularizer=regularizers.l2(0.0001), activation='relu', name="Conv_Layer")(state_channels)
pool = MaxPooling2D(pool_size=(2, 2), name="Pooling_Layer")(conv)
flat = Flatten(name="Flatten_Layer")(pool)
# Объединение разровненных каналов (после пулинга) и действительного действия
# распределение. Используется только в качестве ввода в голову распределения вероятности.
merge = concatenate([flat, valid_actions_dist])
# Распределение вероятности по действиям
hidden_fc_prob_dist_1 = Dense(100, kernel_regularizer=regularizers.l2(0.0001), activation='relu', name="FC_Prob_1")(merge)
hidden_fc_prob_dist_2 = Dense(100, kernel_regularizer=regularizers.l2(0.0001), activation='relu', name="FC_Prob_2")(hidden_fc_prob_dist_1)
output_prob_dist = Dense(32, kernel_regularizer=regularizers.l2(0.0001), activation='softmax', name="Output_Dist")(hidden_fc_prob_dist_2)
# Значение состояния
hidden_fc_value_1 = Dense(100, kernel_regularizer=regularizers.l2(0.0001), activation='relu', name="FC_Value_1")(flat)
hidden_fc_value_2 = Dense(100, kernel_regularizer=regularizers.l2(0.0001), activation='relu', name="FC_Value_2")(hidden_fc_value_1)
output_value = Dense(1, kernel_regularizer=regularizers.l2(0.0001), activation='tanh', name="Output_Value")(hidden_fc_value_2)
model = Model(inputs=[state_channels, valid_actions_dist], outputs=[output_prob_dist, output_value])
model.compile(loss=custom_loss, optimizer="adam", metrics=['accuracy'])
return model
# В основном методе
model = define_model()
# ...
# Процедура MCTS для сбора данных для ввода в сеть
# ...
x_train = [channels_input, valid_actions_dist_input]
y_train = [dist_probs_label, who_won_label]
model.fit(x_train, y_train, epochs=10)
Вкратце, мой вопрос: как правильно реализовать эту пользовательскую функцию потерь, которая использует как выводы сети, так и метки значений сети?
Поскольку вы смешиваете y_true[0]
с y_pred[0]
и y_true[1]
с y_pred[1]
, вы можете рассмотреть возможность использования разных потерь для каждого из них и использования loss={'Output_Dist': custom_loss, 'Output_Value': losses.MSE}
при компиляции. Внутри он добавит результат каждого из них в финальную потерю.
def custom_loss(y_true, y_pred):
return -K.dot(K.transpose(y_true), y_pred)
Ответ или решение
Реализация пользовательской функции потерь с несколькими выходами в Keras
При разработке нейронных сетей для сложных задач, таких как система AlphaGo Zero, иногда требуется использовать кастомные функции потерь, особенно когда сеть имеет несколько выходных слоев, как в вашем случае. Ваша задача состоит в том, чтобы правильно реализовать функцию потерь на основе представленных вами обозначений.
Проблема
Ваша реализация функции потерь не работает корректно из-за неправильного индексирования и смешения истинных значений и предсказаний. Важно раздельно обрабатывать выходы модели, чтобы обеспечить правильное вычисление потерь для каждой из задач. Предлагаемое вами комбинирование выходов с использованием y_true
и y_pred
не дает ожидаемого результата, поскольку вы используете неправильные индексы.
Решение
Рекомендуется разделить расчеты потерь для каждого выходного слоя (например, для распределения вероятностей и для значения) и затем объединить их для общей функции потерь. Вы можете это сделать, передав разные функции потерь для каждого выхода в методе compile
.
Вот как можно переписать вашу функцию потерь и код для компиляции модели:
import keras.backend as K
from keras import regularizers
from keras.layers import Input, Conv2D, MaxPooling2D, Flatten, Dense, concatenate
from keras.models import Model
def custom_loss_value(y_true, y_pred):
z = y_true[1]
v = y_pred[1]
mse_loss = K.mean(K.square(z - v), axis=-1)
return mse_loss
def custom_loss_dist(y_true, y_pred):
pi = y_true[0]
p = y_pred[0]
# Применяем mask к y_true для получения действительных действий
valid_actions_mask = K.cast(K.equal(pi, 1), K.floatx()) # Маска для действительных действий
cross_entropy_loss = -K.sum(valid_actions_mask * K.log(p + K.epsilon()), axis=-1)
return cross_entropy_loss
def define_model():
state_channels = Input(shape=(5, 5, 6), name="States_Channels_Input")
valid_actions_dist = Input(shape=(32,), name="Valid_Actions_Input")
conv = Conv2D(filters=10, kernel_size=2, kernel_regularizer=regularizers.l2(0.0001), activation='relu', name="Conv_Layer")(state_channels)
pool = MaxPooling2D(pool_size=(2, 2), name="Pooling_Layer")(conv)
flat = Flatten(name="Flatten_Layer")(pool)
merge = concatenate([flat, valid_actions_dist])
# Вероятностное распределение действий
hidden_fc_prob_dist_1 = Dense(100, kernel_regularizer=regularizers.l2(0.0001), activation='relu', name="FC_Prob_1")(merge)
output_prob_dist = Dense(32, kernel_regularizer=regularizers.l2(0.0001), activation='softmax', name="Output_Dist")(hidden_fc_prob_dist_1)
# Значение состояния
hidden_fc_value_1 = Dense(100, kernel_regularizer=regularizers.l2(0.0001), activation='relu', name="FC_Value_1")(flat)
output_value = Dense(1, kernel_regularizer=regularizers.l2(0.0001), activation='tanh', name="Output_Value")(hidden_fc_value_1)
model = Model(inputs=[state_channels, valid_actions_dist], outputs=[output_prob_dist, output_value])
# Обратите внимание на разные функции потерь для каждого выхода
model.compile(optimizer='adam', loss={'Output_Dist': custom_loss_dist, 'Output_Value': custom_loss_value}, metrics=['accuracy'])
return model
# В основном методе
model = define_model()
# Предполагается, что данные для обучения формируются заранее:
# x_train = [channels_input, valid_actions_dist_input]
# y_train = [dist_probs_label, who_won_label]
model.fit(x_train, y_train, epochs=10)
Объяснение кода
-
Модульные потери: Мы определили две отдельные функции потерь:
custom_loss_value
использует MSE для оценки ошибки между предсказанным значением и истинным значением, в то время какcustom_loss_dist
рассчитывает кросс-энтропию для распределения вероятностей, учитывая только разрешенные действия. -
Маскирование: В
custom_loss_dist
добавлено маскирование для выявления действительных действий, что позволяет исключить недопустимые действия из расчета потерь. -
Компиляция модели: При компиляции модели разные функции потерь назначаются для разных выходов, что позволяет корректно вычислить итоговую потерю модели.
Заключение
Следуя вышеизложенным рекомендациям, вы сможете реализовать пользовательскую функцию потерь в Keras для модели с несколькими выходами. Это значительно повысит качество ваших предсказаний и поможет в собеседовании с более сложными задачами. Обратите внимание на детали и старайтесь использовать корректные индексы для работы с различными выходами.