theanets/graph.py
def add_layer(self, layer=None, **kwargs):
        '''Add a :ref:`layer <layers>` to our network graph.

        Parameters
        ----------
        layer : int, tuple, dict, or :class:`Layer <theanets.layers.base.Layer>`
            A value specifying the layer to add. For more information, please
            see :ref:`guide-creating-specifying-layers`.
        '''
        # if the given layer is a Layer instance, just add it and move on.
        if isinstance(layer, layers.Layer):
            self.layers.append(layer)
            return

        form = kwargs.pop('form', 'ff' if self.layers else 'input').lower()

        if isinstance(layer, util.basestring):
            if not layers.Layer.is_registered(layer):
                raise util.ConfigurationError('unknown layer type: {}'.format(layer))
            form = layer
            layer = None

        # if layer is a tuple/list of integers, assume it's a shape.
        if isinstance(layer, (tuple, list)) and all(isinstance(x, int) for x in layer):
            kwargs['shape'] = tuple(layer)
            layer = None

        # if layer is some other tuple/list, assume it's a list of:
        # - the name of a layers.Layer class (str)
        # - the name of an activation function (str)
        # - the number of units in the layer (int)
        if isinstance(layer, (tuple, list)):
            for el in layer:
                if isinstance(el, util.basestring) and layers.Layer.is_registered(el):
                    form = el
                elif isinstance(el, util.basestring):
                    kwargs['activation'] = el
                elif isinstance(el, int):
                    if 'size' in kwargs:
                        raise util.ConfigurationError(
                            'duplicate layer sizes! {}'.format(kwargs))
                    kwargs['size'] = el
            layer = None

        # if layer is a dictionary, try to extract a form for the layer, and
        # override our default keyword arguments with the rest.
        if isinstance(layer, dict):
            for key, value in layer.items():
                if key == 'form':
                    form = value.lower()
                else:
                    kwargs[key] = value
            layer = None

        # if neither shape nor size have been specified yet, check that the
        # "layer" param is an int and use it for "size".
        if 'shape' not in kwargs and 'size' not in kwargs and isinstance(layer, int):
            kwargs['size'] = layer

        # if it hasn't been provided in some other way yet, set input
        # dimensionality based on the model.
        if form == 'input' and 'shape' not in kwargs:
            kwargs.setdefault('ndim', self.INPUT_NDIM)

        # set some default layer parameters.
        if form != 'input':
            kwargs.setdefault('inputs', self.layers[-1].output_name)
            kwargs.setdefault('rng', self._rng)

        if form.lower() == 'tied' and 'partner' not in kwargs:
            # we look backward through our list of layers for a partner.
            # any "tied" layer that we find increases a counter by one,
            # and any "untied" layer decreases the counter by one. our
            # partner is the first layer we find with count zero.
            #
            # this is intended to handle the hopefully common case of a
            # (possibly deep) tied-weights autoencoder.
            tied = 1
            partner = None
            for l in self.layers[::-1]:
                tied += 1 if isinstance(l, layers.Tied) else -1
                if tied == 0:
                    partner = l.name
                    break
            else:
                raise util.ConfigurationError(
                    'cannot find partner for "{}"'.format(kwargs))
            kwargs['partner'] = partner

        layer = layers.Layer.build(form, **kwargs)

        # check that graph inputs have unique names.
        if isinstance(layer, layers.Input):
            if any(layer.name == i.name for i in self.inputs):
                raise util.ConfigurationError(
                    '"{}": duplicate input name!'.format(layer.name))

        self.layers.append(layer)
def add_layer(self, layer=None, **kwargs):
        '''Add a :ref:`layer <layers>` to our network graph.

        Parameters
        ----------
        layer : int, tuple, dict, or :class:`Layer <theanets.layers.base.Layer>`
            A value specifying the layer to add. For more information, please
            see :ref:`guide-creating-specifying-layers`.
        '''
        # if the given layer is a Layer instance, just add it and move on.
        if isinstance(layer, layers.Layer):
            self.layers.append(layer)
            return

        form = kwargs.pop('form', 'ff' if self.layers else 'input').lower()

        if isinstance(layer, util.basestring):
            if not layers.Layer.is_registered(layer):
                raise util.ConfigurationError('unknown layer type: {}'.format(layer))
            form = layer
            layer = None

        # if layer is a tuple/list of integers, assume it's a shape.
        if isinstance(layer, (tuple, list)) and all(isinstance(x, int) for x in layer):
            kwargs['shape'] = tuple(layer)
            layer = None

        # if layer is some other tuple/list, assume it's a list of:
        # - the name of a layers.Layer class (str)
        # - the name of an activation function (str)
        # - the number of units in the layer (int)
        if isinstance(layer, (tuple, list)):
            for el in layer:
                if isinstance(el, util.basestring) and layers.Layer.is_registered(el):
                    form = el
                elif isinstance(el, util.basestring):
                    kwargs['activation'] = el
                elif isinstance(el, int):
                    if 'size' in kwargs:
                        raise util.ConfigurationError(
                            'duplicate layer sizes! {}'.format(kwargs))
                    kwargs['size'] = el
            layer = None

        # if layer is a dictionary, try to extract a form for the layer, and
        # override our default keyword arguments with the rest.
        if isinstance(layer, dict):
            for key, value in layer.items():
                if key == 'form':
                    form = value.lower()
                else:
                    kwargs[key] = value
            layer = None

        # if neither shape nor size have been specified yet, check that the
        # "layer" param is an int and use it for "size".
        if 'shape' not in kwargs and 'size' not in kwargs and isinstance(layer, int):
            kwargs['size'] = layer

        # if it hasn't been provided in some other way yet, set input
        # dimensionality based on the model.
        if form == 'input' and 'shape' not in kwargs:
            kwargs.setdefault('ndim', self.INPUT_NDIM)

        # set some default layer parameters.
        if form != 'input':
            kwargs.setdefault('inputs', self.layers[-1].output_name)
            kwargs.setdefault('rng', self._rng)

        if form.lower() == 'tied' and 'partner' not in kwargs:
            # we look backward through our list of layers for a partner.
            # any "tied" layer that we find increases a counter by one,
            # and any "untied" layer decreases the counter by one. our
            # partner is the first layer we find with count zero.
            #
            # this is intended to handle the hopefully common case of a
            # (possibly deep) tied-weights autoencoder.
            tied = 1
            partner = None
            for l in self.layers[::-1]:
                tied += 1 if isinstance(l, layers.Tied) else -1
                if tied == 0:
                    partner = l.name
                    break
            else:
                raise util.ConfigurationError(
                    'cannot find partner for "{}"'.format(kwargs))
            kwargs['partner'] = partner

        layer = layers.Layer.build(form, **kwargs)

        # check that graph inputs have unique names.
        if isinstance(layer, layers.Input):
            if any(layer.name == i.name for i in self.inputs):
                raise util.ConfigurationError(
                    '"{}": duplicate input name!'.format(layer.name))

        self.layers.append(layer)
Add a :ref:`layer <layers>` to our network graph.

        Parameters
        ----------
        layer : int, tuple, dict, or :class:`Layer <theanets.layers.base.Layer>`
            A value specifying the layer to add. For more information, please
            see :ref:`guide-creating-specifying-layers`.