keras Layer

keras Layer

Simple Introduction

Keras实现了很多层,包括核心层、卷基层、RNN网络层等诸多常用的网络结构。

Core 核心层

Source

class Layer(object):
    '''Abstract base layer class. All Keras layers accept certain keyword arguments: trainable: boolean. Set to "False" before model compilation to freeze layer weights (they won't be updated further during training). input_shape: a tuple of integers specifying the expected shape of the input samples. Does not includes the batch size. (e.g. `(100,)` for 100-dimensional inputs). batch_input_shape: a tuple of integers specifying the expected shape of a batch of input samples. Includes the batch size (e.g. `(32, 100)` for a batch of 32 100-dimensional inputs). '''
    def __init__(self, **kwargs):
        allowed_kwargs = {'input_shape',
                          'trainable',
                          'batch_input_shape',
                          'cache_enabled'}
        for kwarg in kwargs:
            assert kwarg in allowed_kwargs, 'Keyword argument not understood: ' + kwarg
        if 'input_shape' in kwargs:
            self.set_input_shape((None,) + tuple(kwargs['input_shape']))
        if 'batch_input_shape' in kwargs:
            self.set_input_shape(tuple(kwargs['batch_input_shape']))
        if 'trainable' in kwargs:
            self._trainable = kwargs['trainable']
        if not hasattr(self, 'params'):
            self.params = []
        self._cache_enabled = True
        if 'cache_enabled' in kwargs:
            self._cache_enabled = kwargs['cache_enabled']


    @property
    def cache_enabled(self):
        return self._cache_enabled


    @cache_enabled.setter
    def cache_enabled(self, value):
        self._cache_enabled = value


    def __call__(self, X, mask=None, train=False):
        # set temporary input
        tmp_input = self.get_input
        tmp_mask = None
        if hasattr(self, 'get_input_mask'):
            tmp_mask = self.get_input_mask
            self.get_input_mask = lambda _: mask
        self.get_input = lambda _: X
        Y = self.get_output(train=train)
        # return input to what it was
        if hasattr(self, 'get_input_mask'):
            self.get_input_mask = tmp_mask
        self.get_input = tmp_input
        return Y


    def set_previous(self, layer, connection_map={}):
        '''Connect a layer to its parent in the computational graph. '''
        assert self.nb_input == layer.nb_output == 1, 'Cannot connect layers: input count and output count should be 1.'
        if hasattr(self, 'input_ndim'):
            assert self.input_ndim == len(layer.output_shape), ('Incompatible shapes: layer expected input with ndim=' +
                                                                str(self.input_ndim) +
                                                                ' but previous layer has output_shape ' +
                                                                str(layer.output_shape))
        if layer.get_output_mask() is not None:
            assert self.supports_masked_input(), 'Cannot connect non-masking layer to layer with masked output.'
        self.previous = layer
        self.build()


    def build(self):
        '''Instantiation of layer weights. Called after `set_previous`, or after `set_input_shape`, once the layer has a defined input shape. Must be implemented on all layers that have weights. '''
        pass


    @property
    def trainable(self):
        if hasattr(self, '_trainable'):
            return self._trainable
        else:
            return True


    @trainable.setter
    def trainable(self, value):
        self._trainable = value


    @property
    def nb_input(self):
        return 1


    @property
    def nb_output(self):
        return 1


    @property
    def input_shape(self):
        # if layer is not connected (e.g. input layer),
        # input shape can be set manually via _input_shape attribute.
        if hasattr(self, 'previous'):
            return self.previous.output_shape
        elif hasattr(self, '_input_shape'):
            return self._input_shape
        else:
            raise Exception('Layer is not connected. Did you forget to set "input_shape"?')


    def set_input_shape(self, input_shape):
        if type(input_shape) not in [tuple, list]:
            raise Exception('Invalid input shape - input_shape should be a tuple of int.')
        input_shape = tuple(input_shape)
        if hasattr(self, 'input_ndim') and self.input_ndim:
            if self.input_ndim != len(input_shape):
                raise Exception('Invalid input shape - Layer expects input ndim=' +
                                str(self.input_ndim) +
                                ', was provided with input shape ' + str(input_shape))
        self._input_shape = input_shape
        self.input = K.placeholder(shape=self._input_shape)
        self.build()


    @property
    def output_shape(self):
        # default assumption: tensor shape unchanged.
        return self.input_shape


    def get_output(self, train=False):
        return self.get_input(train)


    def get_input(self, train=False):
        if hasattr(self, 'previous'):
            # to avoid redundant computations,
            # layer outputs are cached when possible.
            if hasattr(self, 'layer_cache') and self.cache_enabled:
                previous_layer_id = '%s_%s' % (id(self.previous), train)
                if previous_layer_id in self.layer_cache:
                    return self.layer_cache[previous_layer_id]
            previous_output = self.previous.get_output(train=train)
            if hasattr(self, 'layer_cache') and self.cache_enabled:
                previous_layer_id = '%s_%s' % (id(self.previous), train)
                self.layer_cache[previous_layer_id] = previous_output
            return previous_output
        elif hasattr(self, 'input'):
            return self.input
        else:
            raise Exception('Layer is not connected' +
                            'and is not an input layer.')


    def supports_masked_input(self):
        '''Whether or not this layer respects the output mask of its previous layer in its calculations. If you try to attach a layer that does *not* support masked_input to a layer that gives a non-None output_mask(), an error will be raised. '''
        return False


    def get_output_mask(self, train=None):
        '''For some models (such as RNNs) you want a way of being able to mark some output data-points as "masked", so they are not used in future calculations. In such a model, get_output_mask() should return a mask of one less dimension than get_output() (so if get_output is (nb_samples, nb_timesteps, nb_dimensions), then the mask is (nb_samples, nb_timesteps), with a one for every unmasked datapoint, and a zero for every masked one. If there is *no* masking then it shall return None. For instance if you attach an Activation layer (they support masking) to a layer with an output_mask, then that Activation shall also have an output_mask. If you attach it to a layer with no such mask, then the Activation's get_output_mask shall return None. Some layers have an output_mask even if their input is unmasked, notably Embedding which can turn the entry "0" into a mask. '''
        return None


    def set_weights(self, weights):
        '''Set the weights of the layer. weights: a list of numpy arrays. The number of arrays and their shape must match number of the dimensions of the weights of the layer (i.e. it should match the output of `get_weights`). '''
        assert len(self.params) == len(weights), ('Provided weight array does not match layer weights (' +
                                                  str(len(self.params)) + ' layer params vs. ' +
                                                  str(len(weights)) + ' provided weights)')
        for p, w in zip(self.params, weights):
            if K.get_value(p).shape != w.shape:
                raise Exception('Layer shape %s not compatible with weight shape %s.' % (K.get_value(p).shape, w.shape))
            K.set_value(p, w)


    def get_weights(self):
        '''Return the weights of the layer, as a list of numpy arrays. '''
        weights = []
        for p in self.params:
            weights.append(K.get_value(p))
        return weights


    def get_config(self):
        '''Return the parameters of the layer, as a dictionary. '''
        config = {'name': self.__class__.__name__}
        if hasattr(self, '_input_shape'):
            config['input_shape'] = self._input_shape[1:]
        if hasattr(self, '_trainable'):
            config['trainable'] = self._trainable
        config['cache_enabled'] =  self.cache_enabled
        return config


    def get_params(self):
        consts = []
        updates = []


        if hasattr(self, 'regularizers'):
            regularizers = self.regularizers
        else:
            regularizers = []


        if hasattr(self, 'constraints') and len(self.constraints) == len(self.params):
            for c in self.constraints:
                if c:
                    consts.append(c)
                else:
                    consts.append(constraints.identity())
        elif hasattr(self, 'constraint') and self.constraint:
            consts += [self.constraint for _ in range(len(self.params))]
        else:
            consts += [constraints.identity() for _ in range(len(self.params))]


        if hasattr(self, 'updates') and self.updates:
            updates += self.updates


        return self.params, regularizers, consts, updates


    def count_params(self):
        '''Return the total number of floats (or ints) composing the weights of the layer. '''
        return sum([K.count_params(p) for p in self.params])

