Exemple #1
0
    def __init__(
        self,
        source_shape,
        output_shape,
        constraints=None,
        name="affine_grid_warper",
    ):
        """Constructs an AffineGridWarper.

        `source_shape` and `output_shape` are used to define the size of the source
        and output signal domains, as opposed to the shape of the respective
        Tensors. For example, for an image of size `width=W` and `height=H`,
        `{source,output}_shape=[H, W]`; for a volume of size `width=W`, `height=H`
        and `depth=D`, `{source,output}_shape=[H, W, D]`.

        Args:
          source_shape: Iterable of integers determining the size of the source
            signal domain.
          output_shape: Iterable of integers determining the size of the destination
            resampled signal domain.
          constraints: Either a double list of shape `[N, N+1]` defining constraints
            on the entries of a matrix defining an affine transformation in N
            dimensions, or an `AffineWarpConstraints` object. If the double list is
            passed, a numeric value bakes in a constraint on the corresponding
            entry in the tranformation matrix, whereas `None` implies that the
            corresponding entry will be specified at run time.
          name: Name of module.

        Raises:
          Error: If constraints fully define the affine transformation; or if
            input grid shape and contraints have different dimensionality.
          TypeError: If output_shape and source_shape are not both iterable.
        """
        self._source_shape = tuple(source_shape)
        self._output_shape = tuple(output_shape)
        num_dim = len(source_shape)
        if isinstance(constraints, AffineWarpConstraints):
            self._constraints = constraints
        elif constraints is None:
            self._constraints = AffineWarpConstraints.no_constraints(num_dim)
        else:
            self._constraints = AffineWarpConstraints(constraints=constraints)

        if self._constraints.num_free_params == 0:
            raise base.Error("Transformation is fully constrained.")

        if self._constraints.num_dim != num_dim:
            raise base.Error("Incompatible set of constraints provided: "
                             "input grid shape and constraints have different "
                             "dimensionality.")

        super(AffineGridWarper, self).__init__(
            source_shape=source_shape,
            output_shape=output_shape,
            num_coeff=6,
            name=name,
            constraints=self._constraints,
        )
Exemple #2
0
    def gamma(self):
        self._ensure_is_connected()

        if self._gamma is None:
            raise base.Error(
                "Batch normalization doesn't have a scale, so no gamma")
        else:
            return tf.reshape(self._gamma, self._expanded_mean_shape)
Exemple #3
0
    def beta(self):
        self._ensure_is_connected()

        if self._beta is None:
            raise base.Error(
                "Batch normalization doesn't have an offset, so no beta")
        else:
            return tf.reshape(self._beta, self._expanded_mean_shape)
  def gamma(self):
    self._ensure_is_connected()

    if self._gamma is None:
      raise base.Error(
          "Batch normalization doesn't have a scale, so no gamma")
    else:
      return self._gamma
  def beta(self):
    self._ensure_is_connected()

    if self._beta is None:
      raise base.Error(
          "Batch normalization doesn't have an offset, so no beta")
    else:
      return self._beta
Exemple #6
0
  def __init__(self, source_shape, output_shape, num_coeff, name, **kwargs):
    """Constructs a GridWarper module and initializes the source grid params.

    `source_shape` and `output_shape` are used to define the size of the source
    and output signal domains, as opposed to the shape of the respective
    Tensors. For example, for an image of size `width=W` and `height=H`,
    `{source,output}_shape=[H, W]`; for a volume of size `width=W`, `height=H`
    and `depth=D`, `{source,output}_shape=[H, W, D]`.

    Args:
      source_shape: Iterable of integers determining the size of the source
        signal domain.
      output_shape: Iterable of integers determining the size of the destination
        resampled signal domain.
      num_coeff: Number of coefficients parametrizing the grid warp.
        For example, a 2D affine transformation will be defined by the 6
        parameters populating the corresponding 2x3 affine matrix.
      name: Name of Module.
      **kwargs: Extra kwargs to be forwarded to the `create_features` function,
        instantiating the source grid parameters.

    Raises:
      Error: If `len(output_shape) > len(source_shape)`.
      TypeError: If `output_shape` and `source_shape` are not both iterable.
    """
    super(GridWarper, self).__init__(name=name)

    self._source_shape = tuple(source_shape)
    self._output_shape = tuple(output_shape)
    if len(self._output_shape) > len(self._source_shape):
      raise base.Error('Output domain dimensionality ({}) must be equal or '
                       'smaller than source domain dimensionality ({})'
                       .format(len(self._output_shape),
                               len(self._source_shape)))

    self._num_coeff = num_coeff
    self._psi = self._create_features(**kwargs)
Exemple #7
0
  def _build(self, inputs):
    """Assembles the module network and adds it to the graph.

    The internal computation graph is assembled according to the set of
    constraints provided at construction time.

    Args:
      inputs: Tensor containing a batch of transformation parameters.

    Returns:
      A batch of warped grids.

    Raises:
      Error: If the input tensor size is not consistent with the constraints
        passed at construction time.
    """
    input_shape = tf.shape(inputs)
    input_dtype = inputs.dtype.as_numpy_dtype
    batch_size = tf.expand_dims(input_shape[0], 0)
    number_of_params = inputs.get_shape()[1]
    if number_of_params != self._constraints.num_free_params:
      raise base.Error('Input size is not consistent with constraint '
                       'definition: {} parameters expected, {} provided.'
                       .format(self._constraints.num_free_params,
                               number_of_params))
    num_output_dimensions = len(self._psi) // 3
    def get_input_slice(start, size):
      """Extracts a subset of columns from the input 2D Tensor."""
      return basic.SliceByDim([1], [start], [size])(inputs)

    warped_grid = []
    var_index_offset = 0
    number_of_points = np.prod(self._output_shape)
    for i in xrange(num_output_dimensions):
      if self._psi[i] is not None:
        # The i-th output dimension is not fully specified by the constraints,
        # the graph is setup to perform matrix multiplication in batch mode.
        grid_coord = self._psi[i].astype(input_dtype)

        num_active_vars = self._psi[i].shape[0]
        active_vars = get_input_slice(var_index_offset, num_active_vars)
        warped_coord = tf.matmul(active_vars, grid_coord)
        warped_coord = tf.expand_dims(warped_coord, 1)
        var_index_offset += num_active_vars
        offset = self._psi[num_output_dimensions + i]
        if offset is not None:
          offset = offset.astype(input_dtype)
          # Some entries in the i-th row of the affine matrix were constrained
          # and the corresponding matrix multiplications have been precomputed.
          tiling_params = tf.concat(
              [
                  batch_size, tf.constant(
                      1, shape=(1,)), tf.ones_like(offset.shape)
              ],
              0)
          offset = offset.reshape((1, 1) + offset.shape)
          warped_coord += tf.tile(offset, tiling_params)

      else:
        # The i-th output dimension is fully specified by the constraints, and
        # the corresponding matrix multiplications have been precomputed.
        warped_coord = self._psi[num_output_dimensions + i].astype(input_dtype)
        tiling_params = tf.concat(
            [
                batch_size, tf.constant(
                    1, shape=(1,)), tf.ones_like(warped_coord.shape)
            ],
            0)
        warped_coord = warped_coord.reshape((1, 1) + warped_coord.shape)
        warped_coord = tf.tile(warped_coord, tiling_params)

      warped_coord += self._psi[i + 2 * num_output_dimensions]
      # Need to help TF figuring out shape inference since tiling information
      # is held in Tensors which are not known until run time.
      warped_coord.set_shape([None, 1, number_of_points])
      warped_grid.append(warped_coord)

    # Reshape all the warped coordinates tensors to match the specified output
    # shape and concatenate  into a single matrix.
    grid_shape = self._output_shape + (1,)
    warped_grid = [basic.BatchReshape(grid_shape)(grid) for grid in warped_grid]
    return tf.concat(warped_grid, len(grid_shape))
Exemple #8
0
    def __init__(self,
                 mode=HALF,
                 use_batch_norm=False,
                 batch_norm_config=None,
                 initializers=None,
                 partitioners=None,
                 regularizers=None,
                 name="alex_net"):
        """Constructs AlexNet.

    Args:
      mode: Construction mode of network: `AlexNet.FULL`, `AlexNet.HALF` or
          `AlexNet.MINI`.
      use_batch_norm: Whether to use batch normalization between the output of
          a layer and the activation function.
      batch_norm_config: Optional mapping of additional configuration for the
          `snt.BatchNorm` modules.
      initializers: Optional dict containing ops to initialize the filters (with
          key 'w') or biases (with key 'b'). The default initializers are
          truncated normal initializers, which are commonly used when the inputs
          are zero centered (see https://arxiv.org/pdf/1502.03167v3.pdf).
      partitioners: Optional dict containing partitioners for the filters
        (with key 'w') and the biases (with key 'b'). As a default, no
        partitioners are used.
      regularizers: Optional dict containing regularizers for the filters
        (with key 'w') and the biases (with key 'b'). As a default, no
        regularizers are used. A regularizer should be a function that takes
        a single `Tensor` as an input and returns a scalar `Tensor` output, e.g.
        the L1 and L2 regularizers in `tf.contrib.layers`.
      name: Name of the module.

    Raises:
      base.Error: If the given `mode` is not one of `AlexNet.FULL`,
          `AlexNet.HALF` or `AlexNet.MINI`.
      TypeError: If `batch_norm_config` is not a mapping, e.g. `dict`.
      KeyError: If `initializers` contains any keys other than 'w' or 'b'.
      KeyError: If `partitioners` contains any keys other than 'w' or 'b'.
      KeyError: If `regularizers` contains any keys other than 'w' or 'b'.
    """
        super(AlexNet, self).__init__(name=name)

        self._mode = mode
        self._use_batch_norm = use_batch_norm

        if batch_norm_config is not None:
            if not isinstance(batch_norm_config, collections.Mapping):
                raise TypeError(
                    "`batch_norm_config` must be a mapping, e.g. `dict`.")
            self._batch_norm_config = batch_norm_config
        else:
            self._batch_norm_config = {}

        if self._mode == self.HALF:
            # Half of AlexNet, i.e. originally ran on one GPU
            self._conv_layers = [
                (48, (11, 4), (3, 2)),
                (128, (5, 1), (3, 2)),
                (192, (3, 1), None),
                (192, (3, 1), None),
                (128, (3, 1), (3, 2)),
            ]

            self._fc_layers = [2048, 2048]
        elif self._mode == self.FULL:
            # The full AlexNet, i.e. originally ran on two GPUs
            self._conv_layers = [
                (96, (11, 4), (3, 2)),
                (256, (5, 1), (3, 2)),
                (384, (3, 1), None),
                (384, (3, 1), None),
                (256, (3, 1), (3, 2)),
            ]

            self._fc_layers = [4096, 4096]
        elif self._mode == self.MINI:
            # A cut down version of the half net for testing with Cifar10
            self._conv_layers = [
                (48, (3, 1), (3, 1)),
                (128, (3, 1), (3, 1)),
                (192, (3, 1), None),
                (192, (3, 1), None),
                (128, (3, 1), (3, 1)),
            ]

            self._fc_layers = [1024, 1024]
        else:
            raise base.Error("AlexNet construction mode '{}' not recognised, "
                             "must be one of: '{}', '{}', '{}'".format(
                                 mode, self.HALF, self.FULL, self.MINI))

        self._min_size = self._calc_min_size(self._conv_layers)
        self._conv_modules = []
        self._linear_modules = []

        self.possible_keys = {"w", "b"}
        self._initializers = util.check_initializers(initializers,
                                                     self.possible_keys)
        self._partitioners = util.check_partitioners(partitioners,
                                                     self.possible_keys)
        self._regularizers = util.check_regularizers(regularizers,
                                                     self.possible_keys)
Exemple #9
0
    def __init__(self,
                 mode,
                 use_batch_norm=False,
                 batch_norm_config=None,
                 initializers=None,
                 partitioners=None,
                 regularizers=None,
                 bn_on_fc_layers=True,
                 custom_getter=None,
                 name="alex_net"):
        """Constructs AlexNet.

    Args:
      mode: Construction mode of network: `AlexNet.FULL` or `AlexNet.MINI`.
      use_batch_norm: Whether to use batch normalization between the output of
          a layer and the activation function.
      batch_norm_config: Optional mapping of additional configuration for the
          `snt.BatchNorm` modules.
      initializers: Optional dict containing ops to initialize the filters (with
          key 'w') or biases (with key 'b'). The default initializers are
          truncated normal initializers, which are commonly used when the inputs
          are zero centered (see https://arxiv.org/pdf/1502.03167v3.pdf).
      partitioners: Optional dict containing partitioners for the filters
        (with key 'w') and the biases (with key 'b'). As a default, no
        partitioners are used.
      regularizers: Optional dict containing regularizers for the filters
        (with key 'w') and the biases (with key 'b'). As a default, no
        regularizers are used. A regularizer should be a function that takes
        a single `Tensor` as an input and returns a scalar `Tensor` output, e.g.
        the L1 and L2 regularizers in `tf.contrib.layers`.
      bn_on_fc_layers: If `use_batch_norm` is True, add batch normalization to
        the fully-connected layers. This is deprecated.
      custom_getter: Callable or dictionary of callables to use as
        custom getters inside the module. If a dictionary, the keys
        correspond to regexes to match variable names. See the `tf.get_variable`
        documentation for information about the custom_getter API.
      name: Name of the module.

    Raises:
      base.Error: If the given `mode` is not one of `AlexNet.FULL`,
        or `AlexNet.MINI`.
      KeyError: If `initializers`, `partitioners` or `regularizers` contains any
        keys other than 'w' or 'b'.
    """
        super(AlexNet, self).__init__(custom_getter=custom_getter, name=name)

        self._mode = mode
        self._use_batch_norm = use_batch_norm
        self._bn_on_fc_layers = bn_on_fc_layers

        if self._bn_on_fc_layers:
            tf.logging.warn(
                "Using BatchNorm on the fully connected layers in "
                "AlexNet is not recommended. 'bn_on_fc_layers' is a "
                "deprecated option and will likely be removed.")

        self._batch_norm_config = batch_norm_config or {}

        if self._mode == self.FULL:
            # The full AlexNet, i.e. originally ran on two GPUs
            self._conv_layers = [
                (96, (11, 4), (3, 2)),
                (256, (5, 1), (3, 2)),
                (384, (3, 1), None),
                (384, (3, 1), None),
                (256, (3, 1), (3, 2)),
            ]

            self._fc_layers = [4096, 4096]
        elif self._mode == self.MINI:
            # A cut down version of the half net for testing with Cifar10
            self._conv_layers = [
                (48, (3, 1), (3, 1)),
                (128, (3, 1), (3, 1)),
                (192, (3, 1), None),
                (192, (3, 1), None),
                (128, (3, 1), (3, 1)),
            ]

            self._fc_layers = [1024, 1024]
        else:
            raise base.Error("AlexNet construction mode '{}' not recognised, "
                             "must be one of: '{}', '{}'".format(
                                 mode, self.FULL, self.MINI))

        self._min_size = self._calc_min_size(self._conv_layers)
        self._conv_modules = []
        self._linear_modules = []

        self._initializers = util.check_initializers(
            initializers, self.POSSIBLE_INITIALIZER_KEYS)
        self._partitioners = util.check_partitioners(
            partitioners, self.POSSIBLE_INITIALIZER_KEYS)
        self._regularizers = util.check_regularizers(
            regularizers, self.POSSIBLE_INITIALIZER_KEYS)