keras-team / keras

Deep Learning for humans
http://keras.io/
Apache License 2.0
61.28k stars 19.38k forks source link

cannot use tf.keras.preprocessing.image.random_channel_shift or apply_channel_shift with tf.data.Dataset functions like image_dataset_from_directory or tensor_slices. #15141

Closed imohammadhossein closed 2 years ago

imohammadhossein commented 2 years ago

I am using tensorflow 2.5, i cannot use apply_channel_shift or random_channel_shift with tf.data.Dataset it raises the following error: tensor object has no attribute "ndim". can any one please write a sample code for me ? i am using .map function for apply agumentation on tf.data Dataset. many thanks.

ymodak commented 2 years ago

Please share a small reproducible code example to validate the issue. Thanks!

imohammadhossein commented 2 years ago

thank you so much

def augment(image, label):
  image = tf.keras.preprocessing.image.apply_channel_shift(image, 100.0)
  return (image, label)

def prepare(ds):
  ds = ds.map(augment, num_parallel_calls=AUTOTUNE)
  return ds.prefetch(buffer_size=AUTOTUNE)

traindata_tfds = tf.keras.preprocessing.image_dataset_from_directory(
path_train, labels='inferred', label_mode='categorical',
class_names=None, color_mode='rgb', batch_size=Batch_size, image_size=(256,
256), shuffle=True, seed=None, validation_split=None, subset=None,
interpolation='bilinear', follow_links=False, smart_resize=True)

train_ds = prepare(traindata_tfds)

you can set any path containing class folders and images inside them as "path_train" and any batch_size you like. @ymodak

ymodak commented 2 years ago

Have you considered using ImageDataGenerator for augmentation instead? Here is an example for that wraps ImageDataGenerator as tf.data.Dataset.

imohammadhossein commented 2 years ago

@ymodak thank you. but it is not as efficient as purely use tf.data. i want to train a huge deep network and efficiency in data loader is my bottle neck. would you please consider fix those functions to accept tensor object? cause it has written in document that we can pass tensor, but we cant and it raises the following error that I mentioned. thank you so much.

ymodak commented 2 years ago

Created a gist to reproduce the reported behavior. Thanks!

imohammadhossein commented 2 years ago

@ymodak thank you. what shall I do for now ?

ymodak commented 2 years ago

I have triaged the issue to the keras team for review. There is no action required from your end for now. Will update this thread with more information as we progress. Thanks!

mattdangerw commented 2 years ago

I think the issue here is that apply_channel_shift expects numpy input. A tf.data.Dataset.map function will use Tensors. You could try calling into tf.numpy_function inside augment and see if that works.

Keras preprocessing layers and tf.image are more friendly tools for preprocessing that can be applied directly to tensors. I don't believe either has a channel shift utility like this though.

Another option would be to write your own with lower level tensorflow ops. The logic is not too complicated: https://github.com/keras-team/keras-preprocessing/blob/master/keras_preprocessing/image/affine_transformations.py#L176

cc13ny commented 2 years ago

As @mattdangerw suggested, it didn't cause errors with the following code replacement. Please check if it's aligned with what @imohamadhoseins expect. Meanwhile, I guess this gap is caused by the difference between TensorFlow 2.0 and the TensorFlow 1.0 code introduced by Keras. Maybe updating the keras function won't be the recommended way. Please correct me if anyone knows more about it.

From

image = tf.keras.preprocessing.image.apply_channel_shift(image, 100.0)

To image = tf.numpy_function(tf.keras.preprocessing.image.apply_channel_shift, [image, 100.0], tf.float32)

imohammadhossein commented 2 years ago

@mattdangerw @cc13ny thankyou for your responses; yes it works with tf.numpy_function but working with numpy drops the performance considerably, i wanted to use thetf.data purely because of it's significant speed in data loading.

@mattdangerw Keras preprocessing layers doesn't have channel shift; I tried to write channel shift function purely with tf on my own but I couldn't, I had some bugs ...

mattdangerw commented 2 years ago

If a pure tensor implementation is required I believe the best option would be to write your own starting with the current implementation https://github.com/keras-team/keras-preprocessing/blob/master/keras_preprocessing/image/affine_transformations.py#L176

We don't plan on rewriting the functionality in https://github.com/keras-team/keras-preprocessing/tree/master/keras_preprocessing/image from numpy to tf ops. Our focus will be on the preprocessing layers and tf.image, and in both those cases, I don't believe we would like an explicit API for random_channel_shift/apply_channel_shift.