Не удается загрузить модель keras с пользовательским ограничением

#python #keras

#python #keras

Вопрос:

Я создал пользовательское ограничение для моего keras GRU-NN и смог обучить свою сеть с его помощью. Ограничение выглядит следующим образом:

 import keras.backend as K
from keras.constraints import Constraint

class WeightClip(Constraint):
    def __init__(self, mn=0.1, mx=1.0):
        self.mn = mn
        self.mx = mx

    def __call__(self, p):
        return K.clip(p, self.mn, self.mx)

    def get_config(self):
        return {
            'name': self.__class__.__name__,
            'minimum': self.mn, 
            'maximum': self.mx
        }
  

После сохранения модели и попытки перезагрузить ее с

 model = keras.models.load_model(modelFile, custom_objects={'WeightClip': WeightClip})
  

Я получил это сообщение об ошибке:

 TypeError: __init__() got an unexpected keyword argument 'name'
  

Сама модель выглядит следующим образом:

 model = Sequential()
model.add(GRU(
    params.recurrent_units, 
    activation='linear',
    input_shape=(pr.n_features, pr.feature_size), 
    dropout=params.dropout, name='net',
    kernel_constraint=WeightClip(0.1, 1.0),
    bias_constraint=WeightClip(0.1, 1.0)
))
model.add(Dense(
    1, 
    activation='sigmoid', 
    kernel_constraint=WeightClip(0.1, 1.0),
    bias_constraint=WeightClip(0.1, 1.0)
))
  

Ссылаясь на другие подобные вопросы по stackoverflow, которые в большинстве случаев связаны с пользовательскими показателями, я пробовал разные комбинации параметра custom_objects, но, похоже, ничего не помогает. Спасибо за любую помощь!

Комментарии:

1. Кажется, теперь работает. Вместо возврата фактической конфигурации в функции get_config я возвращаю пустые фигурные скобки. Понятия не имею, влияет ли это на поведение модели при составлении прогнозов, но на данный момент это меня не беспокоит. Если кто-нибудь хочет объяснить, я все равно был бы рад!

Ответ №1:

Что происходит за кулисами

Когда вы сохраняете модель, содержащую custom_object в keras , она сохранит ссылку на имя класса, а также словарь, содержащий текущую конфигурацию объектов. Это делается путем вызова .get_config() метода экземпляра пользовательского объекта. Для этого этот метод должен возвращать словарь со всем необходимым для воссоздания экземпляра.

После вызова keras.models.load() , keras загрузит вашу модель и создаст экземпляры ваших пользовательских объектов, используя сохраненные словари. Давайте на мгновение предположим, что old_object_configuration = weight_clip_instance.get_config() . keras теперь будем создавать новый экземпляр с помощью new_weight_clip_instance = WeightClip(**old_object_configuration) . Когда вы возвращаете параметр name в вашем .get_config() методе, но в сигнатуре WeightClip.__init__() параметра name отсутствует, будет выдана ошибка, которую вы видите.

Влияет ли возврат пустого dict на вашу модель?

Используя знания, приведенные выше, теперь мы можем предсказать, что произойдет, если ваш .get_config() метод вернет пустой словарь. Это приводит к вызову new_weight_clip_instance = WeightClip({}) . Новый экземпляр будет иметь значения по умолчанию для mn=0.1 и mx=1.0 , что не является желаемым поведением и приводит к труднодоступным ошибкам.

Рабочий пример

 import keras
import keras.backend as K
from keras import Sequential
from keras.constraints import Constraint
from keras.layers import GRU, Dense


RECURRENT_UNITS = 10
N_FEATURES = 10
FEATURE_SIZE = 50
DROPOUT = 0.5


class WeightClip(Constraint):
    def __init__(self, minimum=0.1, maximum=1.0):
        self.minimum = minimum
        self.maximum = maximum

    def __call__(self, p):
        return K.clip(p, self.minimum, self.maximum)

    def get_config(self):
        return {
            'minimum': self.minimum,
            'maximum': self.maximum
        }


model = Sequential()
model.add(GRU(
    RECURRENT_UNITS,
    activation='linear',
    input_shape=(N_FEATURES, FEATURE_SIZE),
    dropout=DROPOUT,
    name='net',
    kernel_constraint=WeightClip(0.1, 1.0),
    bias_constraint=WeightClip(0.1, 1.0)
))
model.add(Dense(
    1,
    activation='sigmoid',
    kernel_constraint=WeightClip(0.1, 1.0),
    bias_constraint=WeightClip(0.1, 1.0)
))
model.save('mymodel')

model = keras.models.load_model('mymodel', custom_objects={'WeightClip': WeightClip})