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, )
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)
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
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)
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))
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)
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)