Обучите предварительно обученную пользовательскую модель с другой функцией потерь

В TF2 keras я обучил автоэнкодер, используя tensorflow.keras.losses.MeanSquaredError в качестве функции потерь. Теперь я хочу дополнительно обучить эту модель, используя другую функцию потерь, а именно tenorflow.keras.losses.KLDivergence. Причина этого в том, что изначально обучение без учителя проводится для репрезентативного обучения. Затем, имея сгенерированные вложения, я могу кластеризовать их и использовать эти кластеры для самоконтроля, то есть меток, позволяя вторую контролируемую потерю и улучшая модель дальше.

Это не переносное обучение как таковое, поскольку в модель не добавляются новые слои, изменяется только функция потерь, и модель продолжает обучение.

Я пробовал использовать предварительно обученную модель с потерей MSE в качестве свойства новой модели:

class ClusterBooster(tf.keras.Model):

 def __init__(self, base_model, centers):
    super(ClusterBooster, self).__init__()

    self.pretrained = base_model
    self.centers = centers


 def train_step(self, data):
    with tf.GradientTape() as tape:
        loss = self.compiled_loss(self.P, self.Q, regularization_losses=self.losses)

    # Compute gradients
    gradients = tape.gradient(loss, self.trainable_variables)
    
    # Update weights
    self.optimizer.apply_gradients(zip(gradients, self.trainable_variables))

    return {m.name: m.result() for m in self.metrics}

где потеря - это потеря KL между распределениями P и Q. Распределения вычисляются в функции обратного вызова вместо модели train_step, поскольку мне нужен доступ к текущей эпохе (P обновляется каждые 5 эпох, а не каждую эпоху):

def on_epoch_begin(self, epoch, logs=None):
    z = self.model.pretrained.embed(self.feature, training=True)
    z = tf.reshape(z, [tf.shape(z)[0], 1, tf.shape(z)[1]])  # reshape for broadcasting
    # CALCULATE Q FOR EVERY EPOCH
    partial = tf.math.pow(tf.norm(z - self.model.centers, axis=2, ord='euclidean'), 2)
    nominator = 1 / (1 + partial)
    denominator = tf.math.reduce_sum(1 / (1 + partial))
    self.model.Q = nominator / denominator

    # CALCULATE P EVERY 5 EPOCHS TO AVOID INSTABILITY
    if epoch % 5 == 0:
        partial = tf.math.pow(self.model.Q, 2) / tf.math.reduce_sum(self.model.Q, axis=1, keepdims=True)
        nominator = partial
        denominator = tf.math.reduce_sum(partial, axis=0)
        self.model.P = nominator / denominator

Однако при выполнении apply_gradients () я получаю:

ValueError: No gradients provided for any variable: ['dense/kernel:0', 'dense/bias:0', 'dense_1/kernel:0', 'dense_1/bias:0', 'dense_2/kernel:0', 'dense_2/bias:0', 'dense_3/kernel:0', 'dense_3/bias:0']

Я думаю, что это связано с тем, что предварительно обученная модель не настроена на дальнейшее обучение где-то внутри новой модели (вызывается только метод embed (), который не обучает модель). Это правильный подход, и я просто что-то упускаю, или есть способ лучше?


person Marinos Poiitis    schedule 31.01.2021    source источник


Ответы (1)


Кажется, что любые вычисления, выполняемые в обратном вызове, не отслеживаются для вычисления градиента и обновления веса. Таким образом, эти вычисления следует поместить в функцию train_step () пользовательского класса модели (ClusterBooster).

При условии, что у меня нет доступа к количеству эпох внутри функции train_step () ClusterBooster, я создал настраиваемый цикл обучения без класса модели, где я мог бы использовать простой код Python (который быстро вычисляется).

person Marinos Poiitis    schedule 02.02.2021