Ejemplo n.º 1
0
    def __init__(self, layer_type, name=None, **kwargs):
        if not is_valid_layer_name(layer_type):
            raise NetworkValidationError(
                "Invalid layer_type: '{}'".format(layer_type))
        if not (name is None or is_valid_layer_name(name)):
            raise NetworkValidationError(
                "Invalid name for layer: '{}'".format(name))
        super(LayerDetails, self).__init__(name or layer_type)

        self.layer_type = layer_type
        """The type this layer should have when later being instantiated."""

        self.incoming = []
        """A list of all incoming connections, including input/output names.

        Each entry of the list has the form:
        (incoming_layer, output_name, input_name)
        and the type:
        tuple[LayerDetails, str, str]
        """

        self.outgoing = []
        """A list of all outgoing connections, including input/output names.

        Each entry of the list has the form:
        (output_name, input_name, outgoing_layer)
        and the type:
        tuple[str, str, LayerDetails]
        """

        self.layer_kwargs = kwargs
        """Dictionary of additional parameters for this layer"""

        self._traversing = False
Ejemplo n.º 2
0
    def create(cls, layer_type, name=None, **kwargs):
        if isinstance(layer_type, six.string_types):
            layer_type_name = layer_type
        else:
            layer_type_name = layer_type.__name__

        if not layer_type_name.endswith('LayerImpl'):
            raise NetworkValidationError(
                "{} should end with 'LayerImpl'".format(layer_type_name))
        layer_type_name = layer_type_name[:-9]

        details = LayerDetails(layer_type_name, name=name, **kwargs)
        return ConstructionWrapper(details)
Ejemplo n.º 3
0
def validate_architecture(architecture):
    # schema
    for name, layer in architecture.items():
        if not isinstance(name, string_types):
            raise NetworkValidationError('Non-string name {}'.format(name))
        if '@type' not in layer:
            raise NetworkValidationError(
                'Missing @type for "{}"'.format(name))
        if not isinstance(layer['@type'], string_types):
            raise NetworkValidationError('Invalid @type for "{}": {}'.format(
                name, type(layer['@type'])))

        if '@outgoing_connections' in layer and not isinstance(
                layer['@outgoing_connections'], (list, tuple, dict)):
            raise NetworkValidationError(
                'Invalid @outgoing_connections for "{}"'.format(name))

    # layer naming
    for name in architecture:
        if not is_valid_layer_name(name):
            raise NetworkValidationError(
                "Invalid layer name: '{}'".format(name))

    # all outgoing connections are present
    connections = collect_all_connections(architecture)
    end_layers = {c.end_layer for c in connections}
    undefined_end_layers = end_layers.difference(architecture)
    if undefined_end_layers:
        raise NetworkValidationError(
            'Could not find end layer(s) "{}"'.format(undefined_end_layers))

    # has exactly one Input and its called Input
    if "Input" not in architecture or \
            architecture['Input']['@type'] != 'Input':
        raise NetworkValidationError(
            'Needs exactly one Input that is called "Input"')

    # no connections to Input
    if 'Input' in end_layers:
        raise NetworkValidationError(
            'Input can not have incoming connections!')

    # TODO: check if connected
    # TODO: check for cycles
    return True
Ejemplo n.º 4
0
    def permute_rows(self):
        """
        Given a list of sources and a connection table, find a permutation of
        the sources, such that they can be connected to the sinks via a single
        buffer.
        """
        # systematically try all permutations until one satisfies the condition
        for perm in itertools.permutations(self.nesting):
            self.perm = list(flatten(perm))
            ct = np.atleast_2d(self.connection_table[self.perm])
            if Hub.can_be_connected_with_single_buffer(ct):
                self.connection_table = ct
                self.flat_sources = [self.flat_sources[i] for i in self.perm]
                return

        raise NetworkValidationError("Failed to lay out buffers. "
                                     "Please change connectivity.")
Ejemplo n.º 5
0
def get_key_to_references_mapping(keys, references):
    """
    Create a mapping that maps keys to their matching references.
    The 'default' reference matches only if no other reference does.
    The 'fallback' reference is ignored.

    Args:
        keys (iterable[str]):
            List of keys that the references are referring to.

        references (iterable[str]):
            List of references. Can contain star wildcards.

    Returns:
        dict[str, set[str]]:
            Dictionary mapping keys to sets of matching references.
    """
    key_to_reference = {key: set() for key in keys}

    for ref in references:
        if ref in {'default', 'fallback'}:
            continue

        expr = get_regex_for_reference(ref)
        matching_keys = [key for key in key_to_reference if expr.match(key)]
        if not matching_keys:
            raise NetworkValidationError(
                "{} does not match any keys. Possible keys are: {}".format(
                    ref, sorted(key_to_reference.keys())))

        for key in matching_keys:
            key_to_reference[key].add(ref)

    if 'default' in references:
        for key, refs in key_to_reference.items():
            if not refs:
                refs.add('default')

    return key_to_reference
