2

Imgaug has a p parameter which defines a probability for how often a certain augmentation is applied e.g. in 50% of the inputs. Is there something similar for the Keras PreprocessingLayers? One example of such a layer is the RandomFlip. In imgaug we can say that this function should be activated with a probability p, but I guess that the Keras implementation assumes that 50% of the images are to be flipped.

The current implementations of the PreprocessingLayers used for augmentation have the following structure:

If training==True apply function. Else pass input forward.

def call(self,inputs, training=None, **kwargs):
      if training is None:
          training = K.learning_phase()
      def function():
          return do_something(input)

      # comparable to K.switch(condition,true_function,else_function)
      output = control_flow_util.smart_cond(training,function,lambda: inputs)
      return output

I could implement the random apply behavior by changing

    if training is None:
          training = K.learning_phase()

to something like

    if training is None:
          training = K.learning_phase()
          # most likely 'K.switch' or 'tf.cond' must be used instead of 'if' (but 'if' is more readable) 
          if training:
              training = uniform(0,1)<self.p

But I think this should be part of every RandomFunction layer. So I am asking here, does a parameter p already exist for the preprocessing layers? Or should I open an issue on GitHub?

Innat
  • 16,113
  • 6
  • 53
  • 101
mss
  • 348
  • 2
  • 12

2 Answers2

2

Currently, there is no such probability parameter to control the occurrence of the keras built-in augmentation layer. What we can do is create a custom layer to wrap the built-in augmentation layers and make it a random choice in action.

class RandomChance(layers.Layer):
    def __init__(self, layer, probability, **kwargs):
        super(RandomChance, self).__init__(**kwargs)
        self.layer = layer
        self.probability = probability

    def call(self, inputs, training=True):
        apply_layer = tf.random.uniform([]) < self.probability
        outputs = tf.cond(
            pred=tf.logical_and(apply_layer, training),
            true_fn=lambda: self.layer(inputs),
            false_fn=lambda: inputs,
        )
        return outputs

    def get_config(self):
        config = super().get_config()
        config.update(
            {
                "layer": tf.keras.layers.serialize(self.layer),
                "probability": self.probability,
            }
        )
        return config

Now, you can do

random_aug = keras.Sequential(
    [
        RandomChance(layers.RandomFlip(), 0.75),
        RandomChance(layers.RandomBrightness(factor=0.2), 0.5),
    ]
)

FYI, you may not need to do the above approach in the future. From 2.9, you can use KerasCV, which offers many augmentations and each contains a rate parameter to control the occurrence of the augmentation layer. An interesting note, most of the augmentations are batch vectorized and should run faster than existing augmentation libraries.

Innat
  • 16,113
  • 6
  • 53
  • 101
2

Another note about KerasCV -- it also offers keras_cv.layers.MaybeApply, which does exactly what @Innat's answer suggests.

  • 1
    This looks like a good way to do it and it answers the question. Do you have time to add a small example how to use this layer in a data augmentation pipeline? IMO a link is sufficient, but the SO community seems to prefer complete answers for the case that the link breaks. – mss Mar 29 '23 at 13:02