in tensorflow_model_optimization/python/core/common/keras/compression/internal/optimize.py [0:0]
def create_layer_for_training(layer, algorithm):
"""Internal API to create layer for training with weight compression."""
# TODO(tfmot): move these checks to public API for
# visibility.
if not isinstance(algorithm, object):
raise ValueError('`_create_layer_for_training` requires `algorithm` '
'to be an instantiated object, as opposed '
'to the class itself.')
# Currently only supports a layer being built. The non-built
# case may work fine as is, but it needs to be tested, together
# with the followup API for exporting the model when the training
# and inference graphs differ.
if not layer.built:
raise ValueError('`_create_layer_for_training` requires `layer` to '
'be built.')
input_shape = layer.input_shape
compressible_weights = algorithm.get_compressible_weights(layer)
# Clone layer for two reasons:
#
# 1) Avoid unnecessary variable creation which undoes the benefits of
# compression. For instance, if we factorize `kernel` into `a` and `b`,
# since `a` and `b` collectively take less space than `kernel`, we
# no longer want to `kernel` to take up space as a variable.
#
# The design depends on replacing the layer's `add_weight`
# method to prevent variable creation, before `add_weight` is called
# in the layer's `build`. Since the layer is built already, we undo
# this by cloning the layer.
#
# 2) The unoptimized layer and the optimized layer are now independent
# of each other and training one will not affect the other.
#
# TODO(tfmot): consider if it's okay to avoid this complexity during training
# and only add it during inference, which is when model size really matters.
# TODO(tfmot): handle custom Keras layer case.
cloned_layer = layer.__class__.from_config(layer.get_config())
# TODO(tfmot): We concider variable name form is layer_name/variable_name.
layer_name = layer.name
compressible_weights_name = []
for compressible_weight in compressible_weights:
name = compressible_weight.name
if name.startswith(layer_name):
name = name[len(layer_name)+1:]
name = name.split(':')[0]
compressible_weights_name.append(name)
# TODO(tfmot): consider if this manner of handling build hinders
# support for subclassed models in trying to set the attributes
# that are layers while ensuring that the underlying trainable weights
# have been created already.
wrapped_layer = _TrainingWrapper(
cloned_layer,
algorithm,
compressible_weights_name)
if compressible_weights:
# Set pretrained weight values.
wrapped_layer.build(input_shape)
training_weights = _map_to_training_weights(
algorithm,
layer,
compressible_weights)
wrapped_layer.set_weights(
[weight.numpy() for weight in training_weights])
return wrapped_layer