Skip to content

Commit

Permalink
[add] Beta distribution
Browse files Browse the repository at this point in the history
  • Loading branch information
YoshikawaMasashi committed Apr 27, 2018
1 parent d1f78a3 commit 93bb349
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 0 deletions.
122 changes: 122 additions & 0 deletions chainer/distributions/Beta.py
@@ -0,0 +1,122 @@
import chainer
from chainer.backends import cuda
from chainer import Distribution
from chainer.functions.math import digamma
from chainer.functions.math import exponential
from chainer.functions.math import lgamma
import numpy


class Beta(Distribution):

"""Beta Distribution.
Args:
a(:class:`~chainer.Variable` or :class:`numpy.ndarray` or \
:class:`cupy.ndarray`): Parameter of distribution.
b(:class:`~chainer.Variable` or :class:`numpy.ndarray` or \
:class:`cupy.ndarray`): Parameter of distribution.
"""

def __init__(self, a, b):
self.a = a
self.b = b

def __copy__(self):
return self._copy_to(Beta(self.a, self.b))

@property
def batch_shape(self):
return self.a.shape

@property
def entropy(self):
"""Returns entropy.
Returns:
Output Variable representing entropy.
"""
return lgamma.lgamma(self.a) + lgamma.lgamma(self.b) \
- lgamma.lgamma(self.a + self.b) \
- (self.a - 1) * digamma.digamma(self.a) \
- (self.b - 1) * digamma.digamma(self.b) \
+ (self.a + self.b - 2) * digamma.digamma(self.a + self.b)

@property
def event_shape(self):
return ()

@property
def _is_gpu(self):
return isinstance(self.a, cuda.ndarray)

def log_prob(self, x):
"""Returns logarithm logarithm of probability for a input variable.
Args:
x: Input variable representing a random variable.
Returns:
Output variable representing logarithm of probability.
"""
return (self.a - 1) * exponential.log(x) \
+ (self.b - 1) * exponential.log(1 - x) \
- lgamma.lgamma(self.a) - lgamma.lgamma(self.b) \
+ lgamma.lgamma(self.a + self.b)

@property
def mean(self):
"""Returns mean value.
Returns:
~chainer.Variable: Output variable representing mean value.
"""
return self.a / (self.a + self.b)

def _sample_n(self, n):
"""Samples from this distribution.
Args:
n(`int`): Sampling size.
Returns:
~chainer.Variable: Output variable representing sampled random
variable.
"""
if self._is_gpu:
eps = numpy.random.beta(
cuda.to_cpu(self.a.data), cuda.to_cpu(self.b.data),
size=(n,)+self.a.shape).astype(numpy.float32)
eps = cuda.to_gpu(eps, cuda.get_device_from_array(self.a).id)
else:
eps = numpy.random.beta(
self.a.data, self.b.data,
size=(n,)+self.a.shape).astype(numpy.float32)

noise = chainer.Variable(eps)
return noise

@property
def support(self):
"""Returns support.
Returns:
string: Output string that means support of this distribution.
"""
return '[0,1]'

@property
def variance(self):
"""Returns variance.
Returns:
~chainer.Variable: Output variable representing variance.
"""
return (self.a * self.b) / (self.a + self.b) ** 2 \
/ (self.a + self.b + 1)
1 change: 1 addition & 0 deletions chainer/distributions/__init__.py
@@ -1,5 +1,6 @@
"""Collection of distribution implementations."""

from chainer.distributions.Bernoulli import Bernoulli # NOQA
from chainer.distributions.Beta import Beta # NOQA
from chainer.distributions.Gamma import Gamma # NOQA
from chainer.distributions.Normal import Normal # NOQA

0 comments on commit 93bb349

Please sign in to comment.