예제 #1
0
    def _prepare_gradient_func(
        self, input_shape: ImageShape, input_layer: str,
        output_layers: List[str]
    ) -> Tuple[Callable, GridShape, List[GridShape]]:
        """
        Computes gradient function and additional parameters. Note
        that the receptive field parameters like stride or size, do not
        depend on input image shape. However, if the RF of original network
        is bigger than input_shape this method will fail. Hence it is
        recommended to increase the input shape.

        :param input_shape: shape of the input image. Used in @model_func.
        :param input_layer: name of the input layer.
        :param output_layers: a list of names of the target feature map layers.

        :returns
            gradient_function: a function which returns gradient w.r.t. to
                the input image
            input_shape: a shape of the input image tensor
            output_shape: a shapes of the output feature map tensors
        """
        model = self._model_func(ImageShape(*input_shape))
        if self.init_weights:
            setup_model_weights(model)

        gradient_function, input_shape, output_shapes = _define_receptive_field_func(
            model, input_layer, output_layers)

        return (
            gradient_function,
            GridShape(*input_shape),
            [GridShape(*output_shape) for output_shape in output_shapes],
        )
예제 #2
0
    def _prepare_gradient_func(
            self, input_shape: ImageShape, input_layer: str,
            output_layer: str) -> Tuple[Callable, GridShape, GridShape]:

        model = self.model_func(ImageShape(*input_shape))
        if self.init_weights:
            setup_model_weights(model)

        gradient_function, input_shape, output_shape = \
            _define_receptive_field_func(model, input_layer, output_layer)

        return gradient_function, \
               GridShape(*input_shape), \
               GridShape(*output_shape)
예제 #3
0
    def _prepare_gradient_func(
        self, input_shape: ImageShape
    ) -> Tuple[Callable, GridShape, List[GridShape]]:
        """
        Computes gradient function and additional parameters. Note
        that the receptive field parameters like stride or size, do not
        depend on input image shape. However, if the RF of original network
        is bigger than input_shape this method will fail. Hence it is
        recommended to increase the input shape.

        :param input_shape: shape of the input image, which is feed to the
            Pytorch module.

        :returns
            gradient_function: a function which returns gradient w.r.t. to
                the input image.
            input_shape: a shape of the input image tensor.
            output_shapes: a list shapes of the output feature map tensors.
        """
        input_shape = ImageShape(*input_shape)
        input_shape = GridShape(
            n=1,
            c=input_shape.c,
            h=input_shape.h,
            w=input_shape.w,
        )

        gradient_function, input_shape, output_shapes = \
            _define_receptive_field_func(self._model_func, input_shape)

        return gradient_function, input_shape, output_shapes
예제 #4
0
    def _get_gradient_from_grid_point(self,
                                      gradient_function: Callable,
                                      input_shape: GridShape,
                                      output_shape: GridShape,
                                      point: GridPoint,
                                      intensity: float = 1.0) -> np.ndarray:

        output_shape = output_shape._replace(n=1)
        input_shape = input_shape._replace(n=1)

        output_feature_map = np.zeros(shape=output_shape)
        output_feature_map[:, point.x, point.y, 0] = intensity

        receptive_field_grad = gradient_function(
            [output_feature_map,
             np.zeros(shape=input_shape), 0])[0]

        return receptive_field_grad
예제 #5
0
    def _prepare_gradient_func(
            self,
            input_shape: ImageShape,
            input_layer: str,
            output_layer: str
    ) -> Tuple[Callable, GridShape, GridShape]:

        # this function will create default graph
        _ = self.model_func(ImageShape(*input_shape))

        default_graph = tf.get_default_graph()

        # get graph tensors by names
        input_tensor = default_graph \
            .get_operation_by_name(input_layer).outputs[0]

        output_tensor = default_graph \
            .get_operation_by_name(output_layer).outputs[0]

        # get their shapes
        output_shape = _get_tensor_shape(output_tensor)
        input_shape = _get_tensor_shape(input_tensor)

        # define loss function
        output_shape = (1, output_shape[1], output_shape[2], 1)

        receptive_field_mask = tf.placeholder(
            tf.float32, shape=output_shape, name='grid'
        )

        x = tf.reduce_mean(output_tensor, -1, keep_dims=True)
        fake_loss = x * receptive_field_mask
        fake_loss = tf.reduce_mean(fake_loss)
        grads = tf.gradients(fake_loss, input_tensor)
        # here we use Keras API to define gradient function which is simpler
        # than native tf
        gradient_function = keras.backend.function(
            inputs=[receptive_field_mask, input_tensor, keras.backend.learning_phase()],
            outputs=grads
        )

        return gradient_function, \
            GridShape(*input_shape), \
            GridShape(*output_shape)
