Skip to content

Conversation

wwwind
Copy link
Contributor

@wwwind wwwind commented Jan 15, 2021

This PR extends our support for clustering the following two user cases:

  1. The user wants to specify that the bias for the dense layer should be clustered as well.
    In this case the user needs to create a new layer derived from Dense and ClusterableLayer and
    provide what is needed to be clustered in the function get_clusterable_weights.
class MyDenseLayer(keras.layers.Dense, clusterable_layer.ClusterableLayer):

  def __init__(self, num_units):
    super().__init__(num_units)

  def get_clusterable_weights(self):
   # Cluster kernel and bias.
   return [('kernel', self.kernel), ('bias', self.bias)]
  1. This user case is for a keras custom layer. We don't support a keras custom layer by default.
    To be able to cluster it, the user needs to derive it from ClusterableLayer and provides two functions:
    get_clusterable_weights, which specifies what should be clustered as in the first user case,
    get_clusterable_algorithm, which is needed to specify the layout of the weight tensor.
    The example is given below:
class MyClusterableLayer(keras.layers.Layer, clusterable_layer.ClusterableLayer):

  def __init__(self, units=32):
    super(MyClusterableLayer, 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=False
   )

  def call(self, inputs):
    return tf.matmul(inputs, self.w) + self.b

  def get_clusterable_weights(self):
    # Cluster only weights 'w'
    return [('w', self.w)]

  def get_clusterable_algorithm(self, weight_name):
     if weight_name == 'w':
       return ClusterableWeightsCA
     else:
       # We don't cluster other weights.
       return None

, where

class ClusterableWeightsCA(clustering_algorithm.AbstractClusteringAlgorithm):

  def get_pulling_indices(self, weight):
    clst_num = self.cluster_centroids.shape[0]
    tiled_weights = tf.tile(tf.expand_dims(weight, axis=2), [1, 1, clst_num])
    tiled_cluster_centroids = tf.tile(
        tf.reshape(self.cluster_centroids, [1, 1, clst_num]),
        [weight.shape[0], weight.shape[1], 1])

    # We find the nearest cluster centroids and store them so that ops can build
    # their kernels upon it
    pulling_indices = tf.argmin(tf.abs(tiled_weights - tiled_cluster_centroids),
                                axis=2)

    return pulling_indices

Both these user cases are added as a mnist test in the new test file: mnist_clusterable_layer_test.py.

@google-cla google-cla bot added the cla: yes PR contributor has signed CLA label Jan 15, 2021
@github-actions github-actions bot added the technique:clustering Regarding tfmot.clustering.keras APIs and docs label Jan 15, 2021
@wwwind wwwind requested review from akarmi and arovir01 January 15, 2021 16:48
Copy link
Contributor

@akarmi akarmi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, and apologies for taking so long to review!

Can you please tidy up the description? The formatting is a bit off and makes it difficult to read. Also, the code snippet for the second use case does not include get_clusterable_algorithm().

cluster_wrapper.ClusterWeights(keras_custom_layer,
**self.params)

>>>>>>> 8fe29ec... MLTOOLS-1031 Customerable layer API.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please, remove!

pass


class MyCustomerableLayer(keras.layers.Dense,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: MyClusterableLayer instead? There are also similar instances in other part of the PR.

layers.Embedding: {'embeddings': DenseWeightsCA},
layers.LocallyConnected1D: {'kernel': ConvolutionalWeightsCA},
layers.LocallyConnected2D: {'kernel': ConvolutionalWeightsCA},
layers.Conv1D: {'kernel': ConvolutionalWeightsCA, 'bias': BiasWeightsCA},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't cluster biases by default. Will this change such a behaviour? It'd be good to have a test for this.

@@ -0,0 +1,249 @@
# Copyright 2021 The TensorFlow Authors. All Rights Reserved.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: please rename to mnist_clusterable_layer_test.py

@wwwind wwwind requested a review from akarmi February 19, 2021 10:40
Copy link
Contributor

@akarmi akarmi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Looks good. Just a minor request.

self.assertGreater(nr_of_unique_weights, NUMBER_OF_CLUSTERS)

# Record the number of unique values of 'bias'
nr_of_bias_weights = _get_number_of_unique_weights(model, -1, 1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, add a similar assertion check for the number of unique bias values to the one for the weights above.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

Copy link
Contributor

@akarmi akarmi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

@akarmi akarmi added ready to pull Working to get PR submitted to internal repository, after which merging to Github happens. and removed ready to pull Working to get PR submitted to internal repository, after which merging to Github happens. labels Feb 25, 2021
@akarmi akarmi self-requested a review February 25, 2021 18:06
Copy link
Contributor

@akarmi akarmi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies, I missed it initially. We need to expose ClusterableLayer in the public API, which will require exposing AbstractClusteringAlgorithm as well. The latter then needs moving out of the clustering_registry.py into its own module, to prevent exposing the implementation guts in the public API, and we should also then clean up clustering_registry.py to remove unused functions, e.g. register_new_implementation(). Any thoughts?

@github-actions github-actions bot added the api-review API review needed label Mar 1, 2021
@wwwind
Copy link
Contributor Author

wwwind commented Mar 1, 2021

Hi @akarmi Please re-review this PR - all comments are addressed. Thanks!

Copy link
Contributor

@akarmi akarmi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks.
@daverim, as this change affects the public API, please review it as well.

@akarmi akarmi requested review from akarmi and daverim March 1, 2021 17:53
self.assertGreater(nr_of_unique_weights, NUMBER_OF_CLUSTERS)

# Record the number of unique values of 'bias'
nr_of_bias_weights = _get_number_of_unique_weights(model, -1, 1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

@wwwind wwwind requested a review from akarmi March 19, 2021 10:04
@akarmi
Copy link
Contributor

akarmi commented Mar 24, 2021

@daverim, any feedback? - we would like to merge this now.

@fredrec fredrec self-requested a review March 29, 2021 07:59
@fredrec fredrec added the ready to pull Working to get PR submitted to internal repository, after which merging to Github happens. label Mar 29, 2021
copybara-service bot pushed a commit that referenced this pull request Apr 13, 2021
@wwwind
Copy link
Contributor Author

wwwind commented Apr 13, 2021

Hi @daverim I updated this PR with the merged changes. I checked the test that is left in this PR locally and it works as expected.
Could we please merge this PR ? Thanks!

@daverim daverim added ready to pull Working to get PR submitted to internal repository, after which merging to Github happens. and removed ready to pull Working to get PR submitted to internal repository, after which merging to Github happens. labels Apr 19, 2021
@copybara-service copybara-service bot merged commit b7d7bce into tensorflow:master Apr 22, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api-review API review needed cla: yes PR contributor has signed CLA ready to pull Working to get PR submitted to internal repository, after which merging to Github happens. technique:clustering Regarding tfmot.clustering.keras APIs and docs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants