romanovzky
romanovzky

Reputation: 183

How to substitute `keras.layers.merge._Merge` in `tensorflow.keras`

I want to create a custom Merge layer using the tf.keras API. However, the new API hides the keras.layers.merge._Merge class that I want to inherit from.

The purpose of this is to create a Layer that can perform a weighted sum/merge of the outputs of two different layers. Before, and in keras python API (not the one included in tensorflow.keras) I could inherit from keras.layers.merge._Merge class, which is now not accessible from tensorflow.keras.

Where before I could do this

class RandomWeightedAverage(keras.layers.merge._Merge):
    def __init__(self, batch_size):
        super().__init__()
        self.batch_size = batch_size
    def _merge_function(self, inputs):
        alpha = K.random_uniform((self.batch_size, 1, 1, 1))
        return (alpha * inputs[0]) + ((1 - alpha) * inputs[1])

Now I cannot use the same logic if using tensorflow.keras

class RandomWeightedAverage(tf.keras.layers.merge._Merge):
    def __init__(self, batch_size):
        super().__init__()
        self.batch_size = batch_size
    def _merge_function(self, inputs):
        alpha = K.random_uniform((self.batch_size, 1, 1, 1))
        return (alpha * inputs[0]) + ((1 - alpha) * inputs[1])

Produces

AttributeError: module 'tensorflow.python.keras.api._v1.keras.layers' has no attribute 'merge'

I have also tried inheriting from Layer class instead

class RandomWeightedAverage(tensorflow.keras.layers.Layer):
    def __init__(self, batch_size):
        super().__init__()
        self.batch_size = batch_size
    def call(self, inputs):
        alpha = K.random_uniform((self.batch_size, 1, 1, 1))
        return (alpha * inputs[0]) + ((1 - alpha) * inputs[1])

which gives me a layer with output shape equals to multiple, whereas I want the output shape to be well defined. I further attempted

class RandomWeightedAverage(tensorflow.keras.layers.Layer):
    def __init__(self, batch_size):
        super().__init__()
        self.batch_size = batch_size
    def call(self, inputs):
        alpha = K.random_uniform((self.batch_size, 1, 1, 1))
        return (alpha * inputs[0]) + ((1 - alpha) * inputs[1])

    def compute_output_shape(self, input_shape):
        return input_shape[0]

But this did not solve the multiple ambiguity as output shape.

Upvotes: 6

Views: 6669

Answers (1)

Raphael Meudec
Raphael Meudec

Reputation: 741

I have slightly modified your code to use tf.random_uniform instead of K.random_uniform and it's working fine on 1.13.1 and 1.14.0 (full snippet and resulting model.summary() below).

import tensorflow as tf
print(tf.__version__)


class RandomWeightedAverage(tf.keras.layers.Layer):
    def __init__(self, batch_size):
        super().__init__()
        self.batch_size = batch_size

    def call(self, inputs, **kwargs):
        alpha = tf.random_uniform((self.batch_size, 1, 1, 1))
        return (alpha * inputs[0]) + ((1 - alpha) * inputs[1])

    def compute_output_shape(self, input_shape):
        return input_shape[0]


x1 = tf.keras.layers.Input((32, 32, 1))
x2 = tf.keras.layers.Input((32, 32, 1))

y = RandomWeightedAverage(4)(inputs=[x1, x2])

model = tf.keras.Model(inputs=[x1, x2], outputs=[y])

print(model.summary())

model summary

Upvotes: 7

Related Questions