예제 #6
0
def _define_receptive_field_func(model_fn: Callable[[], nn.Module],
                                 input_shape: GridShape):
    shape = [input_shape.n, input_shape.c, input_shape.h, input_shape.w]
    input_image = torch.zeros(*shape)
    model = model_fn()
    _ = model(input_image)

    feature_maps = model.__dict__.get("feature_maps", None)
    if feature_maps is None:
        raise ValueError("Field module.feature_maps is not defined. "
                         "Cannot compute receptive fields.")

    if type(feature_maps) != list:
        raise ValueError("Field module.feature_maps must be a list. "
                         "Cannot compute receptive fields.")

    # compute feature maps output shapes
    output_shapes = []
    for feature_map in feature_maps:
        output_shape = feature_map.size()
        output_shape = GridShape(n=output_shape[0],
                                 c=output_shape[1],
                                 h=output_shape[2],
                                 w=output_shape[3])
        output_shapes.append(output_shape)

    _logger.info(f"Feature maps shape: {output_shapes}")
    _logger.info(f"Input shape       : {input_shape}")

    def gradient_function(
        receptive_field_masks: List[torch.Tensor], ) -> List[np.ndarray]:

        grads = []
        for fm, rf_mask in enumerate(receptive_field_masks):
            input_tensor = torch.zeros(*shape)
            # input_tensor = torch.autograd.Variable(
            #     input_tensor, requires_grad=True
            # )
            input_tensor.requires_grad_(True)
            model.zero_grad()
            _ = model(input_tensor)

            fm = torch.mean(model.feature_maps[fm], 1, keepdim=True)
            fake_loss = fm * rf_mask
            fake_loss = torch.mean(fake_loss)
            fake_loss.backward()
            grads.append(input_tensor.grad.detach().numpy())

        return grads

    return gradient_function, input_shape, output_shapes
예제 #7
0
    def _prepare_gradient_func(
        self, input_shape: ImageShape, input_tensor: str, output_tensors: List[str]
    ) -> Tuple[Callable, GridShape, List[GridShape]]:
        """
        Computes gradient function and additional parameters. Note
        that the receptive field parameters like stride or size, do not
        depend on input image shape. However, if the RF of original network
        is bigger than input_shape this method will fail. Hence it is
        recommended to increase the input shape.

        :param input_shape: shape of the input image. Used in @model_func.
        :param input_tensor: name of the input image tensor.
        :param output_tensors: a list of names of the target
            feature map tensors.

        :returns
            gradient_function: a function which returns gradient w.r.t. to
                the input image.
            input_shape: a shape of the input image tensor.
            output_shape: a list shapes of the output feature map tensors.
        """

        if self._session is not None:
            tf.reset_default_graph()
            self._session.close()

        with tf.Graph().as_default() as graph:
            with tf.variable_scope("", reuse=tf.AUTO_REUSE):

                # this function will create default graph
                _ = self._model_func(ImageShape(*input_shape))

                # default_graph = tf.get_default_graph()
                # get graph tensors by names
                input_tensor = graph.get_operation_by_name(input_tensor).outputs[0]
                input_shape = _get_tensor_shape(input_tensor)

                grads = []
                receptive_field_masks = []
                output_shapes = []

                for output_tensor in output_tensors:
                    output_tensor = graph.get_operation_by_name(output_tensor).outputs[0]

                    # shapes
                    output_shape = _get_tensor_shape(output_tensor)
                    output_shape = (1, output_shape[1], output_shape[2], 1)
                    output_shapes.append(output_shape)

                    # define loss function
                    receptive_field_mask = tf.placeholder(
                        tf.float32, shape=output_shape, name="grid"
                    )
                    grad = _define_fm_gradient(
                        input_tensor, output_tensor, receptive_field_mask
                    )
                    grads.append(grad)
                    receptive_field_masks.append(receptive_field_mask)

                _logger.info(f"Feature maps shape: {output_shapes}")
                _logger.info(f"Input shape       : {input_shape}")

            self._session = tf.Session(graph=graph)
            self._session.run(tf.global_variables_initializer())

            def gradient_fn(fm_masks, input_image):
                fetch_dict = {
                    mask_t: mask_np
                    for mask_t, mask_np in zip(receptive_field_masks, fm_masks)
                }
                fetch_dict[input_tensor] = input_image
                return self._session.run(grads, feed_dict=fetch_dict)

        return (
            gradient_fn,
            GridShape(*input_shape),
            [GridShape(*output_shape) for output_shape in output_shapes],
        )