diff --git a/paddle/fluid/API.spec b/paddle/fluid/API.spec index 33e0c7180e2e7792d68fe5bb1995a3c72afef487..5cfa91528a32e983ff5f55c3be87bfa53779b310 100644 --- a/paddle/fluid/API.spec +++ b/paddle/fluid/API.spec @@ -407,6 +407,18 @@ paddle.fluid.layers.piecewise_decay (ArgSpec(args=['boundaries', 'values'], vara paddle.fluid.layers.noam_decay (ArgSpec(args=['d_model', 'warmup_steps'], varargs=None, keywords=None, defaults=None), ('document', 'fd57228fb76195e66bbcc8d8e42c494d')) paddle.fluid.layers.cosine_decay (ArgSpec(args=['learning_rate', 'step_each_epoch', 'epochs'], varargs=None, keywords=None, defaults=None), ('document', 'f0d65d8c89d0fe78051ca689daa15e35')) paddle.fluid.layers.linear_lr_warmup (ArgSpec(args=['learning_rate', 'warmup_steps', 'start_lr', 'end_lr'], varargs=None, keywords=None, defaults=None), ('document', 'dc7292c456847ba41cfd318e9f7f4363')) +paddle.fluid.layers.Uniform ('paddle.fluid.layers.distributions.Uniform', ('document', 'af70e7003f437e7a8a9e28cded35c433')) +paddle.fluid.layers.Uniform.__init__ (ArgSpec(args=['self', 'low', 'high'], varargs=None, keywords=None, defaults=None), ('document', '6adf97f83acf6453d4a6a4b1070f3754')) +paddle.fluid.layers.Uniform.entropy (ArgSpec(args=['self'], varargs=None, keywords=None, defaults=None), ('document', 'ba59f9ce77af3c93e2b4c8af1801a24e')) +paddle.fluid.layers.Uniform.kl_divergence (ArgSpec(args=['self', 'other'], varargs=None, keywords=None, defaults=None), ('document', '3baee52abbed82d47e9588d9dfe2f42f')) +paddle.fluid.layers.Uniform.log_prob (ArgSpec(args=['self', 'value'], varargs=None, keywords=None, defaults=None), ('document', 'b79091014ceaffb6a7372a198a341c23')) +paddle.fluid.layers.Uniform.sample (ArgSpec(args=['self', 'shape', 'seed'], varargs=None, keywords=None, defaults=(0,)), ('document', 'adac334af13f6984e991b3ecf12b8cb7')) +paddle.fluid.layers.Normal ('paddle.fluid.layers.distributions.Normal', ('document', '3265262d0d8b3b32c6245979a5cdced9')) +paddle.fluid.layers.Normal.__init__ (ArgSpec(args=['self', 'loc', 'scale'], varargs=None, keywords=None, defaults=None), ('document', '6adf97f83acf6453d4a6a4b1070f3754')) +paddle.fluid.layers.Normal.entropy (ArgSpec(args=['self'], varargs=None, keywords=None, defaults=None), ('document', 'd2db47b1e62c037a2570fc526b93f518')) +paddle.fluid.layers.Normal.kl_divergence (ArgSpec(args=['self', 'other'], varargs=None, keywords=None, defaults=None), ('document', '2e8845cdf1129647e6fa6e816876cd3b')) +paddle.fluid.layers.Normal.log_prob (ArgSpec(args=['self', 'value'], varargs=None, keywords=None, defaults=None), ('document', 'b79091014ceaffb6a7372a198a341c23')) +paddle.fluid.layers.Normal.sample (ArgSpec(args=['self', 'shape', 'seed'], varargs=None, keywords=None, defaults=(0,)), ('document', 'adac334af13f6984e991b3ecf12b8cb7')) paddle.fluid.contrib.InitState ('paddle.fluid.contrib.decoder.beam_search_decoder.InitState', ('document', '3afd1f84232718e628e9e566941c5f05')) paddle.fluid.contrib.InitState.__init__ (ArgSpec(args=['self', 'init', 'shape', 'value', 'init_boot', 'need_reorder', 'dtype'], varargs=None, keywords=None, defaults=(None, None, 0.0, None, False, 'float32')), ('document', '6adf97f83acf6453d4a6a4b1070f3754')) paddle.fluid.contrib.StateCell ('paddle.fluid.contrib.decoder.beam_search_decoder.StateCell', ('document', 'ecd0066c02867d445d7b461e28220c50')) diff --git a/python/paddle/fluid/layers/__init__.py b/python/paddle/fluid/layers/__init__.py index 31effea3788c2dd1b0dab6f62194d27a2d7ce7e3..d17636d6d54f9c8b00f289b9af961553651b775e 100644 --- a/python/paddle/fluid/layers/__init__.py +++ b/python/paddle/fluid/layers/__init__.py @@ -34,6 +34,7 @@ from . import metric_op from .metric_op import * from .learning_rate_scheduler import * from .collective import * +from .distributions import * __all__ = [] __all__ += nn.__all__ @@ -45,3 +46,4 @@ __all__ += device.__all__ __all__ += detection.__all__ __all__ += metric_op.__all__ __all__ += learning_rate_scheduler.__all__ +__all__ += distributions.__all__ diff --git a/python/paddle/fluid/layers/distributions.py b/python/paddle/fluid/layers/distributions.py new file mode 100644 index 0000000000000000000000000000000000000000..51d134179bf4cb18fedf3e332646b9cd7cdf8fea --- /dev/null +++ b/python/paddle/fluid/layers/distributions.py @@ -0,0 +1,398 @@ +# Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import print_function + +from . import control_flow +from . import tensor +from . import ops +from . import nn +import math +import numpy as np +import warnings + +__all__ = ['Uniform', 'Normal'] + + +class Distribution(object): + """ + Distribution is the abstract base class for probability distributions. + """ + + def sample(self): + """Sampling from the distribution.""" + raise NotImplementedError + + def entropy(self): + """The entropy of the distribution.""" + raise NotImplementedError + + def kl_divergence(self, other): + """The KL-divergence between self distributions and other.""" + raise NotImplementedError + + def log_prob(self, value): + """Log probability density/mass function.""" + raise NotImplementedError + + def _validate_args(self, *args): + """ + Argument validation for distribution args + Args: + value (float, list, numpy.ndarray, Variable) + Raises + ValueError: if one argument is Variable, all arguments should be Variable + """ + is_variable = False + is_number = False + for arg in args: + if isinstance(arg, tensor.Variable): + is_variable = True + else: + is_number = True + + if is_variable and is_number: + raise ValueError( + 'if one argument is Variable, all arguments should be Variable') + + return is_variable + + def _to_variable(self, *args): + """ + Argument convert args to Variable + + Args: + value (float, list, numpy.ndarray, Variable) + Returns: + Variable of args. + """ + numpy_args = [] + variable_args = [] + tmp = 0. + + for arg in args: + valid_arg = False + for cls in [float, list, np.ndarray, tensor.Variable]: + if isinstance(arg, cls): + valid_arg = True + break + assert valid_arg, "type of input args must be float, list, numpy.ndarray or Variable." + if isinstance(arg, float): + arg = np.zeros(1) + arg + arg_np = np.array(arg) + arg_dtype = arg_np.dtype + if str(arg_dtype) not in ['float32']: + warnings.warn( + "data type of argument only support float32, your argument will be convert to float32." + ) + arg_np = arg_np.astype('float32') + tmp = tmp + arg_np + numpy_args.append(arg_np) + + dtype = tmp.dtype + for arg in numpy_args: + arg_broadcasted, _ = np.broadcast_arrays(arg, tmp) + arg_variable = tensor.create_tensor(dtype=dtype) + tensor.assign(arg_broadcasted, arg_variable) + variable_args.append(arg_variable) + + return tuple(variable_args) + + +class Uniform(Distribution): + """Uniform distribution with `low` and `high` parameters. + + Mathematical Details + + The probability density function (pdf) is, + + .. math:: + + pdf(x; a, b) = \\frac{1}{Z}, \ a <=x 0): + scale_np = np.random.randn(batch_size, dims).astype('float32') + while not np.all(other_scale_np > 0): + other_scale_np = np.random.randn(batch_size, dims).astype('float32') + return loc_np, other_loc_np, loc_float, scale_float, other_loc_float, \ + other_scale_float, scale_np, other_scale_np, values_np + + def test_normal_distribution(self, batch_size=2, dims=3, tolerance=1e-6): + test_program = fluid.Program() + loc_np, other_loc_np, loc_float, scale_float, other_loc_float, other_scale_float, scale_np, other_scale_np, values_np = self.get_normal_random_input( + batch_size, dims) + + feed_vars, fetch_list = self.build_normal_program( + test_program, batch_size, dims, loc_float, scale_float, + other_loc_float, other_scale_float, scale_np, other_scale_np, + loc_np, other_loc_np, values_np) + self.executor.run(fluid.default_startup_program()) + + np_normal_float = NormalNumpy(loc_float, scale_float) + np_other_normal_float = NormalNumpy(other_loc_float, other_scale_float) + np_normal_float_np_broadcast = NormalNumpy(loc_float, scale_np) + np_other_normal_float_np_broadcast = NormalNumpy(other_loc_float, + other_scale_np) + np_normal = NormalNumpy(loc_np, scale_np) + np_other_normal = NormalNumpy(other_loc_np, other_scale_np) + + gt_sample_float = np_normal_float.sample([batch_size, dims]) + gt_sample_float_np_broadcast = np_normal_float_np_broadcast.sample( + [batch_size, dims]) + gt_sample_np = np_normal.sample([batch_size, dims]) + gt_entropy_float = np_normal_float.entropy() + gt_entropy_float_np_broadcast = np_normal_float_np_broadcast.entropy() + gt_entropy = np_normal.entropy() + gt_lp_float_np_broadcast = np_normal_float_np_broadcast.log_prob( + values_np) + gt_lp = np_normal.log_prob(values_np) + gt_kl_float = np_normal_float.kl_divergence(np_other_normal_float) + gt_kl_float_np_broadcast = np_normal_float_np_broadcast.kl_divergence( + np_other_normal_float_np_broadcast) + gt_kl = np_normal.kl_divergence(np_other_normal) + + [ + output_sample_float, output_sample_float_np_broadcast, + output_sample_np, output_sample_variable, output_entropy_float, + output_entropy_float_np_broadcast, output_entropy_np, + output_entropy_variable, output_lp_float_np_broadcast, output_lp_np, + output_lp_variable, output_kl_float, output_kl_float_np_broadcast, + output_kl_np, output_kl_variable + ] = self.executor.run(program=test_program, + feed=feed_vars, + fetch_list=fetch_list) + + np.testing.assert_allclose( + output_sample_float.shape, gt_sample_float.shape, rtol=tolerance) + np.testing.assert_allclose( + output_sample_float_np_broadcast.shape, + gt_sample_float_np_broadcast.shape, + rtol=tolerance) + np.testing.assert_allclose( + output_sample_np.shape, gt_sample_np.shape, rtol=tolerance) + np.testing.assert_allclose( + output_sample_variable.shape, gt_sample_np.shape, rtol=tolerance) + np.testing.assert_allclose( + output_entropy_float, gt_entropy_float, rtol=tolerance) + np.testing.assert_allclose( + output_entropy_float_np_broadcast, + gt_entropy_float_np_broadcast, + rtol=tolerance) + np.testing.assert_allclose( + output_entropy_np, gt_entropy, rtol=tolerance) + np.testing.assert_allclose( + output_entropy_variable, gt_entropy, rtol=tolerance) + np.testing.assert_allclose( + output_lp_float_np_broadcast, + gt_lp_float_np_broadcast, + rtol=tolerance) + np.testing.assert_allclose(output_lp_np, gt_lp, rtol=tolerance) + np.testing.assert_allclose(output_lp_variable, gt_lp, rtol=tolerance) + np.testing.assert_allclose(output_kl_float, gt_kl_float, rtol=tolerance) + np.testing.assert_allclose( + output_kl_float_np_broadcast, + gt_kl_float_np_broadcast, + rtol=tolerance) + np.testing.assert_allclose(output_kl_np, gt_kl, rtol=tolerance) + np.testing.assert_allclose(output_kl_variable, gt_kl, rtol=tolerance) + + def build_uniform_program(self, test_program, batch_size, dims, low_float, + high_float, high_np, low_np, values_np): + with fluid.program_guard(test_program): + low = layers.data(name='low', shape=[dims], dtype='float32') + high = layers.data(name='high', shape=[dims], dtype='float32') + + values = layers.data(name='values', shape=[dims], dtype='float32') + + uniform_float = Uniform(low_float, high_float) + uniform_float_np_broadcast = Uniform(low_float, high_np) + uniform_np = Uniform(low_np, high_np) + uniform_variable = Uniform(low, high) + + sample_float = uniform_float.sample([batch_size, dims]) + sample_float_np_broadcast = uniform_float_np_broadcast.sample( + [batch_size, dims]) + sample_np = uniform_np.sample([batch_size, dims]) + sample_variable = uniform_variable.sample([batch_size, dims]) + + entropy_float = uniform_float.entropy() + entropy_float_np_broadcast = uniform_float_np_broadcast.entropy() + entropy_np = uniform_np.entropy() + entropy_variable = uniform_variable.entropy() + + lp_float_np_broadcast = uniform_float_np_broadcast.log_prob(values) + lp_np = uniform_np.log_prob(values) + lp_variable = uniform_variable.log_prob(values) + + fetch_list = [ + sample_float, sample_float_np_broadcast, sample_np, sample_variable, + entropy_float, entropy_float_np_broadcast, entropy_np, + entropy_variable, lp_float_np_broadcast, lp_np, lp_variable + ] + feed_vars = {'low': low_np, 'high': high_np, 'values': values_np} + return feed_vars, fetch_list + + def test_uniform_distribution(self, batch_size=2, dims=3, tolerance=1e-6): + test_program = fluid.Program() + + low_np = np.random.randn(batch_size, dims).astype('float32') + low_float = np.random.uniform(-2, 1) + high_float = np.random.uniform(1, 3) + high_np = np.random.uniform(-5.0, 5.0, + (batch_size, dims)).astype('float32') + values_np = np.random.randn(batch_size, dims).astype('float32') + + feed_vars, fetch_list = self.build_uniform_program( + test_program, batch_size, dims, low_float, high_float, high_np, + low_np, values_np) + + self.executor.run(fluid.default_startup_program()) + + np_uniform_float = UniformNumpy(low_float, high_float) + np_uniform_float_np_broadcast = UniformNumpy(low_float, high_np) + np_uniform = UniformNumpy(low_np, high_np) + + gt_sample_float = np_uniform_float.sample([batch_size, dims]) + gt_sample_float_np_broadcast = np_uniform_float_np_broadcast.sample( + [batch_size, dims]) + gt_sample_np = np_uniform.sample([batch_size, dims]) + gt_entropy_float = np_uniform_float.entropy() + gt_entropy_float_np_broadcast = np_uniform_float_np_broadcast.entropy() + gt_entropy = np_uniform.entropy() + gt_lp_float_np_broadcast = np_uniform_float_np_broadcast.log_prob( + values_np) + gt_lp = np_uniform.log_prob(values_np) + + # result calculated by paddle + [ + output_sample_float, output_sample_float_np_broadcast, + output_sample_np, output_sample_variable, output_entropy_float, + output_entropy_float_np_broadcast, output_entropy_np, + output_entropy_variable, output_lp_float_np_broadcast, output_lp_np, + output_lp_variable + ] = self.executor.run(program=test_program, + feed=feed_vars, + fetch_list=fetch_list) + + np.testing.assert_allclose( + output_sample_float.shape, gt_sample_float.shape, rtol=tolerance) + np.testing.assert_allclose( + output_sample_float_np_broadcast.shape, + gt_sample_float_np_broadcast.shape, + rtol=tolerance) + np.testing.assert_allclose( + output_sample_np.shape, gt_sample_np.shape, rtol=tolerance) + np.testing.assert_allclose( + output_sample_variable.shape, gt_sample_np.shape, rtol=tolerance) + np.testing.assert_allclose( + output_entropy_float, gt_entropy_float, rtol=tolerance) + np.testing.assert_allclose( + output_entropy_float_np_broadcast, + gt_entropy_float_np_broadcast, + rtol=tolerance) + np.testing.assert_allclose( + output_entropy_np, gt_entropy, rtol=tolerance) + np.testing.assert_allclose( + output_entropy_variable, gt_entropy, rtol=tolerance) + np.testing.assert_allclose( + output_lp_float_np_broadcast, + gt_lp_float_np_broadcast, + rtol=tolerance) + np.testing.assert_allclose(output_lp_np, gt_lp, rtol=tolerance) + np.testing.assert_allclose(output_lp_variable, gt_lp, rtol=tolerance) + + +if __name__ == '__main__': + unittest.main()