Naming, batch_flatten
This commit is contained in:
parent
13379da81b
commit
037e592f2b
@ -287,6 +287,10 @@ def tile(x, n):
|
|||||||
|
|
||||||
|
|
||||||
def flatten(x):
|
def flatten(x):
|
||||||
|
return tf.reshape(x, [-1])
|
||||||
|
|
||||||
|
|
||||||
|
def batch_flatten(x):
|
||||||
'''Turn a n-D tensor into a 2D tensor where
|
'''Turn a n-D tensor into a 2D tensor where
|
||||||
the first dimension is conserved.
|
the first dimension is conserved.
|
||||||
'''
|
'''
|
||||||
@ -345,12 +349,16 @@ def set_value(x, value):
|
|||||||
class Function(object):
|
class Function(object):
|
||||||
|
|
||||||
def __init__(self, inputs, outputs, updates=[]):
|
def __init__(self, inputs, outputs, updates=[]):
|
||||||
|
assert type(inputs) in {list, tuple}
|
||||||
|
assert type(outputs) in {list, tuple}
|
||||||
|
assert type(updates) in {list, tuple}
|
||||||
self.inputs = list(inputs)
|
self.inputs = list(inputs)
|
||||||
self.outputs = list(outputs)
|
self.outputs = list(outputs)
|
||||||
with tf.control_dependencies(self.outputs):
|
with tf.control_dependencies(self.outputs):
|
||||||
self.updates = [tf.assign(p, new_p) for (p, new_p) in updates]
|
self.updates = [tf.assign(p, new_p) for (p, new_p) in updates]
|
||||||
|
|
||||||
def __call__(self, inputs):
|
def __call__(self, inputs):
|
||||||
|
assert type(inputs) in {list, tuple}
|
||||||
names = [v.name for v in self.inputs]
|
names = [v.name for v in self.inputs]
|
||||||
feed_dict = dict(zip(names, inputs))
|
feed_dict = dict(zip(names, inputs))
|
||||||
session = _get_session()
|
session = _get_session()
|
||||||
@ -442,7 +450,7 @@ def rnn(step_function, inputs, initial_states,
|
|||||||
new_states = successive_states[-1]
|
new_states = successive_states[-1]
|
||||||
|
|
||||||
outputs = tf.transpose(outputs, (1, 0, 2))
|
outputs = tf.transpose(outputs, (1, 0, 2))
|
||||||
return last_output, outputs, states
|
return last_output, outputs, new_states
|
||||||
|
|
||||||
|
|
||||||
def switch(condition, then_expression, else_expression):
|
def switch(condition, then_expression, else_expression):
|
||||||
|
@ -287,6 +287,10 @@ def tile(x, n):
|
|||||||
|
|
||||||
|
|
||||||
def flatten(x):
|
def flatten(x):
|
||||||
|
return T.flatten(x)
|
||||||
|
|
||||||
|
|
||||||
|
def batch_flatten(x):
|
||||||
'''Turn a n-D tensor into a 2D tensor where
|
'''Turn a n-D tensor into a 2D tensor where
|
||||||
the first dimension is conserved.
|
the first dimension is conserved.
|
||||||
'''
|
'''
|
||||||
@ -378,10 +382,14 @@ def set_value(x, value):
|
|||||||
class Function(object):
|
class Function(object):
|
||||||
|
|
||||||
def __init__(self, inputs, outputs, updates=[], **kwargs):
|
def __init__(self, inputs, outputs, updates=[], **kwargs):
|
||||||
|
assert type(inputs) in {list, tuple}
|
||||||
|
assert type(outputs) in {list, tuple}
|
||||||
|
assert type(updates) in {list, tuple}
|
||||||
self.function = theano.function(inputs, outputs, updates=updates,
|
self.function = theano.function(inputs, outputs, updates=updates,
|
||||||
allow_input_downcast=True, **kwargs)
|
allow_input_downcast=True, **kwargs)
|
||||||
|
|
||||||
def __call__(self, inputs):
|
def __call__(self, inputs):
|
||||||
|
assert type(inputs) in {list, tuple}
|
||||||
return self.function(*inputs)
|
return self.function(*inputs)
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,52 +9,54 @@ def get_fans(shape):
|
|||||||
return fan_in, fan_out
|
return fan_in, fan_out
|
||||||
|
|
||||||
|
|
||||||
def uniform(shape, scale=0.05):
|
def uniform(shape, scale=0.05, name=None):
|
||||||
return K.variable(np.random.uniform(low=-scale, high=scale, size=shape))
|
return K.variable(np.random.uniform(low=-scale, high=scale, size=shape),
|
||||||
|
name=name)
|
||||||
|
|
||||||
|
|
||||||
def normal(shape, scale=0.05):
|
def normal(shape, scale=0.05, name=None):
|
||||||
return K.variable(np.random.normal(loc=0.0, scale=scale, size=shape))
|
return K.variable(np.random.normal(loc=0.0, scale=scale, size=shape),
|
||||||
|
name=name)
|
||||||
|
|
||||||
|
|
||||||
def lecun_uniform(shape):
|
def lecun_uniform(shape, name=None):
|
||||||
''' Reference: LeCun 98, Efficient Backprop
|
''' Reference: LeCun 98, Efficient Backprop
|
||||||
http://yann.lecun.com/exdb/publis/pdf/lecun-98b.pdf
|
http://yann.lecun.com/exdb/publis/pdf/lecun-98b.pdf
|
||||||
'''
|
'''
|
||||||
fan_in, fan_out = get_fans(shape)
|
fan_in, fan_out = get_fans(shape)
|
||||||
scale = np.sqrt(3. / fan_in)
|
scale = np.sqrt(3. / fan_in)
|
||||||
return uniform(shape, scale)
|
return uniform(shape, scale, name=name)
|
||||||
|
|
||||||
|
|
||||||
def glorot_normal(shape):
|
def glorot_normal(shape, name=None):
|
||||||
''' Reference: Glorot & Bengio, AISTATS 2010
|
''' Reference: Glorot & Bengio, AISTATS 2010
|
||||||
'''
|
'''
|
||||||
fan_in, fan_out = get_fans(shape)
|
fan_in, fan_out = get_fans(shape)
|
||||||
s = np.sqrt(2. / (fan_in + fan_out))
|
s = np.sqrt(2. / (fan_in + fan_out))
|
||||||
return normal(shape, s)
|
return normal(shape, s, name=name)
|
||||||
|
|
||||||
|
|
||||||
def glorot_uniform(shape):
|
def glorot_uniform(shape, name=None):
|
||||||
fan_in, fan_out = get_fans(shape)
|
fan_in, fan_out = get_fans(shape)
|
||||||
s = np.sqrt(6. / (fan_in + fan_out))
|
s = np.sqrt(6. / (fan_in + fan_out))
|
||||||
return uniform(shape, s)
|
return uniform(shape, s, name=name)
|
||||||
|
|
||||||
|
|
||||||
def he_normal(shape):
|
def he_normal(shape, name=None):
|
||||||
''' Reference: He et al., http://arxiv.org/abs/1502.01852
|
''' Reference: He et al., http://arxiv.org/abs/1502.01852
|
||||||
'''
|
'''
|
||||||
fan_in, fan_out = get_fans(shape)
|
fan_in, fan_out = get_fans(shape)
|
||||||
s = np.sqrt(2. / fan_in)
|
s = np.sqrt(2. / fan_in)
|
||||||
return normal(shape, s)
|
return normal(shape, s, name=name)
|
||||||
|
|
||||||
|
|
||||||
def he_uniform(shape):
|
def he_uniform(shape, name=None):
|
||||||
fan_in, fan_out = get_fans(shape)
|
fan_in, fan_out = get_fans(shape)
|
||||||
s = np.sqrt(6. / fan_in)
|
s = np.sqrt(6. / fan_in)
|
||||||
return uniform(shape, s)
|
return uniform(shape, s, name=name)
|
||||||
|
|
||||||
|
|
||||||
def orthogonal(shape, scale=1.1):
|
def orthogonal(shape, scale=1.1, name=None):
|
||||||
''' From Lasagne. Reference: Saxe et al., http://arxiv.org/abs/1312.6120
|
''' From Lasagne. Reference: Saxe et al., http://arxiv.org/abs/1312.6120
|
||||||
'''
|
'''
|
||||||
flat_shape = (shape[0], np.prod(shape[1:]))
|
flat_shape = (shape[0], np.prod(shape[1:]))
|
||||||
@ -63,23 +65,23 @@ def orthogonal(shape, scale=1.1):
|
|||||||
# pick the one with the correct shape
|
# pick the one with the correct shape
|
||||||
q = u if u.shape == flat_shape else v
|
q = u if u.shape == flat_shape else v
|
||||||
q = q.reshape(shape)
|
q = q.reshape(shape)
|
||||||
return K.variable(scale * q[:shape[0], :shape[1]])
|
return K.variable(scale * q[:shape[0], :shape[1]], name=name)
|
||||||
|
|
||||||
|
|
||||||
def identity(shape, scale=1):
|
def identity(shape, scale=1, name=None):
|
||||||
if len(shape) != 2 or shape[0] != shape[1]:
|
if len(shape) != 2 or shape[0] != shape[1]:
|
||||||
raise Exception('Identity matrix initialization can only be used '
|
raise Exception('Identity matrix initialization can only be used '
|
||||||
'for 2D square matrices.')
|
'for 2D square matrices.')
|
||||||
else:
|
else:
|
||||||
return K.variable(scale * np.identity(shape[0]))
|
return K.variable(scale * np.identity(shape[0]), name=name)
|
||||||
|
|
||||||
|
|
||||||
def zero(shape):
|
def zero(shape, name=None):
|
||||||
return K.zeros(shape)
|
return K.zeros(shape, name=name)
|
||||||
|
|
||||||
|
|
||||||
def one(shape):
|
def one(shape, name=None):
|
||||||
return K.ones(shape)
|
return K.ones(shape, name=name)
|
||||||
|
|
||||||
|
|
||||||
from .utils.generic_utils import get_from_module
|
from .utils.generic_utils import get_from_module
|
||||||
|
@ -36,20 +36,34 @@ class Layer(object):
|
|||||||
allowed_kwargs = {'input_shape',
|
allowed_kwargs = {'input_shape',
|
||||||
'trainable',
|
'trainable',
|
||||||
'batch_input_shape',
|
'batch_input_shape',
|
||||||
'cache_enabled'}
|
'cache_enabled',
|
||||||
|
'name'}
|
||||||
for kwarg in kwargs:
|
for kwarg in kwargs:
|
||||||
assert kwarg in allowed_kwargs, 'Keyword argument not understood: ' + kwarg
|
assert kwarg in allowed_kwargs, 'Keyword argument not understood: ' + kwarg
|
||||||
|
|
||||||
if 'input_shape' in kwargs:
|
if 'input_shape' in kwargs:
|
||||||
self.set_input_shape((None,) + tuple(kwargs['input_shape']))
|
self.set_input_shape((None,) + tuple(kwargs['input_shape']))
|
||||||
if 'batch_input_shape' in kwargs:
|
if 'batch_input_shape' in kwargs:
|
||||||
self.set_input_shape(tuple(kwargs['batch_input_shape']))
|
self.set_input_shape(tuple(kwargs['batch_input_shape']))
|
||||||
|
self.trainable = True
|
||||||
if 'trainable' in kwargs:
|
if 'trainable' in kwargs:
|
||||||
self._trainable = kwargs['trainable']
|
self.trainable = kwargs['trainable']
|
||||||
|
self.name = self.__class__.__name__.lower()
|
||||||
|
if 'name' in kwargs:
|
||||||
|
self.name = kwargs['name']
|
||||||
if not hasattr(self, 'params'):
|
if not hasattr(self, 'params'):
|
||||||
self.params = []
|
self.params = []
|
||||||
self._cache_enabled = True
|
self.cache_enabled = True
|
||||||
if 'cache_enabled' in kwargs:
|
if 'cache_enabled' in kwargs:
|
||||||
self._cache_enabled = kwargs['cache_enabled']
|
self.cache_enabled = kwargs['cache_enabled']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
@name.setter
|
||||||
|
def name(self, name):
|
||||||
|
self._name = name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def cache_enabled(self):
|
def cache_enabled(self):
|
||||||
@ -233,7 +247,8 @@ class Layer(object):
|
|||||||
config['input_shape'] = self._input_shape[1:]
|
config['input_shape'] = self._input_shape[1:]
|
||||||
if hasattr(self, '_trainable'):
|
if hasattr(self, '_trainable'):
|
||||||
config['trainable'] = self._trainable
|
config['trainable'] = self._trainable
|
||||||
config['cache_enabled'] = self.cache_enabled
|
config['cache_enabled'] = self.cache_enabled
|
||||||
|
config['custom_name'] = self.name
|
||||||
return config
|
return config
|
||||||
|
|
||||||
def get_params(self):
|
def get_params(self):
|
||||||
@ -819,7 +834,7 @@ class Flatten(Layer):
|
|||||||
|
|
||||||
def get_output(self, train=False):
|
def get_output(self, train=False):
|
||||||
X = self.get_input(train)
|
X = self.get_input(train)
|
||||||
return K.flatten(X)
|
return K.batch_flatten(X)
|
||||||
|
|
||||||
|
|
||||||
class RepeatVector(Layer):
|
class RepeatVector(Layer):
|
||||||
|
@ -71,10 +71,11 @@ def container_from_config(original_layer_dict, custom_objects={}):
|
|||||||
kwargs[kwarg] = layer_dict[kwarg]
|
kwargs[kwarg] = layer_dict[kwarg]
|
||||||
return AutoEncoder(**kwargs)
|
return AutoEncoder(**kwargs)
|
||||||
|
|
||||||
else:
|
else: # this is a non-topological layer (e.g. Dense, etc.)
|
||||||
layer_dict.pop('name')
|
layer_dict.pop('name')
|
||||||
|
|
||||||
for k, v in layer_dict.items():
|
for k, v in layer_dict.items():
|
||||||
|
# a dictionary argument may be a regularizer or constraint
|
||||||
if isinstance(v, dict):
|
if isinstance(v, dict):
|
||||||
vname = v.pop('name')
|
vname = v.pop('name')
|
||||||
if vname in [x for x, y in inspect.getmembers(constraints, predicate=inspect.isclass)]:
|
if vname in [x for x, y in inspect.getmembers(constraints, predicate=inspect.isclass)]:
|
||||||
@ -85,6 +86,9 @@ def container_from_config(original_layer_dict, custom_objects={}):
|
|||||||
# not a regularizer of constraint, don't touch it
|
# not a regularizer of constraint, don't touch it
|
||||||
v['name'] = vname
|
v['name'] = vname
|
||||||
|
|
||||||
|
# the "name" keyword argument of layers is saved as "custom_name"
|
||||||
|
if 'custom_name' in layer_dict:
|
||||||
|
layer_dict['name'] = layer_dict.pop('custom_name')
|
||||||
base_layer = get_layer(name, layer_dict)
|
base_layer = get_layer(name, layer_dict)
|
||||||
return base_layer
|
return base_layer
|
||||||
|
|
||||||
|
@ -130,6 +130,21 @@ def test_maxout_dense():
|
|||||||
_runner(layer)
|
_runner(layer)
|
||||||
|
|
||||||
|
|
||||||
|
def test_naming():
|
||||||
|
layer = core.Dense(2, input_dim=2)
|
||||||
|
assert layer.name == 'dense'
|
||||||
|
|
||||||
|
model = Sequential()
|
||||||
|
model.add(core.Dense(2, input_dim=2, name='my_dense'))
|
||||||
|
model.add(core.Dense(2, name='my_dense'))
|
||||||
|
|
||||||
|
assert model.layers[0].name == 'my_dense'
|
||||||
|
assert model.layers[1].name == 'my_dense'
|
||||||
|
|
||||||
|
model.compile(optimizer='rmsprop', loss='mse')
|
||||||
|
model.train_on_batch(np.random.random((2, 2)), np.random.random((2, 2)))
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(K._BACKEND == 'tensorflow',
|
@pytest.mark.skipif(K._BACKEND == 'tensorflow',
|
||||||
reason='currently not working with TensorFlow')
|
reason='currently not working with TensorFlow')
|
||||||
def test_sequences():
|
def test_sequences():
|
||||||
|
@ -85,6 +85,8 @@ def test_batchnorm_config():
|
|||||||
epsilon=0.1, momentum=0.9)
|
epsilon=0.1, momentum=0.9)
|
||||||
conf = norm.get_config()
|
conf = norm.get_config()
|
||||||
del conf['cache_enabled']
|
del conf['cache_enabled']
|
||||||
|
del conf['trainable']
|
||||||
|
del conf['custom_name']
|
||||||
conf_target = {"input_shape": (10, 10),
|
conf_target = {"input_shape": (10, 10),
|
||||||
"name": normalization.BatchNormalization.__name__,
|
"name": normalization.BatchNormalization.__name__,
|
||||||
"epsilon": 0.1, "mode": 1, "momentum": 0.9}
|
"epsilon": 0.1, "mode": 1, "momentum": 0.9}
|
||||||
|
Loading…
Reference in New Issue
Block a user