Esempio n. 1
0
def test_keras_model_preprocess():
    num_classes = 1000
    bounds = (0, 255)
    channels = num_classes

    with warnings.catch_warnings():
        warnings.filterwarnings("ignore", category=DeprecationWarning)
        inputs = Input(shape=(5, 5, channels))
        logits = GlobalAveragePooling2D(
            data_format='channels_last')(inputs)

        preprocessing = (np.arange(num_classes)[None, None],
                         np.random.uniform(size=(5, 5, channels)) + 1)

        model1 = KerasModel(
            Model(inputs=inputs, outputs=logits),
            bounds=bounds,
            predicts='logits')

        model2 = KerasModel(
            Model(inputs=inputs, outputs=logits),
            bounds=bounds,
            predicts='logits',
            preprocessing=preprocessing)

        model3 = KerasModel(
            Model(inputs=inputs, outputs=logits),
            bounds=bounds,
            predicts='logits')

        preprocessing = (0, np.random.uniform(size=(5, 5, channels)) + 1)

        model4 = KerasModel(
            Model(inputs=inputs, outputs=logits),
            bounds=bounds,
            predicts='logits',
            preprocessing=preprocessing)

    np.random.seed(22)
    test_images = np.random.rand(2, 5, 5, channels).astype(np.float32)
    test_images_copy = test_images.copy()

    p1 = model1.batch_predictions(test_images)
    p2 = model2.batch_predictions(test_images)

    # make sure the images have not been changed by
    # the in-place preprocessing
    assert np.all(test_images == test_images_copy)

    p3 = model3.batch_predictions(test_images)

    assert p1.shape == p2.shape == p3.shape == (2, num_classes)

    np.testing.assert_array_almost_equal(
        p1 - p1.max(),
        p3 - p3.max(),
        decimal=5)

    model4.batch_predictions(test_images)
Esempio n. 2
0
def test_keras_model_probs(num_classes):
    bounds = (0, 255)
    channels = num_classes

    with warnings.catch_warnings():
        warnings.filterwarnings("ignore", category=DeprecationWarning)
        inputs = Input(shape=(5, 5, channels))
        logits = GlobalAveragePooling2D(
            data_format='channels_last')(inputs)
        probs = Activation(softmax)(logits)

        model1 = KerasModel(
            Model(inputs=inputs, outputs=logits),
            bounds=bounds,
            predicts='logits')

        model2 = KerasModel(
            Model(inputs=inputs, outputs=probs),
            bounds=bounds,
            predicts='probabilities')

        model3 = KerasModel(
            Model(inputs=inputs, outputs=probs),
            bounds=bounds,
            predicts='probs')

    np.random.seed(22)
    test_images = np.random.rand(2, 5, 5, channels).astype(np.float32)

    p1 = model1.batch_predictions(test_images)
    p2 = model2.batch_predictions(test_images)
    p3 = model3.batch_predictions(test_images)

    assert p1.shape == p2.shape == p3.shape == (2, num_classes)

    np.testing.assert_array_almost_equal(
        p1 - p1.max(),
        p2 - p2.max(),
        decimal=1)

    np.testing.assert_array_almost_equal(
        p2 - p2.max(),
        p3 - p3.max(),
        decimal=5)
