A custom random variable

Dear Edwar’s users.

I need a custom random variable to incorporate to my model. Specifically a 3D random variable with x and y coordinates distributed uniformly inside the unit disk, and z coordinates like a Normal distribution. Here my code (doing copy-paste from other distributions like the Normal distribution)

from edward.models import RandomVariable
from tensorflow.contrib.distributions import Distribution

import tensorflow as tf


class CustomRandomVariable(RandomVariable, Distribution):
  def __init__(self, loc, scale, validate_args=False,
               allow_nan_stats=True, name="CustomRandomVariable"):
    super(CustomRandomVariable, self).__init__(
    	loc,
    	scale,
        validate_args=validate_args,
        allow_nan_stats=allow_nan_stats,
        name=name)

  def _log_prob(self, value):
    raise NotImplementedError("log_prob is not implemented")

  def _sample_n(self, n, seed=None):
	a = tf.contrib.distributions.Uniform(low=0.0,high=1.0)
	b = tf.contrib.distributions.Uniform(low=0.0,high=6.283185)
	x = tf.sqrt(a)*tf.cos(b)
	y = tf.sqrt(a)*tf.sin(b)
	z = tf.contrib.distributions.Normal(loc=self.loc, scale=self.scale)
	return tf.concat([x,y,z],0)

Then I obtain the following error. Please, any help will be welcome!

>>> from Fmodule import CustomRandomVariable
>>> x = CustomRandomVariable(loc=1.0,scale=2.0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "Fmodule.py", line 23, in __init__
    name=name)
  File "build/bdist.linux-x86_64/egg/edward/models/random_variable.py", line 119, in __init__
  File "/home/angel/anaconda2/lib/python2.7/site-packages/tensorflow/contrib/distributions/python/ops/distribution.py", line 659, in sample
    return self._call_sample_n(sample_shape, seed, name)
  File "/home/angel/anaconda2/lib/python2.7/site-packages/tensorflow/contrib/distributions/python/ops/distribution.py", line 638, in _call_sample_n
    samples = self._sample_n(n, seed, **kwargs)
  File "Fmodule.py", line 31, in _sample_n
    x = tf.sqrt(a)*tf.cos(b)
  File "/home/angel/anaconda2/lib/python2.7/site-packages/tensorflow/python/ops/math_ops.py", line 434, in sqrt
    return gen_math_ops.sqrt(x, name=name)
  File "/home/angel/anaconda2/lib/python2.7/site-packages/tensorflow/python/ops/gen_math_ops.py", line 2545, in sqrt
    result = _op_def_lib.apply_op("Sqrt", x=x, name=name)
  File "/home/angel/anaconda2/lib/python2.7/site-packages/tensorflow/python/framework/op_def_library.py", line 494, in apply_op
    raise err
TypeError: Expected binary or unicode string, got <tensorflow.contrib.distributions.python.ops.uniform.Uniform object at 0x7f3992245990>

You’re multiplying tf distribution objects. They are not convertible to tensors. You should instantiate the uniforms as Edward random variables.

Yes! It works!

But now I obtain the following error (simple, I guess)…this is because I am newbie coding on python :frowning:

from edward.models import RandomVariable
from tensorflow.contrib.distributions import Distribution

import tensorflow as tf
from edward.models import Normal, Uniform

class CustomRandomVariable(RandomVariable, Distribution):
  def __init__(self, loc, scale, validate_args=False,
               allow_nan_stats=True, name="CustomRandomVariable"):
    super(CustomRandomVariable, self).__init__(
    	loc,
    	scale,
        validate_args=validate_args,
        allow_nan_stats=allow_nan_stats,
        name=name)

  def _log_prob(self, value):
    raise NotImplementedError("log_prob is not implemented")

  def _sample_n(self, n, seed=None):
	a = Uniform(low=0.0,high=1.0)
	b = Uniform(low=0.0,high=6.283185)
	x = tf.sqrt(a)*tf.cos(b)
	y = tf.sqrt(a)*tf.sin(b)
	z = Normal(loc=self.loc, scale=self.scale)
	return tf.concat([x,y,z],0)

Here the error:
>>> from Fmodule import CustomRandomVariable
>>> x = CustomRandomVariable(loc=1.0,scale=2.0)
Traceback (most recent call last):
File “”, line 1, in
File “Fmodule.py”, line 15, in init
name=name)
File “build/bdist.linux-x86_64/egg/edward/models/random_variable.py”, line 119, in init
File “/home/angel/anaconda2/lib/python2.7/site-packages/tensorflow/contrib/distributions/python/ops/distribution.py”, line 659, in sample
return self._call_sample_n(sample_shape, seed, name)
File “/home/angel/anaconda2/lib/python2.7/site-packages/tensorflow/contrib/distributions/python/ops/distribution.py”, line 638, in _call_sample_n
samples = self._sample_n(n, seed, **kwargs)
File “Fmodule.py”, line 25, in _sample_n
z = Normal(loc=self.loc, scale=self.scale)
AttributeError: ‘CustomRandomVariable’ object has no attribute ‘loc’

You’re passing loc and scale into a parent __init__ method. These parent classes don’t accept them. You need to store them in this init method.

I understand @dustin After some attempts, I got what I want. Now I will try to include this distribution in my model.

Thanks again!

The code:

from edward.models import RandomVariable
from tensorflow.contrib.distributions import Distribution

import tensorflow as tf
from edward.models import Normal, Uniform

try:
  from tensorflow.contrib.distributions import FULLY_REPARAMETERIZED
except Exception as e:
  raise ImportError("{0}. Your TensorFlow version is not supported.".format(e))


class newNormal(Distribution):
	def __init__(self,params,validate_args=False,allow_nan_stats=True,name="newNormal"):
		parameters = locals()
		with tf.name_scope(name, values=[params]):
			with tf.control_dependencies([]):
				self._params = tf.identity(params, name="params")
				try:
					self._n = tf.shape(self._params)[0]
				except ValueError:  # scalar params
					self._n = tf.constant(1)
		
		super(newNormal, self).__init__(
			dtype=self._params.dtype,
			reparameterization_type=FULLY_REPARAMETERIZED,
			validate_args=validate_args,
			allow_nan_stats=allow_nan_stats,
			parameters=parameters,
			graph_parents=[self._params, self._n],
			name=name)

	@staticmethod
	def _param_shapes(sample_shape):
		return {"params": tf.convert_to_tensor(sample_shape, dtype=tf.int32)}

	@property
	def params(self):
		"""Distribution parameter."""
		return self._params

	@property
	def n(self):
		"""Number of samples."""
		return self._n
	
	def _log_prob(self, value):
		raise NotImplementedError("log_prob is not implemented")

	def _sample_n(self, n, seed=None):
		input_tensor = self.params
		r = Uniform(low=input_tensor[0],high=input_tensor[1])._sample_n(n, seed)
		b = Uniform(low=0.0,high=6.283185)._sample_n(n, seed)
		x = tf.sqrt(r)*tf.cos(b)
		y = tf.sqrt(r)*tf.sin(b)
		z = Normal(loc=input_tensor[2],scale=input_tensor[3])._sample_n(n, seed)
		return tf.stack([x, y, z], axis=1)
1 Like