def add_layer(self, layer=None, is_output=False, **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`.
        is_output : bool, optional
            True iff this is the output layer for the graph. This influences the
            default activation function used for the layer: output layers in
            most models have a linear activation, while output layers in
            classifier networks default to a softmax activation.
        '''
        # 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 layer is a tuple, assume that it contains one or more of the following:
        # - a layers.Layer subclass to construct (type)
        # - 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:
                try:
                    if issubclass(el, layers.Layer):
                        form = el.__name__
                except __HOLE__:
                    pass
                if isinstance(el, util.basestring):
                    if layers.Layer.is_registered(el):
                        form = el
                    else:
                        kwargs['activation'] = el
                if isinstance(el, int):
                    kwargs['size'] = el

        # 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

        name = 'hid{}'.format(len(self.layers))
        if is_output:
            name = 'out'
        if form == 'input':
            name = 'in'
        kwargs.setdefault('name', name)
        kwargs.setdefault('size', layer)

        if form == 'input':
            kwargs.setdefault('ndim', self.INPUT_NDIM)
        else:
            act = self.DEFAULT_OUTPUT_ACTIVATION if is_output else 'relu'
            kwargs.setdefault('inputs', self.layers[-1].output_name)
            kwargs.setdefault('rng', self._rng)
            kwargs.setdefault('activation', act)

        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)

        if isinstance(layer, layers.Input):
            names = set(i.name for i in self.inputs)
            assert layer.name not in names, \
                '"{}": duplicate input name!'.format(layer.name)

        self.layers.append(layer)
dataset/ETHPy150Open lmjohns3/theanets/theanets/graph.py/Network.add_layer