Недавно, экспериментируя с дистилляцией знаний для уменьшения размера моделей глубоких нейронных сетей, я хотел опробовать предложение, сделанное JH Cho et. al в своей статье под названием Об эффективности извлечения знаний.

Они утверждают, что для лучшего обучения модели ученика помогает преждевременное прекращение обучения модели учителя. Они также делятся обширным набором результатов для проверки своих утверждений. Вдохновленный этим, я захотел попробовать это на себе.

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

Здесь я описываю два метода:

Способ 1

В этом методе вместо одного вызова метода model.fit () для общего количества эпох (total_epochs) мы можем перекомпилировать модель с скорректированными весами потерь после каждую эпоху и тренируйте модель для одной эпохи за раз.

for epoch in range(total_epochs):
    loss_weights = loss_adjuster(epoch) # Calculate the weights
    model.compile(optimizer = optimizer,
                       loss = loss, # Loss definitions
                       loss_weights = loss_weights)
    loss = model.fit(x, y) # Fit on the dataset

Если веса потерь не меняются после каждой эпохи, возможно, лучшим подходом будет разделение обучения на разные этапы (a эпох на этапе I и b эпох на II этапе и так далее). Это потребует перекомпиляции модели только один раз перед каждым этапом, а также позволит использовать встроенные методы keras для обучения. Ниже приводится пример двухэтапного разделения.

Stage I
loss_weights = [0.1, 0.9]
model.compile(optimizer = optimizer,
                       loss = loss, # Loss definitions
                       loss_weights = loss_weights)
loss = model.fit(data_generator, # Fit on the dataset
                 epochs = a_epochs)
Stage II
loss_weights = [0.0, 1.0]
model.compile(optimizer = optimizer,
                       loss = loss, # Loss definitions
                       loss_weights = loss_weights)
loss = model.fit(data_generator, # Fit on the dataset
                 epochs = b_epochs)

Теперь, несмотря на то, что это простой и понятный метод, он включает в себя повторную перекомпиляцию модели.

Способ 2

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

Вышеупомянутый метод отлично подходит для обучения, но вызывает следующую ошибку при сохранении модели с помощью model.save ().

TypeError: (‘Not JSON Serializable:’, <tf.Variable ‘Variable:0’ shape=() dtype=float32, numpy=1.0>)

Следующая причина объясняется вышеупомянутой ошибкой, как упомянуто здесь

«… Нельзя использовать объекты переменных тензорного потока в скомпилированных аргументах…»

Это означает, что описанный выше метод имеет ограниченную практичность, поскольку мы не сможем сохранить полное состояние модели для целей повторного обучения. Хотя, если вас интересуют только веса модели, этот метод должен работать нормально.

Метод 2.1

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

Благодаря этому мы, наконец, можем сохранить модель со всеми скомпилированными аргументами. Конечно, у этого метода есть свои недостатки, так как мы больше не можем следить за исходными значениями потерь.

Если вы находите подобные истории ценными и хотели бы поддержать меня как писателя, подумайте о подписке на членство Medium. Это 5 долларов в месяц и дает вам неограниченный доступ к статьям Medium. Регистрация по реферальной ссылке предоставит мне небольшую комиссию без каких-либо дополнительных затрат для вас.