Реализация пользовательского сверточного слоя в Keras - ошибка при загрузке модели - PullRequest
1 голос
/ 29 июня 2019

Я реализовал минимальный пример Wavenet, внимательно следуя приведенным ниже шагам - https://github.com/basveeling/wavenet.

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

Я использую tenenflow 1.13 и keras 2.2.4

Вот пример первых трех пар ключ / значение для объектов.

objects = {'initial_causal_conv': <class 'wavenet_utils.CausalConv1D'>,
           'dilated_conv_1_tanh_s0': <class 'wavenet_utils.CausalConv1D'>,
           'dilated_conv_1_sigm_s0': <class 'wavenet_utils.CausalConv1D'>,
           '...': <class 'wavenet_utils.CausalConv1D'>,
           '...': <class 'wavenet_utils.CausalConv1D'>}
model.fit(x=[x_tr1, x_tr2],
             y=y_tr1,
             epochs=epochs,
             batch_size=batch_size,
             validation_data=([x_vl1, x_vl2], y_vl1),
             callbacks=[checkpoint, early_stopping],
             verbose=verbose,
             shuffle=True,
             class_weight=class_weight)
model = load_model('model.h5', custom_objects=objects)

, который затем возвращает эту ошибку:

Traceback (most recent call last):
  File "/home/xxx/PycharmProjects/WAVE/DATA_NN.py", line 48, in <module>
    objects=objects)
  File "/home/xxx/PycharmProjects/WAVE/functions.py", line 572, in run_neural_net
    model = load_model('model_conv.h5', custom_objects=objects)
  File "/home/xxx/PycharmProjects/WAVE/venv/lib/python3.6/site-packages/keras/engine/saving.py", line 419, in load_model
    model = _deserialize_model(f, custom_objects, compile)
  File "/home/xxx/PycharmProjects/WAVE/venv/lib/python3.6/site-packages/keras/engine/saving.py", line 225, in _deserialize_model
    model = model_from_config(model_config, custom_objects=custom_objects)
  File "/home/xxx/PycharmProjects/WAVE/venv/lib/python3.6/site-packages/keras/engine/saving.py", line 458, in model_from_config
    return deserialize(config, custom_objects=custom_objects)
  File "/home/xxx/PycharmProjects/WAVE/venv/lib/python3.6/site-packages/keras/layers/__init__.py", line 55, in deserialize
    printable_module_name='layer')
  File "/home/xxx/PycharmProjects/WAVE/venv/lib/python3.6/site-packages/keras/utils/generic_utils.py", line 145, in deserialize_keras_object
    list(custom_objects.items())))
  File "/home/xxx/PycharmProjects/WAVE/venv/lib/python3.6/site-packages/keras/engine/network.py", line 1022, in from_config
    process_layer(layer_data)
  File "/home/xxx/PycharmProjects/WAVE/venv/lib/python3.6/site-packages/keras/engine/network.py", line 1008, in process_layer
    custom_objects=custom_objects)
  File "/home/xxx/PycharmProjects/WAVE/venv/lib/python3.6/site-packages/keras/layers/__init__.py", line 55, in deserialize
    printable_module_name='layer')
  File "/home/xxx/PycharmProjects/WAVE/venv/lib/python3.6/site-packages/keras/utils/generic_utils.py", line 138, in deserialize_keras_object
    ': ' + class_name)
ValueError: Unknown layer: CausalConv1D

КогдаПри построении модели CausalConv1D необходимо импортировать из wavenet_utils.py

Ниже приведена полная функция build_model А вот wavenet_utils, содержащая класс CausalConv1D :

from keras.layers import Conv1D
from keras.utils.conv_utils import conv_output_length
import tensorflow as tf


class CausalConv1D(Conv1D):
    def __init__(self, filters, kernel_size, init='glorot_uniform', activation=None,
                 padding='valid', strides=1, dilation_rate=1, bias_regularizer=None,
                 activity_regularizer=None, kernel_constraint=None, bias_constraint=None, use_bias=True, causal=False,
                 output_dim=1,
                 **kwargs):
        self.output_dim = output_dim

        super(CausalConv1D, self).__init__(filters,
                                           kernel_size=kernel_size,
                                           strides=strides,
                                           padding=padding,
                                           dilation_rate=dilation_rate,
                                           activation=activation,
                                           use_bias=use_bias,
                                           kernel_initializer=init,
                                           activity_regularizer=activity_regularizer,
                                           bias_regularizer=bias_regularizer,
                                           kernel_constraint=kernel_constraint,
                                           bias_constraint=bias_constraint,
                                           **kwargs)

        self.causal = causal
        if self.causal and padding != 'valid':
            raise ValueError("Causal mode dictates border_mode=valid.")

    def build(self, input_shape):
        super(CausalConv1D, self).build(input_shape)

    def call(self, x):
        if self.causal:
            def asymmetric_temporal_padding(x, left_pad=1, right_pad=1):
                pattern = [[0, 0], [left_pad, right_pad], [0, 0]]
                return tf.pad(x, pattern)

            x = asymmetric_temporal_padding(x, self.dilation_rate[0] * (self.kernel_size[0] - 1), 0)
        return super(CausalConv1D, self).call(x)

    def compute_output_shape(self, input_shape):
        input_length = input_shape[1]

        if self.causal:
            input_length += self.dilation_rate[0] * (self.kernel_size[0] - 1)

        length = conv_output_length(input_length,
                                    self.kernel_size[0],
                                    self.padding,
                                    self.strides[0],
                                    dilation=self.dilation_rate[0])

        shape = tf.TensorShape(input_shape).as_list()
        shape[-1] = self.output_dim
        return (input_shape[0], length, self.filters)

    def get_config(self):
        base_config = super(CausalConv1D, self).get_config()
        base_config['output_dim'] = self.output_dim
        return base_config

