I've constructed a mini-version of a model I want to train for the sake of debugging with this function:
def build_mini_model(contrast_factor=1.25):
# Define input layer with variable input shape
inputs = tf.keras.Input(shape=(None, None, 3)) # Accepts images of any size with 3 channels (RGB)
# Convert RGB to grayscale
x= tf.image.rgb_to_grayscale(inputs)
# Enhance contrast
x = tf.image.adjust_contrast(x, contrast_factor)
# Create a functional model
mini_model = Model(inputs=inputs, outputs=x)
return mini_model
I then create and compile it:
mini_model = build_mini_model()
mini_model.compile(optimizer=Adam(), loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
mini_model.summary()
and see the following summary:
Model: "model_3"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_5 (InputLayer) [(None, None, None, 3)] 0
tf.image.rgb_to_grayscale_ (None, None, None, 1) 0
4 (TFOpLambda)
tf.image.adjust_contrast_4 (None, None, None, 1) 0
(TFOpLambda)
=================================================================
Total params: 0 (0.00 Byte)
Trainable params: 0 (0.00 Byte)
Non-trainable params: 0 (0.00 Byte)
But, when I try to test pusing an image through it like this:
l_in = tf.random.normal((1, 32, 32, 3))
for x in range(len(mini_model.layers)):
print(x,mini_model.layers[x].name, l_in.shape)
l_out = mini_model.layers[x](l_in)
print(" ", l_out.shape)
l_in = l_out
I get the following output:
0 input_5 (1, 32, 32, 3)
(1, 32, 32, 3)
1 tf.image.rgb_to_grayscale_4 (1, 32, 32, 3)
(1, 32, 32, 1)
2 tf.image.adjust_contrast_4 (1, 32, 32, 1)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[68], line 4
2 for x in range(len(mini_model.layers)):
3 print(x,mini_model.layers[x].name, l_in.shape)
----> 4 l_out = mini_model.layers[x](l_in)
5 print(" ", l_out.shape)
6 l_in = l_out
File ~/anaconda3/envs/IK_env/lib/python3.11/site-packages/keras/src/utils/traceback_utils.py:70, in filter_traceback.<locals>.error_handler(*args, **kwargs)
67 filtered_tb = _process_traceback_frames(e.__traceback__)
68 # To get the full stack trace, call:
69 # `tf.debugging.disable_traceback_filtering()`
---> 70 raise e.with_traceback(filtered_tb) from None
71 finally:
72 del filtered_tb
File ~/anaconda3/envs/IK_env/lib/python3.11/site-packages/tensorflow/python/util/dispatch.py:1170, in add_dispatch_support.<locals>.decorator.<locals>.op_dispatch_handler(*args, **kwargs)
1168 if iterable_params is not None:
1169 args, kwargs = replace_iterable_params(args, kwargs, iterable_params)
-> 1170 result = api_dispatcher.Dispatch(args, kwargs)
1171 if result is not NotImplemented:
1172 return result
TypeError: Missing required positional argument
When I go to the documentation at TF_Docs, I see that tf.image.adjust_contrast
only expects 2 arguments:
tf.image.adjust_contrast(
images, contrast_factor
)
which I've given it.
If I break this down layer-by-layer and explicitly call the tf.image.adjust_contrast
, everything is fine:
l_in = tf.random.normal((1, 32, 32, 3))
l_out = model.layers[0](l_in)
print(0,model.layers[0].name, l_in.shape)
print(" ",l_out.shape)
l_in = l_out
l_out = model.layers[1](l_in)
print(1,model.layers[1].name, l_in.shape)
print(" ",l_out.shape)
l_in = l_out
print(x,model.layers[2].name, l_in.shape)
l_out = tf.image.adjust_contrast(l_in, 1.25)
print(" ",l_out.shape)
Gives this output:
0 input_3 (1, 32, 32, 3)
(1, 32, 32, 3)
1 tf.image.rgb_to_grayscale_2 (1, 32, 32, 3)
(1, 32, 32, 1)
2 tf.image.adjust_contrast_2 (1, 32, 32, 1)
(1, 32, 32, 1)
What am I doing wrong here?
It seems like(?) you're invoking every layer's call method individually by mini_model.layers[x](l_in)
, so for adjust_contrast it should be mini_model.layers[x](l_in, constrast_factor)
.
The easiest way to solve this is to create a new layer by subclassing:
class AdjustContrastLayer(tf.keras.layers.Layer):
def __init__(self, contrast_factor, **kwargs):
super(AdjustContrastLayer, self).__init__(**kwargs)
self.contrast_factor = contrast_factor
def call(self, inputs):
return tf.image.adjust_contrast(inputs, self.contrast_factor)
def get_config(self):
config = super(AdjustContrastLayer, self).get_config()
config.update({"contrast_factor": self.contrast_factor})
return config
The model construction looks like this:
def build_mini_model(contrast_factor=1.25):
inputs = tf.keras.Input(shape=(None, None, 3))
x= tf.image.rgb_to_grayscale(inputs)
x = AdjustContrastLayer(contrast_factor)(x)
mini_model = Model(inputs=inputs, outputs=x)
return mini_model
After that your for loop should also execute normally.