set_previous

设置previous layer, 使previous layer连接到当前的layer,同时会调用build方法初始化regularizers,weights等参数.

build

被set_previous调用,初始化regularizers,weights等参数.

input_shape

python property. 如果该layer是输入层,返回自身的input shape, 否则返回previous layer的input shape.

set_input_shape

设置input shape(tuple, list), 并调用build方法初始化regularizers,weights等参数.

get_input

返回previous layer的output,如果当前层是输入层,则返回当前的输入.

Activation Layer

主要是计算经过激活函数后输出值,激活函数有softmax, softplus, relu, tanh, sigmoid, hard_sigmoid, linear.

source

class Activation(MaskedLayer):
    '''Apply an activation function to an output. # Input shape Arbitrary. Use the keyword argument `input_shape` (tuple of integers, does not include the samples axis) when using this layer as the first layer in a model. # Output shape Same shape as input. # Arguments: activation: name of activation function to use (see: [activations](../activations.md)), or alternatively, a Theano or TensorFlow operation. '''
    def __init__(self, activation, **kwargs):
        super(Activation, self).__init__(**kwargs)
        self.activation = activations.get(activation)


    def get_output(self, train=False):
        X = self.get_input(train)
        return self.activation(X)


    def get_config(self):
        config = {'name': self.__class__.__name__,
                  'activation': self.activation.__name__}
        base_config = super(Activation, self).get_config()
        return dict(list(base_config.items()) + list(config.items()))

