2

I was trying to create custom augmentation layer in Keras. the idea is to make faster augmentations (instead of running same function BATCH_SIZE times, run it once over the whole batch).

I got stuck in the function:

__call__(inputs, training=False, **kwargs)

on training the function gets inputs of shape (None, 128, 128, 3) where the last 3 numbers indicate the image's shapes. for my undestanding the first None should be the Batch size, which is not deterministic (for some unknown reason).

my problem is right here. in my function I use np.random.ranf(inputs.shape) which is not happy with None as shape indicator and throws the error:

TypeError: 'NoneType' object cannot be interpreted as an integer

on the other hand I can't figure out how to get the batch size for the calculations. The code for the custom Augmentation layer is here below. any help would be appreciated!

class RandomHSV(Layer):
    """Adding Random Noise to HSV image. output is RGB
  Input shape:
    Arbitrary.
  Output shape:
    Same as input.
  Arguments:
    hsv_max_amp: list or tuple of the maximum amplitudes of the noise in range of [0, 1]
    name: A string, the name of the layer.
  """

    def __init__(self, hsv_max_amp=(0, 0, 0), name=None, **kwargs):
        super(RandomHSV, self).__init__(name=name, **kwargs)
        self.hsv_max_amp = np.array(list(hsv_max_amp), dtype='float32')

    def build(self, input_shape):
        self.batch_size = input_shape[0]
        super(RandomHSV, self).build(input_shape)  # Be sure to call this at the end

    def call(self, inputs, training=True, **kwargs):
        def hsv_noise():
            hsv = tf.image.rgb_to_hsv(inputs)
            # the random noise is a random matrix in shape (batch_size, img_w, img_h, depth)
            # after creating the random matrix, multiply it (element wise) by the self.hsv_max_amp.
            # that gets multiplied by random enabler (np.random.randint(0, 2, 3) -> 3 items, 0 or 1)
            # then removing an offset.
            random_noise = (np.random.ranf(inputs.shape) * (
                    np.random.random(1) * self.hsv_max_amp * np.random.randint(0, 2, 3)) - self.hsv_max_amp / 2) * 2
            # those lines will cut any number which goes above 1 or goes below 0 (round it to 1 or 0 respectively).
            hsv = tf.minimum(1., tf.maximum(0., hsv + random_noise))
            batch = tf.image.hsv_to_rgb(hsv)
            batch.set_shape(inputs.shape)
            return batch

        # applying hsv_noise if Training. if Testing then just passing batch forward unchanged
        return control_flow_util.smart_cond(pred=training, true_fn=hsv_noise, false_fn=lambda: inputs)

EDIT: I know that I can specify in the Input() layer the batch size, It does fix the problem, but is there any way to do it without specifying the shape in the Input layer? So it could be more generic.

Jhon Margalit
  • 451
  • 4
  • 12
  • 1
    Did you try using a random generator from tensorflow instead of numpy? – Jérémie Gince Aug 06 '21 at 21:50
  • @JérémieGince Thanks for the comment, I have Tried it now, It doesn't work, the Error I get from the line: `r = tf.random.Generator.from_seed(seed=1) r.normal(shape=(None, 2, 3))` is: `ValueError: Attempt to convert a value (None) with an unsupported type () to a Tensor.` – Jhon Margalit Aug 07 '21 at 09:11

0 Answers0