Makes Keras Network (which extends from base_layer) actually call the base_layer's __init__. More work is needed to clean up the class hierarchy, but this should at least reduce a lot of the need for hasattr/getattrs in various places when models and layers mismatch.
The deleted lines are done by the base_layer's constructor.
PiperOrigin-RevId: 292428876
Change-Id: Ie765f1f0d771e0b7897dacd385164ca117e7a1ba
diff --git a/tensorflow/python/keras/engine/base_layer.py b/tensorflow/python/keras/engine/base_layer.py
index 50aad3e..2a6e573 100644
--- a/tensorflow/python/keras/engine/base_layer.py
+++ b/tensorflow/python/keras/engine/base_layer.py
@@ -195,7 +195,7 @@
# the layer's weights.
self.built = False
# Provides information about which inputs are compatible with the layer.
- self.input_spec = None
+ self._input_spec = None
self.supports_masking = False
self._supports_ragged_inputs = False
@@ -216,6 +216,10 @@
# added using the `add_metric` API.
self._metrics = []
+ # Both graph and subclassed networks have a dtype policy. For graph
+ # networks, the policy's compute and variable dtypes are ignored, but other
+ # fields, like the loss scale, are used by Models. For subclassed networks,
+ # the compute and variable dtypes are used as like any ordinary layer.
self._set_dtype_policy(dtype)
# Boolean indicating whether the layer automatically casts its inputs to the
# layer's compute_dtype.
@@ -223,16 +227,21 @@
base_layer_utils.v2_dtype_behavior_enabled())
# Dependencies tracked via attribute assignment.
+ # All layers in order of horizontal graph traversal.
+ # Entries are unique. For models includes input and output layers.
self._maybe_create_attribute('_layers', [])
# These lists will be filled via successive calls
# to self._add_inbound_node().
+ # Used in symbolic mode only, only in conjunction with graph-networks
self._inbound_nodes = []
self._outbound_nodes = []
self._init_call_fn_args()
# Whether the `call` method can be used to build a TF graph without issues.
+ # This attribute has no effect if the model is created using the Functional
+ # API. Instead, `model.dynamic` is determined based on the internal layers.
self._dynamic = dynamic
# Manage input shape information if passed.
@@ -250,10 +259,7 @@
self._batch_input_shape = batch_input_shape
# Manage initial weight values if passed.
- if 'weights' in kwargs:
- self._initial_weights = kwargs['weights']
- else:
- self._initial_weights = None
+ self._initial_weights = kwargs.get('weights', None)
def build(self, input_shape):
"""Creates the variables of the layer (optional, for subclass implementers).
@@ -2199,7 +2205,7 @@
self.built = True
# Optionally load weight values specified at layer instantiation.
- if getattr(self, '_initial_weights', None) is not None:
+ if self._initial_weights is not None:
if ops.executing_eagerly_outside_functions():
with ops.init_scope():
# Using `init_scope` since we want variable assignment in
diff --git a/tensorflow/python/keras/engine/network.py b/tensorflow/python/keras/engine/network.py
index 05b7a9b..21f6435 100644
--- a/tensorflow/python/keras/engine/network.py
+++ b/tensorflow/python/keras/engine/network.py
@@ -24,7 +24,6 @@
import itertools
import json
import os
-import threading
import numpy as np
import six
@@ -198,36 +197,17 @@
generic_utils.validate_kwargs(kwargs, {'trainable', 'dtype', 'dynamic',
'autocast'})
- # Object to store all thread local layer properties.
- self._thread_local = threading.local()
+ super(Network, self).__init__(name=name, **kwargs)
- self._init_set_name(name, zero_based=True)
- self._activity_regularizer = None
- # This acts just like the `trainable` attribute of any layer instance.
- self._trainable = kwargs.get('trainable', True)
- # This attribute has no effect if the model is created using the Functional
- # API. Instead, `model.dynamic` is determined based on the internal layers.
- self._dynamic = kwargs.get('dynamic', False)
self._is_compiled = False
- self._layers = []
# This is True for Sequential networks and Functional networks.
self._compute_output_and_mask_jointly = False
- self.supports_masking = False
if not hasattr(self, 'optimizer'):
# Don't reset optimizer if already set.
self.optimizer = None
- # Private attributes to implement compatibility with Layer.
- self._maybe_create_attribute('_trainable_weights', [])
- self._maybe_create_attribute('_non_trainable_weights', [])
- self._updates = [] # Used in symbolic mode only.
- self._losses = []
- self._callable_losses = []
- # A list of metric instances corresponding to the symbolic metric tensors
- # added using the `add_metric` API.
- self._metrics = []
self._scope = None # Never used.
self._reuse = None # Never used.
if context.executing_eagerly():
@@ -235,20 +215,6 @@
else:
self._graph = ops.get_default_graph() # Used in symbolic mode only.
- # Both graph and subclassed networks have a dtype policy. For graph
- # networks, the policy's compute and variable dtypes are ignored, but other
- # fields, like the loss scale, are used by Models. For subclassed networks,
- # the compute and variable dtypes are used as like any ordinary layer.
- self._set_dtype_policy(kwargs.get('dtype', None))
-
- # All layers in order of horizontal graph traversal.
- # Entries are unique. Includes input and output layers.
- self._maybe_create_attribute('_layers', [])
-
- # Used in symbolic mode only, only in conjunction with graph-networks
- self._outbound_nodes = []
- self._inbound_nodes = []
-
self._trackable_saver = (
trackable_utils.saver_with_op_caching(self))