Repository: larq/larq

Issue:
Inconsistent quantiser names
This is very minor and I'm very happy for this to be a `wontfix`.

At the moment two out of eight quantizers have a "Quantizer" suffix:

<img width="251" alt="image" src="https://user-images.githubusercontent.com/7688302/77927969-c04f2400-729f-11ea-8e3d-d04c8d85367f.png">
It seems to me it should be all of them with the suffix or none of them with the suffix. We could potentially standardise on one version but have an alias to the other version.


Discussion:
I have a slight preference to dropping the suffixes for the two that have them, but no strong opinion. Also in favor of standardizing.
I agree, I'm in favour of standardising as well :+1:
I think dropping the suffix makes the most sense since the quantizers will likely be used as `lq.quantizers.*`. 
Would you want to add an alias for the two that would change so that this wouldn't be a breaking change?
> Would you want to add an alias for the two that would change so that this wouldn't be a breaking change?

I think I'd prefer that for now, since it's not much work.
We can remove the alias for good when we have to make some breaking changes elsewhere.

Resolving patch:
diff --git a/larq/optimizers.py b/larq/optimizers.py
--- a/larq/optimizers.py
+++ b/larq/optimizers.py
@@ -20,7 +20,7 @@
 
 !!! example
     ```python
-    no_op_quantizer = lq.quantizers.NoOpQuantizer(precision=1)
+    no_op_quantizer = lq.quantizers.NoOp(precision=1)
     layer = lq.layers.QuantDense(16, kernel_quantizer=no_op_quantizer)
 
     case_optimizer = lq.optimizers.CaseOptimizer(
@@ -243,11 +243,11 @@ class Bop(tf.keras.optimizers.Optimizer):
 
     !!! warning
         The `is_binary_variable` check of this optimizer will only target variables that
-        have been explicitly marked as being binary using `NoOpQuantizer(precision=1)`.
+        have been explicitly marked as being binary using `NoOp(precision=1)`.
 
     !!! example
         ```python
