Layer
classtf_keras.layers.Layer(trainable=True, name=None, dtype=None, dynamic=False, **kwargs)
This is the class from which all layers inherit.
A layer is a callable object that takes as input one or more tensors and
that outputs one or more tensors. It involves computation, defined
in the call()
method, and a state (weight variables). State can be
created in various places, at the convenience of the subclass implementer:
__init__()
;build()
method, which is invoked by the first
__call__()
to the layer, and supplies the shape(s) of the input(s),
which may not have been known at initialization time;call()
, with some caveats discussed
below.Layers are recursively composable: If you assign a Layer instance as an
attribute of another Layer, the outer layer will start tracking the weights
created by the inner layer. Nested layers should be instantiated in the
__init__()
method.
Users will just instantiate a layer and then treat it as a callable.
Arguments
tf.keras.mixed_precision.Policy
, which allows the computation and
weight dtype to differ. Default of None
means to use
tf.keras.mixed_precision.global_policy()
, which is a float32 policy
unless set to different value.True
if your layer should only be run eagerly, and
should not be used to generate a static computation graph.
This would be the case for a Tree-RNN or a recursive network,
for example, or generally for any layer that manipulates tensors
using Python control flow. If False
, we assume that the layer can
safely be used to generate a static computation graph.Attributes
dtype
.tf.keras.mixed_precision.Policy
, this will be different than
variable_dtype
.tf.keras.mixed_precision.Policy
documentation for details.layer.trainable_weights
.InputSpec
object(s) specifying the
constraints on inputs that can be accepted by the layer.We recommend that descendants of Layer
implement the following methods:
__init__()
: Defines custom layer attributes, and creates layer weights
that do not depend on input shapes, using add_weight()
, or other state.build(self, input_shape)
: This method can be used to create weights that
depend on the shape(s) of the input(s), using add_weight()
, or other
state. __call__()
will automatically build the layer (if it has not been
built yet) by calling build()
.call(self, inputs, *args, **kwargs)
: Called in __call__
after making
sure build()
has been called. call()
performs the logic of applying
the layer to the inputs
. The first invocation may additionally create
state that could not be conveniently created in build()
; see its
docstring for details.
Two reserved keyword arguments you can optionally use in call()
are:
- training
(boolean, whether the call is in inference mode or training
mode). See more details in the layer/model subclassing guide
- mask
(boolean tensor encoding masked timesteps in the input, used
in RNN layers). See more details in
the layer/model subclassing guide
A typical signature for this method is call(self, inputs)
, and user
could optionally add training
and mask
if the layer need them. *args
and **kwargs
is only useful for future extension when more input
parameters are planned to be added.get_config(self)
: Returns a dictionary containing the configuration used
to initialize this layer. If the keys differ from the arguments
in __init__
, then override from_config(self)
as well.
This method is used when saving
the layer or a model that contains this layer.Examples
Here's a basic example: a layer with two variables, w
and b
,
that returns y = w . x + b
.
It shows how to implement build()
and call()
.
Variables set as attributes of a layer are tracked as weights
of the layers (in layer.weights
).
class SimpleDense(Layer):
def __init__(self, units=32):
super(SimpleDense, self).__init__()
self.units = units
def build(self, input_shape): # Create the state of the layer (weights)
w_init = tf.random_normal_initializer()
self.w = tf.Variable(
initial_value=w_init(shape=(input_shape[-1], self.units),
dtype='float32'),
trainable=True)
b_init = tf.zeros_initializer()
self.b = tf.Variable(
initial_value=b_init(shape=(self.units,), dtype='float32'),
trainable=True)
def call(self, inputs): # Defines the computation from inputs to outputs
return tf.matmul(inputs, self.w) + self.b
# Instantiates the layer.
linear_layer = SimpleDense(4)
# This will also call `build(input_shape)` and create the weights.
y = linear_layer(tf.ones((2, 2)))
assert len(linear_layer.weights) == 2
# These weights are trainable, so they're listed in `trainable_weights`:
assert len(linear_layer.trainable_weights) == 2
Note that the method add_weight()
offers a shortcut to create weights:
class SimpleDense(Layer):
def __init__(self, units=32):
super(SimpleDense, self).__init__()
self.units = units
def build(self, input_shape):
self.w = self.add_weight(shape=(input_shape[-1], self.units),
initializer='random_normal',
trainable=True)
self.b = self.add_weight(shape=(self.units,),
initializer='random_normal',
trainable=True)
def call(self, inputs):
return tf.matmul(inputs, self.w) + self.b
Besides trainable weights, updated via backpropagation during training,
layers can also have non-trainable weights. These weights are meant to
be updated manually during call()
. Here's a example layer that computes
the running sum of its inputs:
class ComputeSum(Layer):
def __init__(self, input_dim):
super(ComputeSum, self).__init__()
# Create a non-trainable weight.
self.total = tf.Variable(initial_value=tf.zeros((input_dim,)),
trainable=False)
def call(self, inputs):
self.total.assign_add(tf.reduce_sum(inputs, axis=0))
return self.total
my_sum = ComputeSum(2)
x = tf.ones((2, 2))
y = my_sum(x)
print(y.numpy()) # [2. 2.]
y = my_sum(x)
print(y.numpy()) # [4. 4.]
assert my_sum.weights == [my_sum.total]
assert my_sum.non_trainable_weights == [my_sum.total]
assert my_sum.trainable_weights == []
For more information about creating layers, see the guide Making new Layers and Models via subclassing
weights
propertytf_keras.layers.Layer.weights
Returns the list of all layer variables/weights.
Returns
A list of variables.
trainable_weights
propertytf_keras.layers.Layer.trainable_weights
List of all trainable weights tracked by this layer.
Trainable weights are updated via gradient descent during training.
Returns
A list of trainable variables.
non_trainable_weights
propertytf_keras.layers.Layer.non_trainable_weights
List of all non-trainable weights tracked by this layer.
Non-trainable weights are not updated during training. They are
expected to be updated manually in call()
.
Returns
A list of non-trainable variables.
add_weight
methodLayer.add_weight(
name=None,
shape=None,
dtype=None,
initializer=None,
regularizer=None,
trainable=None,
constraint=None,
use_resource=None,
synchronization=tf.VariableSynchronization.AUTO,
aggregation=tf.VariableSynchronization.NONE,
**kwargs
)
Adds a new variable to the layer.
Arguments
self.dtype
.trainable
cannot be True
if synchronization
is set to ON_READ
.ResourceVariable
or not.
See this guide
for more information.tf.VariableSynchronization
. By default the synchronization is set
to AUTO
and the current DistributionStrategy
chooses when to
synchronize. If synchronization
is set to ON_READ
, trainable
must not be set to True
.tf.VariableAggregation
.getter
,
collections
, experimental_autocast
and caching_device
.Returns
The variable created.
Raises
ON_READ
.trainable
propertytf_keras.layers.Layer.trainable
get_weights
methodLayer.get_weights()
Returns the current weights of the layer, as NumPy arrays.
The weights of a layer represent the state of the layer. This function returns both trainable and non-trainable weight values associated with this layer as a list of NumPy arrays, which can in turn be used to load state into similarly parameterized layers.
For example, a Dense
layer returns a list of two values: the kernel
matrix and the bias vector. These can be used to set the weights of
another Dense
layer:
>>> layer_a = tf.keras.layers.Dense(1,
... kernel_initializer=tf.constant_initializer(1.))
>>> a_out = layer_a(tf.convert_to_tensor([[1., 2., 3.]]))
>>> layer_a.get_weights()
[array([[1.],
[1.],
[1.]], dtype=float32), array([0.], dtype=float32)]
>>> layer_b = tf.keras.layers.Dense(1,
... kernel_initializer=tf.constant_initializer(2.))
>>> b_out = layer_b(tf.convert_to_tensor([[10., 20., 30.]]))
>>> layer_b.get_weights()
[array([[2.],
[2.],
[2.]], dtype=float32), array([0.], dtype=float32)]
>>> layer_b.set_weights(layer_a.get_weights())
>>> layer_b.get_weights()
[array([[1.],
[1.],
[1.]], dtype=float32), array([0.], dtype=float32)]
Returns
Weights values as a list of NumPy arrays.
set_weights
methodLayer.set_weights(weights)
Sets the weights of the layer, from NumPy arrays.
The weights of a layer represent the state of the layer. This function sets the weight values from numpy arrays. The weight values should be passed in the order they are created by the layer. Note that the layer's weights must be instantiated before calling this function, by calling the layer.
For example, a Dense
layer returns a list of two values: the kernel
matrix and the bias vector. These can be used to set the weights of
another Dense
layer:
>>> layer_a = tf.keras.layers.Dense(1,
... kernel_initializer=tf.constant_initializer(1.))
>>> a_out = layer_a(tf.convert_to_tensor([[1., 2., 3.]]))
>>> layer_a.get_weights()
[array([[1.],
[1.],
[1.]], dtype=float32), array([0.], dtype=float32)]
>>> layer_b = tf.keras.layers.Dense(1,
... kernel_initializer=tf.constant_initializer(2.))
>>> b_out = layer_b(tf.convert_to_tensor([[10., 20., 30.]]))
>>> layer_b.get_weights()
[array([[2.],
[2.],
[2.]], dtype=float32), array([0.], dtype=float32)]
>>> layer_b.set_weights(layer_a.get_weights())
>>> layer_b.get_weights()
[array([[1.],
[1.],
[1.]], dtype=float32), array([0.], dtype=float32)]
Arguments
get_weights
).Raises
get_config
methodModel.get_config()
Returns the config of the Model
.
Config is a Python dictionary (serializable) containing the
configuration of an object, which in this case is a Model
. This allows
the Model
to be be reinstantiated later (without its trained weights)
from this configuration.
Note that get_config()
does not guarantee to return a fresh copy of
dict every time it is called. The callers should make a copy of the
returned dict if they want to modify it.
Developers of subclassed Model
are advised to override this method,
and continue to update the dict from super(MyModel, self).get_config()
to provide the proper configuration of this Model
. The default config
will return config dict for init parameters if they are basic types.
Raises NotImplementedError
when in cases where a custom
get_config()
implementation is required for the subclassed model.
Returns
Python dictionary containing the configuration of this Model
.
add_loss
methodLayer.add_loss(losses, **kwargs)
Add loss tensor(s), potentially dependent on layer inputs.
Some losses (for instance, activity regularization losses) may be
dependent on the inputs passed when calling a layer. Hence, when reusing
the same layer on different inputs a
and b
, some entries in
layer.losses
may be dependent on a
and some on b
. This method
automatically keeps track of dependencies.
This method can be used inside a subclassed layer or model's call
function, in which case losses
should be a Tensor or list of Tensors.
Example
class MyLayer(tf.keras.layers.Layer):
def call(self, inputs):
self.add_loss(tf.abs(tf.reduce_mean(inputs)))
return inputs
The same code works in distributed training: the input to add_loss()
is treated like a regularization loss and averaged across replicas
by the training loop (both built-in Model.fit()
and compliant custom
training loops).
The add_loss
method can also be called directly on a Functional Model
during construction. In this case, any loss Tensors passed to this Model
must be symbolic and be able to be traced back to the model's Input
s.
These losses become part of the model's topology and are tracked in
get_config
.
Example
inputs = tf.keras.Input(shape=(10,))
x = tf.keras.layers.Dense(10)(inputs)
outputs = tf.keras.layers.Dense(1)(x)
model = tf.keras.Model(inputs, outputs)
# Activity regularization.
model.add_loss(tf.abs(tf.reduce_mean(x)))
If this is not the case for your loss (if, for example, your loss
references a Variable
of one of the model's layers), you can wrap your
loss in a zero-argument lambda. These losses are not tracked as part of
the model's topology since they can't be serialized.
Example
inputs = tf.keras.Input(shape=(10,))
d = tf.keras.layers.Dense(10)
x = d(inputs)
outputs = tf.keras.layers.Dense(1)(x)
model = tf.keras.Model(inputs, outputs)
# Weight regularization.
model.add_loss(lambda: tf.reduce_mean(d.kernel))
Arguments
losses
propertytf_keras.layers.Layer.losses
List of losses added using the add_loss()
API.
Variable regularization tensors are created when this property is
accessed, so it is eager safe: accessing losses
under a
tf.GradientTape
will propagate gradients back to the corresponding
variables.
Examples
>>> class MyLayer(tf.keras.layers.Layer):
... def call(self, inputs):
... self.add_loss(tf.abs(tf.reduce_mean(inputs)))
... return inputs
>>> l = MyLayer()
>>> l(np.ones((10, 1)))
>>> l.losses
[1.0]
>>> inputs = tf.keras.Input(shape=(10,))
>>> x = tf.keras.layers.Dense(10)(inputs)
>>> outputs = tf.keras.layers.Dense(1)(x)
>>> model = tf.keras.Model(inputs, outputs)
>>> # Activity regularization.
>>> len(model.losses)
0
>>> model.add_loss(tf.abs(tf.reduce_mean(x)))
>>> len(model.losses)
1
>>> inputs = tf.keras.Input(shape=(10,))
>>> d = tf.keras.layers.Dense(10, kernel_initializer='ones')
>>> x = d(inputs)
>>> outputs = tf.keras.layers.Dense(1)(x)
>>> model = tf.keras.Model(inputs, outputs)
>>> # Weight regularization.
>>> model.add_loss(lambda: tf.reduce_mean(d.kernel))
>>> model.losses
[<tf.Tensor: shape=(), dtype=float32, numpy=1.0>]
Returns
A list of tensors.