-
Notifications
You must be signed in to change notification settings - Fork 328
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add RandomBrightness preprocessing layer. #122
Conversation
During inference time, the output will be identical to input. Call the layer with | ||
training=True to adjust brightness of the input. | ||
|
||
Note that same brightness adjustment will be apply to all the images in the same |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this what we want? Does this have any positive/negative significant impact on convergence?
https://github.com/tensorflow/models/blob/master/official/vision/beta/projects/simclr/dataloaders/preprocess_ops.py#L30
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great link - yeah, if possible we should avoid applying the same augmentations to an entire batch unless it is extremely difficult to avoid doing so.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also if it is the same on the entire batch why we are not just layer wrapping:
https://www.tensorflow.org/api_docs/python/tf/image/random_brightness
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also as we have discussed in #91 (comment) we still need to evaluate if we want to expose the op in the public API, keep it only in the keras-cv private API or just embedded in the layer itself.
In the case we want to expose the op in the public API are we going to almost duplicate tf.image.random_brightness
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated. The new implementation will generate different adjustment for each of the image in the batch.
On a side note, tf.image.random_brightness has some assumption about the dtype and the range of the value. Eg when dtype is int, it expect the value to range from [0, 255]. When the dtype is float, it will assume the value is ranged [0.0, 1.0]. This means if you give it a float32 image with value [0, 255], then it will almost adjust nothing, since the delta is only [0, 1] and not scaled with * 255.
The current implementation in this PR is only expecting RGB colored image, and all the dtypes should work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes this one is true, but I think that we are entering in another policy here where forking ops is preferred then PR Tensorflow (core).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the difference between the current PR and tf ops is quite large and have different assumption
- Scale the delta based on the input dtype (this is the major one, and has been apply to all the tf.image ops, which I don't think can be easily changed)
- Support of batch inputs. All the existing tf.image ops only take care of single image input. Updating all of them to have batch input support might require more work (but doable).
- Output value clip. (Minor and doable).
- Uneven delta range. (Minor and doable).
I am not sure who is the active API owner of tf.image ops, @fchollet for more inputs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the end probably it is better to take the ownership of tf.image
here and handle the deprecation warning PRs in TF instead of growing incompatible API between TFA/TF/Keras-*.
Then I understand the everyone care only about its ownership but I think that we could improve the library perception to the users/contributors if we think as an ecosystem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, you are right, my mistake. The current PR apply different adjustment to each image, but the tf.image apply the same adjustment.
Checked with @fchollet offline. It seems that there isn't an active owner for tf.image at this moment. We will have some discussion about how we are going to move forward.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current PR apply different adjustment to each image, but the tf.image apply the same adjustment.
Yes like your first original implementation here.
In the end as I've explained it is more an ecosystem coordination/harmonization topic then just forking ops with slightly incompatible behaviors so I've mentioned you with a new comment at #74 (comment).
I hope that we could track this general topic there.
batch. | ||
|
||
Args: | ||
scale: Float or a list/tuple of 2 floats between -1.0 and 1.0. The scale is |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we expose image pixel boundaries as well? I'm starting to think we should support all formats for pixel values (i..e [0,1], [-1, 1], [0, 255]).
This seems like a decision we should make and keep consistent across all of our layers
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For brightness/contrast and any color related augmentation, I feel we should stay with RGB color (0~255). The normalization of the input (for model) should happen after the color adjustment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also think so, like there is a separate rescaling layer that can be used for pixel normalization after all transformation.
Thanks Scott for the feature add! |
It seems that the test for random_cutout are failing. We should fix or disable it for now. |
Weird - I just ran locally and it worked. Let me look into what's going on here. |
false_fn=lambda: inputs, | ||
) | ||
|
||
def _brightness_adjust(self, image): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to standardize image or images?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
A couple comments on consistency within Keras. It seems like bad UX that:
I am not super opinionated on a solution. But I think we should:
|
@mattdangerw Also internally Here in the brightness the ops is forked with a slightly different behaviour. |
I like the idea of aliasing RandomContrast. It will quickly become an outlier as more and more image based preprocessing layers become hosted in KerasCV. Changing the old behavior to expect [0, 255] seems reasonable if KPLs have not been around long enough that this breaking change will be too difficult to get submitted. |
Unless we do some sort of bulk solution, I think that tension will continue to persist somewhat given that there are 10ish image preprocessing layers in core Keras. I would actually vote for |
yeah, that's a really good point. I underestimated how many image augmentations were in core Keras. RandomBrightness does seem to fit the mould a bit better in core Keras. Ok, I'm on board to add it there. |
Honestly we are going to strongly confuse users on the namespace to use or the wheel to install to find a specific CV preprocessing layer. How solarize is different from brightness? It is hard to semantically grasp this namespace difference as the TF user base has both in the same |
For brightness adjustment, the value should be same for all the channels. The existing implementation was generating the different value across the channel.
I also like the idea of having core image KPL in keras core, and have extended KPL in keras-cv, in the meantime, the core image KPL should probably be aliasing here. For the behavior difference of [0, 255] vs [0, 1] in the existing keras image KPL, we should probably fix the discrepancy and unify to [0, 255]. This means we will update the image KPL in core keras. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR!
import tensorflow as tf | ||
|
||
_SCALE_VALIDATION_ERROR = ( | ||
"The `scale` should be number or a list of two numbers " |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"The scale
argument should be a number (or a list of two numbers) "
"in the range [-1.0, 1.0]. "
batch. | ||
|
||
Args: | ||
scale: Float or a list/tuple of 2 floats between -1.0 and 1.0. The scale is |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For naming consistency with other preprocessing layers, we should use factor
, see e.g. https://keras.io/api/layers/preprocessing_layers/image_augmentation/random_rotation/
When -1 is chosen, the output image will be black, and when 1.0 is | ||
chosen, the image will be fully white. When only one float is provided, | ||
eg, 0.2, then -0.2 will be used for lower bound and 0.2 will be used for | ||
upper bound. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we also support integers? Interpreted as a range in absolute levels, e.g. 32
would be interpreted as a +-32 shift of the channels
if input_number > 1.0 or input_number < -1.0: | ||
raise ValueError(_SCALE_VALIDATION_ERROR + f"Got {input_number}") | ||
|
||
def call(self, inputs, training=None): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Augmentation preprocessing layers should default to training=True
(default should be to apply the transformation). You can assume that training
is a Python bool in what follows.
This change is ported from keras-team/keras-cv#122. This layer is considered as a core KPL, since we already have RandomContrast. All the image related KPL will be exposed in the keras-cv later as well. PiperOrigin-RevId: 428849704
This change is ported from keras-team/keras-cv#122. This layer is considered as a core KPL, since we already have RandomContrast. All the image related KPL will be exposed in the keras-cv later as well. PiperOrigin-RevId: 428849704
This change is ported from keras-team/keras-cv#122. This layer is considered as a core KPL, since we already have RandomContrast. All the image related KPL will be exposed in the keras-cv later as well. PiperOrigin-RevId: 428849704
This change is ported from keras-team/keras-cv#122. This layer is considered as a core KPL, since we already have RandomContrast. All the image related KPL will be exposed in the keras-cv later as well. PiperOrigin-RevId: 428849704
This change is ported from keras-team/keras-cv#122. This layer is considered as a core KPL, since we already have RandomContrast. All the image related KPL will be exposed in the keras-cv later as well. PiperOrigin-RevId: 429127641
This change is ported from keras-team/keras-cv#122. This layer is considered as a core KPL, since we already have RandomContrast. All the image related KPL will be exposed in the keras-cv later as well. PiperOrigin-RevId: 429127641 Change-Id: Ide2609d3f2c8d1f33260c99b8607f9df0b289200
Closing this PR now. Since we have keras.layers.RandomContrast, Keras team decided to keep the RandomBrightness in the core keras as well since both of them are very close to each other. See https://github.com/keras-team/keras/blob/9628af85a0a2cb04cf433b1ad991017b70ae2005/keras/layers/preprocessing/image_preprocessing.py#L1393 for more details. |
* Add keras_core.layers.Attention * Address style comments * Fix jax
Fix #87.
As a demo (produced by the demo script).
Original image:
Augmented image (scale by -0.5 ~ 0.5
randomly selected)