-        no_op_quantizer = lq.quantizers.NoOpQuantizer(precision=1)
+        no_op_quantizer = lq.quantizers.NoOp(precision=1)
         layer = lq.layers.QuantDense(16, kernel_quantizer=no_op_quantizer)
 
         optimizer = lq.optimizers.CaseOptimizer(
diff --git a/larq/quantizers.py b/larq/quantizers.py
--- a/larq/quantizers.py
+++ b/larq/quantizers.py
@@ -52,14 +52,16 @@
 from larq import context, math, metrics as lq_metrics, utils
 
 __all__ = [
-    "SteSign",
     "ApproxSign",
-    "MagnitudeAwareSign",
-    "SwishSign",
-    "SteTern",
-    "SteHeaviside",
+    "DoReFa",
     "DoReFaQuantizer",
+    "MagnitudeAwareSign",
+    "NoOp",
     "NoOpQuantizer",
+    "SteHeaviside",
+    "SteSign",
+    "SteTern",
+    "SwishSign",
 ]
 
 
@@ -166,7 +168,7 @@ def non_trainable_weights(self):
 
 
 @utils.register_keras_custom_object
-class NoOpQuantizer(BaseQuantizer):
+class NoOp(BaseQuantizer):
     r"""Instantiates a serializable no-op quantizer.
 
     \\[
@@ -204,6 +206,11 @@ def get_config(self):
         return {**super().get_config(), "precision": self.precision}
 
 
+# `NoOp` used to be called `NoOpQuantizer`; this alias is for
+# backwards-compatibility.
+NoOpQuantizer = NoOp
+
+
 @utils.register_alias("ste_sign")
 @utils.register_keras_custom_object
 class SteSign(BaseQuantizer):
@@ -508,7 +515,7 @@ def get_config(self):
 
 @utils.register_alias("dorefa_quantizer")
 @utils.register_keras_custom_object
-class DoReFaQuantizer(BaseQuantizer):
+class DoReFa(BaseQuantizer):
     r"""Instantiates a serializable k_bit quantizer as in the DoReFa paper.
 
     \\[
@@ -529,7 +536,7 @@ class DoReFaQuantizer(BaseQuantizer):
     \end{cases}\\]
 
     ```plot-activation
-    quantizers.DoReFaQuantizer
+    quantizers.DoReFa
     ```
 
     # Arguments
@@ -566,6 +573,11 @@ def get_config(self):
         return {**super().get_config(), "k_bit": self.precision}
 
 
+# `DoReFa` used to be called `DoReFaQuantizer`; this alias is for
+# backwards-compatibility.
+DoReFaQuantizer = DoReFa
+
+
 Quantizer = Union[tf.keras.layers.Layer, Callable[[tf.Tensor], tf.Tensor]]
 
 


Test patch:
diff --git a/larq/optimizers_test.py b/larq/optimizers_test.py
--- a/larq/optimizers_test.py
+++ b/larq/optimizers_test.py
@@ -94,7 +94,7 @@ def test_missing_default(self):
                     lq.layers.QuantDense(
                         64,
                         input_quantizer="ste_sign",
-                        kernel_quantizer=lq.quantizers.NoOpQuantizer(precision=1),
+                        kernel_quantizer=lq.quantizers.NoOp(precision=1),
                         activation="relu",
                     ),
                     tf.keras.layers.Dense(10, activation="softmax"),
@@ -145,7 +145,7 @@ def test_weights(self):
                 lq.layers.QuantDense(
                     64,
                     input_quantizer="ste_sign",
-                    kernel_quantizer=lq.quantizers.NoOpQuantizer(precision=1),
+                    kernel_quantizer=lq.quantizers.NoOp(precision=1),
                     activation="relu",
                 ),
                 tf.keras.layers.Dense(10, activation="softmax"),
diff --git a/larq/quantizers_test.py b/larq/quantizers_test.py
--- a/larq/quantizers_test.py
+++ b/larq/quantizers_test.py
@@ -53,12 +53,12 @@ def test_serialization(self, module, name, ref_cls):
         assert type(fn.precision) == int
 
     def test_noop_serialization(self):
-        fn = lq.quantizers.get(lq.quantizers.NoOpQuantizer(precision=1))
-        assert fn.__class__ == lq.quantizers.NoOpQuantizer
+        fn = lq.quantizers.get(lq.quantizers.NoOp(precision=1))
+        assert fn.__class__ == lq.quantizers.NoOp
         assert fn.precision == 1
         config = lq.quantizers.serialize(fn)
         fn = lq.quantizers.deserialize(config)
-        assert fn.__class__ == lq.quantizers.NoOpQuantizer
+        assert fn.__class__ == lq.quantizers.NoOp
         assert fn.precision == 1
 
     def test_invalid_usage(self):
@@ -217,7 +217,7 @@ def test_ternarization_with_ternary_weight_networks(self):
 
     def test_dorefa_quantize(self):
         x = tf.keras.backend.placeholder(ndim=2)
-        f = tf.keras.backend.function([x], [lq.quantizers.DoReFaQuantizer(2)(x)])
+        f = tf.keras.backend.function([x], [lq.quantizers.DoReFa(2)(x)])
         real_values = testing_utils.generate_real_values_with_zeros()
         result = f([real_values])[0]
         k_bit = 2
@@ -333,7 +333,7 @@ def ste_grad(x):
         x = testing_utils.generate_real_values_with_zeros(shape=(8, 3, 3, 16))
         tf_x = tf.Variable(x)
         with tf.GradientTape() as tape:
-            activation = lq.quantizers.DoReFaQuantizer(2)(tf_x)
+            activation = lq.quantizers.DoReFa(2)(tf_x)
         grad = tape.gradient(activation, tf_x)
         np.testing.assert_allclose(grad.numpy(), ste_grad(x))
 
@@ -347,7 +347,7 @@ def ste_grad(x):
         ("swish_sign", lq.quantizers.SwishSign),
         ("magnitude_aware_sign", lq.quantizers.MagnitudeAwareSign),
         ("ste_tern", lq.quantizers.SteTern),
-        ("dorefa_quantizer", lq.quantizers.DoReFaQuantizer),
+        ("dorefa_quantizer", lq.quantizers.DoReFa),
     ],
 )
 def test_metrics(quantizer):
@@ -406,3 +406,8 @@ def test_get_kernel_quantizer_accepts_function():
     custom_quantizer = lq.quantizers.get_kernel_quantizer(lambda x: x)
     assert callable(custom_quantizer)
     assert not hasattr(custom_quantizer, "_custom_metrics")
+
+
+def test_backwards_compat_aliases():
+    assert lq.quantizers.DoReFaQuantizer == lq.quantizers.DoReFa
+    assert lq.quantizers.NoOpQuantizer == lq.quantizers.NoOp