From f3ac4d8e3530d4c42cfbcf979cf3cf9ad515a080 Mon Sep 17 00:00:00 2001 From: Abhinav Arora Date: Fri, 27 Oct 2017 16:50:26 -0700 Subject: [PATCH] Adding L1 Decay Regularizer (#5173) --- python/paddle/v2/framework/regularizer.py | 44 ++++++++++++++++++- .../v2/framework/tests/test_regularizer.py | 34 ++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/python/paddle/v2/framework/regularizer.py b/python/paddle/v2/framework/regularizer.py index cc7ebbe97e5..5111ac5566f 100644 --- a/python/paddle/v2/framework/regularizer.py +++ b/python/paddle/v2/framework/regularizer.py @@ -1,6 +1,8 @@ import paddle.v2.framework.framework as framework -__all__ = ['append_regularization_ops', 'L2DecayRegularizer'] +__all__ = [ + 'append_regularization_ops', 'L2DecayRegularizer', 'L1DecayRegularizer' +] def append_regularization_ops(parameters_and_grads): @@ -97,3 +99,43 @@ class L2DecayRegularizer(WeightDecayRegularizer): attrs={"scale": self._regularization_coeff}) return decay + + +class L1DecayRegularizer(WeightDecayRegularizer): + """Implements the L1 Weight Decay Regularization + """ + + def __init__(self, regularization_coeff=0.0): + assert regularization_coeff is not None + super(L1DecayRegularizer, self).__init__() + self._regularization_coeff = regularization_coeff + + def __call__(self, param, block): + """Add L1 weight decay ops to network + + Adds L1 weight decay ops. + L1WeightDecay = reg_coeff * sign(parameter) + + Args: + param: parameter variable for which regularization is applied + block: block in which variable is to be created + + Returns: + new variable for weight decay + """ + assert isinstance(param, framework.Parameter) + assert isinstance(block, framework.Block) + decay = block.create_var( + dtype="float32", shape=param.shape, lod_level=param.lod_level) + # Append sign op + block.append_op( + type='sign', inputs={"X": param}, outputs={"Out": decay}) + + # Append scale op to the output of sign op + block.append_op( + type='scale', + inputs={"X": decay}, + outputs={"Out": decay}, + attrs={"scale": self._regularization_coeff}) + + return decay diff --git a/python/paddle/v2/framework/tests/test_regularizer.py b/python/paddle/v2/framework/tests/test_regularizer.py index 06a892ada19..b21dceb584b 100644 --- a/python/paddle/v2/framework/tests/test_regularizer.py +++ b/python/paddle/v2/framework/tests/test_regularizer.py @@ -39,5 +39,39 @@ class TestL2DecayRegularizer(unittest.TestCase): self.assertEqual(block.ops[-2].type, 'scale') +class TestL1DecayRegularizer(unittest.TestCase): + def test_l2decay_regularizer(self): + program = framework.Program() + block = program.global_block() + mul_x = block.create_parameter( + dtype="float32", + shape=[5, 10], + lod_level=0, + name="mul.x", + regularizer=regularizer.L1DecayRegularizer(0.5)) + self.assertTrue(mul_x.regularizer is not None) + self.assertTrue( + isinstance(mul_x.regularizer, regularizer.L1DecayRegularizer)) + mul_y = block.create_var( + dtype="float32", shape=[10, 8], lod_level=0, name="mul.y") + mul_out = block.create_var( + dtype="float32", shape=[5, 8], lod_level=0, name="mul.out") + block.append_op( + type="mul", + inputs={"X": mul_x, + "Y": mul_y}, + outputs={"Out": mul_out}, + attrs={"x_num_col_dims": 1}) + params_grads = append_backward_ops(mul_out) + self.assertEqual(len(params_grads), 1) + count_ops = len(block.ops) + params_grads = optimizer.append_regularization_ops(params_grads) + self.assertEqual(len(params_grads), 1) + self.assertEqual(len(block.ops), count_ops + 3) + self.assertEqual(block.ops[-1].type, 'elementwise_add') + self.assertEqual(block.ops[-2].type, 'scale') + self.assertEqual(block.ops[-3].type, 'sign') + + if __name__ == '__main__': unittest.main() -- GitLab