Esempio n. 3
0
def test_keras_model_preprocess():
    num_classes = 1000
    bounds = (0, 255)
    channels = num_classes

    inputs = Input(shape=(5, 5, channels))
    logits = GlobalAveragePooling2D(data_format='channels_last')(inputs)

    def preprocess_fn(x):
        # modify x in-place
        x /= 2
        return x

    model1 = KerasModel(Model(inputs=inputs, outputs=logits),
                        bounds=bounds,
                        predicts='logits')

    model2 = KerasModel(Model(inputs=inputs, outputs=logits),
                        bounds=bounds,
                        predicts='logits',
                        preprocess_fn=preprocess_fn)

    model3 = KerasModel(Model(inputs=inputs, outputs=logits),
                        bounds=bounds,
                        predicts='logits')

    np.random.seed(22)
    test_images = np.random.rand(2, 5, 5, channels).astype(np.float32)
    test_images_copy = test_images.copy()

    p1 = model1.batch_predictions(test_images)
    p2 = model2.batch_predictions(test_images)

    # make sure the images have not been changed by
    # the in-place preprocessing
    assert np.all(test_images == test_images_copy)

    p3 = model3.batch_predictions(test_images)

    assert p1.shape == p2.shape == p3.shape == (2, num_classes)

    np.testing.assert_array_almost_equal(p1 - p1.max(),
                                         p3 - p3.max(),
                                         decimal=5)
class FoolboxKerasModelEntropy(DifferentiableModel):
    def __init__(self,
                 model,
                 bounds,
                 channel_axis=3,
                 preprocessing=(0, 1),
                 predicts='probabilities',
                 entropy_mask=True,
                 cache_grad_mask=False):
        super(FoolboxKerasModelEntropy,
              self).__init__(bounds=bounds,
                             channel_axis=channel_axis,
                             preprocessing=preprocessing)

        self.entropy_mask = entropy_mask
        self.grad_mask = None
        self.cache_grad_mask = cache_grad_mask
        self.keras_model = KerasModel(model, bounds, channel_axis,
                                      preprocessing, predicts)

    def compute_gradient_mask(self, image):
        gray = skimage.color.rgb2gray(image)
        mask = skimage.filters.rank.entropy(gray, skimage.morphology.disk(3))

        low = mask < 4.2
        high = mask >= 4.2

        mask[low] = 0.0
        mask[high] = 1.0

        self.grad_mask = np.broadcast_to(
            mask.reshape(mask.shape[0] * mask.shape[1], 1),
            (mask.shape[0] * mask.shape[1], image.shape[2])).reshape(
                image.shape)

    def __mask_gradient(self, grad, image):
        if self.entropy_mask is True:
            if self.cache_grad_mask is True:
                return grad * self.grad_mask
            else:
                mask = utils.image2mask(image)
                mask = np.broadcast_to(
                    mask.reshape(mask.shape[0] * mask.shape[1], 1),
                    (mask.shape[0] * mask.shape[1], image.shape[2])).reshape(
                        image.shape)

                return grad * mask
        else:
            return grad

    def predictions_and_gradient(self, image, label):
        """Calculates predictions for an image and the gradient of
        the cross-entropy loss w.r.t. the image.
        Parameters
        ----------
        image : `numpy.ndarray`
            Single input with shape as expected by the model
            (without the batch dimension).
        label : int
            Reference label used to calculate the gradient.
        Returns
        -------
        predictions : `numpy.ndarray`
            Vector of predictions (logits, i.e. before the softmax) with
            shape (number of classes,).
        gradient : `numpy.ndarray`
            The gradient of the cross-entropy loss w.r.t. the image. Will
            have the same shape as the image.
        See Also
        --------
        :meth:`gradient`
        """

        pred, grad = self.keras_model.predictions_and_gradient(image, label)

        return pred, self.__mask_gradient(grad, image)

    def num_classes(self):
        return self.keras_model.num_classes()

    def batch_predictions(self, images):
        return self.keras_model.batch_predictions(images)

    def backward(self, gradient, image):
        """Backpropagates the gradient of some loss w.r.t. the logits
        through the network and returns the gradient of that loss w.r.t
        to the input image.
        Parameters
        ----------
        gradient : `numpy.ndarray`
            Gradient of some loss w.r.t. the logits.
        image : `numpy.ndarray`
            Single input with shape as expected by the model
            (without the batch dimension).
        Returns
        -------
        gradient : `numpy.ndarray`
            The gradient w.r.t the image.
        See Also
        --------
        :meth:`gradient`
        """

        grad = self.keras_model.backward(gradient, image)

        return self.__mask_gradient(grad, image)