Как сохранить имена пользовательских слоев и избежать "TensorFlowOpLayer" при экспорте модели json - PullRequest
1 голос
/ 06 мая 2020

Я обучаю последовательную модель tf.keras, которую хочу преобразовать в формат tfjs, состоящий из файла model.json с описанием слоев и файлов двоичных весов, чтобы развернуть ее на веб-сайте для вывода.

Два слоя в моей модели являются пользовательскими слоями, так как в tf.keras.layers нет подходящих слоев, предопределенных для работы. Это фиктивная версия того, как выглядит мой код модели:

import tensorflow as tf

class SliceChannelsLayer(tf.keras.layers.Layer):
    ... (model implementation) ...

class L1NormLayer(tf.keras.layers.Layer):
    ... (model implementation) ...

def sequential_model():
    inputs = tf.keras.Input(shape=(30, 36, 36, 6), batch_size=None)
    outputs_a = SliceChannelsLayer(start=0, end=3)(inputs)
    outputs_b = SliceChannelsLayer(start=3, end=6)(inputs)
    ...
    other Keras layers
    ...
    attention = L1NormLayer(1)(attention)
    outputs_motion = tf.keras.layers.Multiply()([outputs_a, attention])
    return tf.keras.Model(inputs, outputs_b)

model = sequential_model()

В моем коде JavaScript я реализовал два настраиваемых слоя как , как показано в примере, приведенном в tf js -examples :

class SliceChannelsLayer extends tf.layers.Layer {
  ... (model implementation) ...
}

class L1NormLayer extends tf.layers.Layer {
  ... (model implementation) ...
}

При запуске tfjs.converters.save_keras_model(model, "tfjs_export") оба настраиваемых слоя получают одинаковое имя в model.json: TensorFlowOpLayer.

Однако , Мне нужно сопоставить имена моих реализаций слоя JavaScript с этими именами, что невозможно, когда несколько слоев получают одно и то же имя. Мой код работает, когда я вручную редактирую файл model.json, чтобы заменить TensorFlowOpLayer на SliceChannelsLayer или L1NormLayer.

Мой вопрос : Как мне избежать необходимости вручную изменять имена слоев в model.json после экспорта?

Изменить: поведение можно воспроизвести с помощью следующего кода:

import tensorflow as tf
import tensorflowjs as tfjs

class L1NormLayer(tf.keras.layers.Layer):
    """L1NormLayer"""
    def __init__(self, axis, **kwargs):
        super(L1NormLayer, self).__init__()
        self.axis = axis
    def __call__(self, inputs):
        inputs, _ = tf.linalg.normalize(inputs, ord=1, axis=self.axis)
        return inputs

class SliceChannelsLayer(tf.keras.layers.Layer):
    """SliceChannelsLayer"""
    def __init__(self, start, end, **kwargs):
        super(SliceChannelsLayer, self).__init__()
        self.start = start
        self.end = end
    def __call__(self, inputs):
        inputs = inputs[:, :, :, :, self.start:self.end]
        return inputs

inputs = tf.keras.Input(shape=(29, 36, 36, 6), batch_size=1)
outputs_a = SliceChannelsLayer(start=0, end=3, name="SliceChannels")(inputs)
outputs_b = SliceChannelsLayer(start=3, end=6, name="SliceChannels")(inputs)
attention = tf.keras.layers.TimeDistributed(
    tf.keras.layers.Conv2D(
        filters=1, kernel_size=(1, 1), activation="sigmoid"))(
            outputs_b)
attention = L1NormLayer(1, name="L1Norm")(attention)
outputs_a = tf.keras.layers.Multiply()([outputs_b, attention])
outputs_a = tf.keras.layers.Dense(units=1, activation="linear")(outputs_a)
model = tf.keras.Model(inputs=inputs, outputs=outputs_a)

model.compile(loss='mean_squared_error',
              optimizer=tf.keras.optimizers.RMSprop())

model.summary()

tfjs.converters.save_keras_model(model, "tfjs")

1 Ответ

1 голос
/ 06 мая 2020

Метод __call__ должен быть call.

...