Как правильно реализовать пользовательскую функцию squash в TF2.0 (пользовательский слой или другой)

#python-3.x #tensorflow #tensorflow2.0

#python-3.x #tensorflow #tensorflow2.0

Вопрос:

Я пытаюсь реализовать простую модель capsnet в TF2.0.

На данный момент я добавил несколько слоев conv2d и слой reshape, но теперь мне нужно добавить функцию squash. Проблема в том, что tf.norm() отправит меня на NaN посадку, поскольку я сжимаю целые векторы, поэтому мне приходится использовать пользовательскую функцию squash. Я никогда раньше не писал пользовательский слой, и я в основном просто использовал шаблон из руководства и добавил математическую функцию под call() .

Поскольку я делаю все это внутри keras.models.Sequential модели, я не был уверен, как получить результат после первых нескольких слоев, поэтому я просто решил сделать функцию squash своим собственным слоем в модели. Я чувствую, что это, вероятно, совершенно неверно, поэтому я ищу информацию о наилучшем способе решения этой проблемы.

Должен ли я вообще использовать keras.Model для этого, или я должен использовать новую функцию eager execution, чтобы просто передавать тензоры через слои вручную? Если можно использовать SquashLayer() то, что я реализовал, то что мне передать в качестве аргумента, чтобы я получил правильный вывод для перехода на следующий уровень?

 class SquashLayer(tf.keras.layers.Layer):
    def __init__(self, output_units):
        super(SquashLayer, self).__init__()
        self.output_units = output_units

    def build(self, input_shape):
        self.kernel = self.add_variable(
          'kernel', [input_shape[-1], self.output_units])

    def call(self, input):
        squared_norm = tf.reduce_sum(tf.square(input), axis=-1, keepdims=True)
        safe_norm = tf.sqrt(squared_norm   1e-7)
        squash_factor = squared_norm / (1.   squared_norm)
        unit_vector = input / safe_norm
        return squash_factor * unit_vector

model = keras.models.Sequential([
    keras.layers.InputLayer(input_shape=(28, 28, 1)),
    keras.layers.Conv2D(filters=256, kernel_size=9, strides=1, padding='valid', activation=tf.nn.relu, name='conv1'),
    keras.layers.Conv2D(filters=256, kernel_size=9, strides=2, padding='valid', activation=tf.nn.relu, name='conv2'),
    keras.layers.Reshape((-1, caps1_n_caps, caps1_n_dims)),
    SquashLayer()
    ])
  

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

1. Он должен работать нормально, за исключением того, что SquashLayer constructoreв Sequential не получает output_units аргумент. И вы не используете self.kernel в своем пользовательском слое, какой в этом смысл? В противном случае вас должно устраивать tf.keras.models.Sequential , tf.keras.Model были бы хорошие архитектуры, требующие большей гибкости (например, DenseNets). И последнее, но не менее важное, пожалуйста, обновите свой код такими вещами, как caps1_n_caps , чтобы сделать вашу проблему воспроизводимой.