您的位置:首页 > 其它

keras Layer

2016-05-15 15:38 309 查看

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: