Expected behavior
When I create a custom PyDataset and then pass it into the Normalization adapt method, the mean and variance should be computed successfully, as for a TensorFlow dataset.
Actual behavior
Method adapt does not handle the PyDataset like inputs.
Traceback (most recent call last):
File "/home/user/project/keras_bug_sample.py", line 14, in <module>
normalizer.adapt(CustomDataset)
File "/home/user/.pyenv/versions/3.12.8/lib/python3.12/site-packages/keras/src/layers/preprocessing/normalization.py", line 230, in adapt
self.build(input_shape)
^^^^^^^^^^^
UnboundLocalError: cannot access local variable 'input_shape' where it is not associated with a value
Steps to reproduce
import keras
class CustomDataset(keras.utils.PyDataset):
def __len__(self):
return 100
def __getitem__(self, idx):
# Generate dummy data
x = np.random.rand(32, 32, 3)
y = np.random.randint(0, 10, size=(1,))
return x, y
normalizer = keras.layers.Normalization()
normalizer.adapt(CustomDataset)
Comment From: sonali-kumari1
Hi @limzikiki -
Thanks for reporting this. The error UnboundLocalError: cannot access local variable 'input_shape' where it is not associated with a value
occurs because adapt() does not directly support custom datasets like keras.utils.PyDataset
. The adapt()
method expects data to be in the form of tf.data.Dataset
, NumPy array, or a backend-native eager tensor. Since you are passing keras.utils.PyDataset
, adapt()
is not able to extract the input_shape
which leads to the UnboundLocalError
. To resolve this you can convert your custom dataset into tf.data.Dataset
and ensure that dataset is properly batched to compute the mean and variance correctly.
Comment From: limzikiki
I ended up fixing it by subclassing the Normalization class and introducing support for the PyDataset type inputs. I was wondering if the Keras community would also benefit from this feature. Basically, what I did in my solution is that I fetched the first batch, and then, based on its shape, I built the normalisation. I don't know if that's a proper solution. If that’s okay, I can open a PR with the changes.
Comment From: VarunS1997
Please go ahead and make a PR, @limzikiki -- thank you!
Comment From: tripathi-genius
Is it open to contributions? I want to contribute.
Comment From: hertschuh
@tripathi-genius
Is it open to contributions? I want to contribute.
Yes!
The idea is to reuse as much of the existing logic from data_adapters
.
Maybe you can just use get_adapter
and then call get_tf_dataset()
on the returned adapter.