Lambda Layer

该layer的output是经过lambda计算,如果该layer是input layer,则lambda的input是当前layer 的input,否则是previous layer的input

example

kerasmodel.add_node(Lambda(lambda x:x.sum(2)), name='merge',inputs=['embedding','embedpoint'], merge_mode='mul')

source

class Lambda(Layer):
    '''Used for evaluating an arbitrary Theano / TensorFlow expression on the output of the previous layer. # Input shape Arbitrary. Use the keyword argument input_shape (tuple of integers, does not include the samples axis) when using this layer as the first layer in a model. # Output shape Specified by `output_shape` argument. # Arguments function: The function to be evaluated. Takes one argument: the output of previous layer output_shape: Expected output shape from function. Could be a tuple or a function of the shape of the input '''
    def __init__(self, function, output_shape=None, **kwargs):
        super(Lambda, self).__init__(**kwargs)
        py3 = sys.version_info[0] == 3
        if py3:
            self.function = marshal.dumps(function.__code__)
        else:
            assert hasattr(function, 'func_code'), ('The Lambda layer "function"'
                                                    ' argument must be a Python function.')
            self.function = marshal.dumps(function.func_code)
        if output_shape is None:
            self._output_shape = None
        elif type(output_shape) in {tuple, list}:
            self._output_shape = tuple(output_shape)
        else:
            if py3:
                self._output_shape = marshal.dumps(output_shape.__code__)
            else:
                self._output_shape = marshal.dumps(output_shape.func_code)
        super(Lambda, self).__init__()


    @property
    def output_shape(self):
        if self._output_shape is None:
            return self.input_shape
        elif type(self._output_shape) == tuple:
            return (self.input_shape[0], ) + self._output_shape
        else:
            output_shape_func = marshal.loads(self._output_shape)
            output_shape_func = types.FunctionType(output_shape_func, globals())
            shape = output_shape_func(self.previous.output_shape)
            if type(shape) not in {list, tuple}:
                raise Exception('output_shape function must return a tuple')
            return tuple(shape)


    def get_output(self, train=False):
        func = marshal.loads(self.function)
        func = types.FunctionType(func, globals())
        if hasattr(self, 'previous'):
            return func(self.previous.get_output(train))
        else:
            return func(self.input)

Embedding Layer

使用keras实现word2Vector时,需要用到Embedding Layer

你可能感兴趣的:(深度学习)