Ejemplo n.º 6
0
    def initialize(self, default_or_init_dict=None, seed=None, **kwargs):
        """Initialize the weights of the network.

        Initialization can be specified in three equivalent ways:

            1. just a default initializer:

                >>> net.initialize(Gaussian())

                Note that this is equivalent to:

                >>> net.initialize(default=Gaussian())

            2. by passing a dictionary:

                >>> net.initialize({'RegularLayer': Uniform(),
                ...                 'LstmLayer': Gaussian()})

            3. by using keyword arguments:

                >>> net.initialize(RegularLayer=Uniform(),
                ...                LstmLayer=Uniform())

        All following explanations will be with regards to the dictionary style
        of initialization, because it is the most general one.

        Note:
            It is not recommended to combine 2. and 3. but if they are,
            then keyword arguments take precedence.

        Each initialization consists of a layer-pattern and that maps to an
        initializer or a weight-pattern dictionary.

        Layer patterns can take the following forms:

            1. ``{'layer_name': INIT_OR_SUBDICT}``
               Matches all the weights of the layer named layer_name
            2. ``{'layer_*': INIT_OR_SUBDICT}``
               Matches all layers with a name that starts with ``layer_``
               The wild-card ``*`` can appear at arbitrary positions and even
               multiple times in one path.

        There are two special layer patterns:

            3. ``{'default': INIT}``
               Matches all weights that are not matched by any other
               path-pattern
            4. ``{'fallback': INIT}``
               Set a fallback initializer for every weight. It will only be
               evaluated for the weights for which the regular initializer
               failed with an InitializationError.

               `This is useful for initializers that require a certain shape
               of weights and will not work otherwise. The fallback will then
               be used for all cases when that initializer failed.`

        The weight-pattern sub-dictionary follows the same form as the layer-
        pattern:

            1) ``{'layer_pattern': {'a': INIT_A, 'b': INIT_B}}``
            2) ``{'layer_pattern': {'a*': INIT}``
            3) ``{'layer_pattern': {'default': INIT}``
            4) ``{'layer_pattern': {'fallback': INIT}``


        An initializer can either be a scalar, something that converts to a
        numpy array of the correct shape or an :class:`Initializer` object.
        So for example:

        >>> net.initialize(default=0,
        ...                RnnLayer={'b': [1, 2, 3, 4, 5]},
        ...                ForwardLayer=bs.Gaussian())

        Note:
            Each view must match exactly one initialization and up to one
            fallback to be unambiguous. Otherwise the initialization will fail.

        You can specify a seed to make the initialization reproducible:

        >>> net.initialize({'default': bs.Gaussian()}, seed=1234)
        """
        init_refs = _update_references_with_dict(default_or_init_dict, kwargs)
        self.initializers = get_description(init_refs)
        all_parameters = {
            k: v.parameters
            for k, v in self.buffer.items()
            if isinstance(v, BufferView) and 'parameters' in v
        }
        _replace_lists_with_array_initializers(init_refs)
        initializers, fallback = resolve_references(all_parameters, init_refs)
        init_rnd = self.rnd.create_random_state(seed)
        for layer_name, views in sorted(all_parameters.items()):
            if views is None:
                continue
            for view_name, view in sorted(views.items()):
                init = initializers[layer_name][view_name]
                fb = fallback[layer_name][view_name]
                if len(init) > 1:
                    raise NetworkValidationError(
                        "Multiple initializers for {}.{}: {}".format(
                            layer_name, view_name, init))

                if len(init) == 0:
                    raise NetworkValidationError(
                        "No initializer for {}.{}".format(
                            layer_name, view_name))
                if len(fb) > 1:
                    raise NetworkValidationError(
                        "Multiple fallbacks for {}.{}: {}".format(
                            layer_name, view_name, fb))

                fb = fb.pop() if len(fb) else None
                self.handler.set_from_numpy(
                    view,
                    evaluate_initializer(init.pop(),
                                         view.shape,
                                         fb,
                                         seed=init_rnd.generate_seed()))