РЕДАКТИРОВАТЬ:

Я пробовал этот подход и раньше.

objects = {'CausalConv1D': <class 'wavenet_utils.CausalConv1D'>}
model.fit(x=[x_tr1, x_tr2],
             y=y_tr1,
             epochs=epochs,
             batch_size=batch_size,
             validation_data=([x_vl1, x_vl2], y_vl1),
             callbacks=[checkpoint, early_stopping],
             verbose=verbose,
             shuffle=True,
             class_weight=class_weight)
model = load_model('model.h5', custom_objects=objects)

, который затем возвращает эту ошибку:

Traceback (most recent call last):
  File "/home/xxx/PycharmProjects/WAVE/DATA_NN.py", line 47, in <module>
    objects=objects)
  File "/home/xxx/PycharmProjects/WAVE/functions.py", line 574, in run_neural_net
    model = load_model('model.h5', custom_objects=objects)
  File "/home/xxx/PycharmProjects/WAVE/venv/lib/python3.6/site-packages/keras/engine/saving.py", line 419, in load_model
    model = _deserialize_model(f, custom_objects, compile)
  File "/home/xxx/PycharmProjects/WAVE/venv/lib/python3.6/site-packages/keras/engine/saving.py", line 225, in _deserialize_model
    model = model_from_config(model_config, custom_objects=custom_objects)
  File "/home/xxx/PycharmProjects/WAVE/venv/lib/python3.6/site-packages/keras/engine/saving.py", line 458, in model_from_config
    return deserialize(config, custom_objects=custom_objects)
  File "/home/xxx/PycharmProjects/WAVE/venv/lib/python3.6/site-packages/keras/layers/__init__.py", line 55, in deserialize
    printable_module_name='layer')
  File "/home/xxx/PycharmProjects/WAVE/venv/lib/python3.6/site-packages/keras/utils/generic_utils.py", line 145, in deserialize_keras_object
    list(custom_objects.items())))
  File "/home/xxx/PycharmProjects/WAVE/venv/lib/python3.6/site-packages/keras/engine/network.py", line 1022, in from_config
    process_layer(layer_data)
  File "/home/xxx/PycharmProjects/WAVE/venv/lib/python3.6/site-packages/keras/engine/network.py", line 1008, in process_layer
    custom_objects=custom_objects)
  File "/home/xxx/PycharmProjects/WAVE/venv/lib/python3.6/site-packages/keras/layers/__init__.py", line 55, in deserialize
    printable_module_name='layer')
  File "/home/xxx/PycharmProjects/WAVE/venv/lib/python3.6/site-packages/keras/utils/generic_utils.py", line 147, in deserialize_keras_object
    return cls.from_config(config['config'])
  File "/home/xxx/PycharmProjects/WAVE/venv/lib/python3.6/site-packages/keras/engine/base_layer.py", line 1109, in from_config
    return cls(**config)
  File "/home/xxx/PycharmProjects/WAVE/wavenet_utils.py", line 26, in __init__
    **kwargs)
TypeError: __init__() got multiple values for keyword argument 'kernel_initializer'

Может ли это быть проблемой, упомянутой здесь https://github.com/keras-team/keras/issues/12316?

И если так,есть ли способ обойти это?

Ответы [ 2 ]

2 голосов
/ 29 июня 2019

Существует только один пользовательский объект, который CausalConv1D.

objects = {'CausalConv1D': wavenet_utils.CausalConv1D}

Теперь вы должны быть уверены, что ваш метод get_config правильный и содержит все необходимое в методе __init__ вашего слоя.

Он пропускает свойство causal и имеет kernel_initializer, исходящий из базового класса, который не поддерживается вашим методом __init__.

Давайте перечислим каждое необходимое вам свойство, а затем проверим, какие из них есть в базовой конфигурации:

  • фильтры: в базе
  • kernel_size: в базе
  • init: не в базе, но в базе kernel_initializer !!!!!
    • kernel_initializer - это элемент конфигурации, который не поддерживается вашим методом __init__
    • переименуйте этот init параметр в kernel_initializer
  • активация: в базе
  • набивка: в основании
  • шагов: в базе
  • dilation_rate: в базе
  • bias_regularizer: в базе
  • Activity_regularizer: в базе
  • kernel_constraint: в базе
  • bias_constraint: в базе
  • use_bias: в базе
  • причинно-следственная связь: не в базе !
    • должен добавить это в свой конфиг! (или модель всегда будет использовать значение по умолчанию)
  • output_dim: не в базе !
  • ** Кварги: в базе

Слой __init__:

def __init__(self, filters, kernel_size, 

             ############## here:
             kernel_initializer='glorot_uniform', 
             #############

             activation=None,
             padding='valid', strides=1, dilation_rate=1, bias_regularizer=None,
             activity_regularizer=None, kernel_constraint=None, bias_constraint=None, use_bias=True, causal=False,
             output_dim=1,
             **kwargs):

Слой get_config

Он должен содержать все параметры __init__, которые не входят в базовый класс:

def get_config(self):
    base_config = super(CausalConv1D, self).get_config()
    base_config['causal'] = self.causal
    base_config['output_dim'] = self.output_dim
    return base_config
1 голос
/ 29 июня 2019

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

model = build_model()

checkpoint = ModelCheckpoint('model.h5', monitor='val_acc',
                             verbose=1, save_best_only=True, save_weights_only=True, mode='max')

model.fit(x, y)

del model

model = build_model()

model.load_weights('model.h5')

model.predict(x_test)
...