'Can you mix keras.layers output with tensorflow operations?
I know that output of keras layers (like keras.layers.Dense()
) produce so-called 'keras tensors'. Also, there are 'tensorflow tensors' that are produced by tensorflow operations (like tf.reduce_sum()
).
Some functionality can be delivered by only one of those approaches, so it is obvious that I will have to mix them sometimes to do the calculation. In my opinion, mixing keras layers code with tf ops looks far from beatiful but thats another topic.
My question is - is it doable to mix keras layers and tensorflow ops? And will there be any problems related to mixing keras and tensorflow tensors that they produce?
Lets consider an example of custom class, don't look deep into the calculation, it makes no sense. The point is to show what I'm talking about.
class Calculation(layers.Layer):
def __init__(self, units):
super().__init__()
self.units = units
self.conv3d = layers.Conv3D(units, kernel_size=3, strides=2)
self.norm = layers.LayerNormalization(units)
def call(self, x):
x = activations.gelu(x)
x = self.norm(x) # keras layer
x = tf.transpose(x, (0, 4, 1, 2, 3))
x = self.conv3d(x) # keras layer
x = tf.transpose(x, (0, 2, 3, 4, 1))
x = tf.reshape(x, (-1, 1, 2 * self.units))
return x
Another example, this time not inside custom layer:
encoder_input = keras.Input(shape=(28, 28, 1), name="img")
x = layers.Conv2D(16, 3, activation="relu")(encoder_input)
x = layers.Conv2D(32, 3, activation="relu")(x)
x = layers.MaxPooling2D(3)(x)
x = layers.Conv2D(32, 3, activation="relu")(x)
x = tf.einsum('...ijk->...jik', x) # tensorflow op, just swap height and width for no reason
x = layers.Conv2D(16, 3, activation="relu")(x)
I know that there is such thing as keras.layers.Lambda
layer, but sometimes I need to use like 90% of tensorflow ops and only 10% of calculations done by keras layers (because there is no tf op alternative and I don't want to implement my own every time). In that case using lambda layer makes little sense.
Is there a good approach for writing complex models (where implementation lays beyond just stacking keras existing layers) in tensorflow 2.X?
Solution 1:[1]
IMO, it actually does not matter how you mix Tensorflow
operations with Keras
layers as long as you preserve the batch dimension and generally the tensor shape. You might want to, for example, wrap the tf
operations inside Lambda
layers to set some meta-data like the names, but that depends on your taste:
import tensorflow as tf
encoder_input = tf.keras.Input(shape=(28, 28, 1), name="img")
x = tf.keras.layers.Conv2D(16, 3, activation="relu")(encoder_input)
x = tf.keras.layers.Conv2D(32, 3, activation="relu")(x)
x = tf.keras.layers.MaxPooling2D(3)(x)
x = tf.keras.layers.Conv2D(32, 3, activation="relu")(x)
x = tf.keras.layers.Lambda(lambda x: tf.einsum('...ijk->...jik', x), name='Einsum')(x) # tensorflow op, just swap height and width for no reason
x = tf.keras.layers.Conv2D(16, 3, activation="relu")(x)
model = tf.keras.Model(encoder_input, x)
print(model.summary())
Model: "model_1"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
img (InputLayer) [(None, 28, 28, 1)] 0
conv2d_4 (Conv2D) (None, 26, 26, 16) 160
conv2d_5 (Conv2D) (None, 24, 24, 32) 4640
max_pooling2d_1 (MaxPooling (None, 8, 8, 32) 0
2D)
conv2d_6 (Conv2D) (None, 6, 6, 32) 9248
Einsum (Lambda) (None, 6, 6, 32) 0
conv2d_7 (Conv2D) (None, 4, 4, 16) 4624
=================================================================
Total params: 18,672
Trainable params: 18,672
Non-trainable params: 0
_________________________________________________________________
None
For example, if you use tf.reduce_sum
with axis=0
, you lose the batch dimension (None
), which is problematic for a Keras
model:
import tensorflow as tf
encoder_input = tf.keras.Input(shape=(28, 28, 1), name="img")
x = tf.keras.layers.Conv2D(16, 3, activation="relu")(encoder_input)
x = tf.reduce_sum(x, axis=0)
model = tf.keras.Model(encoder_input, x)
print(model.summary())
Model: "model_4"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
img (InputLayer) [(None, 28, 28, 1)] 0
conv2d_12 (Conv2D) (None, 26, 26, 16) 160
tf.math.reduce_sum_1 (TFOpL (26, 26, 16) 0
ambda)
=================================================================
Total params: 160
Trainable params: 160
Non-trainable params: 0
_________________________________________________________________
None
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |