提交 6b1cdf30 authored 作者: Pascal Lamblin's avatar Pascal Lamblin

Beginning of the work to make random functions accept tensor parameters.

上级 14ceb214
...@@ -175,40 +175,76 @@ class RandomFunction(gof.Op): ...@@ -175,40 +175,76 @@ class RandomFunction(gof.Op):
def grad(self, inputs, outputs): def grad(self, inputs, outputs):
return [None for i in inputs] return [None for i in inputs]
def _infer_ndim(ndim, shape): def _infer_ndim(ndim, shape, *args):
"""returns int, variable pair, such that the int is the length of the variable, and the """
variable is an integer or uint vector Infer the number of dimensions from the shape or the other arguments.
:rtype: (int, variable) pair, where the variable is an integer vector.
:returns: the first element returned is the inferred number of dimensions.
The second element's length is either the first element, or 0
(if the original shape was None).
In the special case where the shape argument is None, the variable
returned has a length of 0, meaning that the shape will be computed
at runtime from the shape of the other args.
""" """
# Find the minimum value of ndim required by the *args
if len(args) > 0:
args_ndim = max(arg.ndim for arg in args)
else:
args_ndim = 0
if isinstance(shape, (tuple, list)): if isinstance(shape, (tuple, list)):
v_shape = tensor.TensorConstant(type=tensor.lvector, data=theano._asarray(shape, dtype='int64')) v_shape = tensor.TensorConstant(type=tensor.lvector, data=theano._asarray(shape, dtype='int64'))
shape_ndim = len(shape)
if ndim is None:
ndim = shape_ndim
else:
if shape_ndim != ndim:
raise ValueError('ndim should be equal to len(shape), but\n',
'ndim = %s, len(shape) = %s, shape = %s'
% (ndim, shape_ndim, shape))
elif shape is None:
# The shape will be computed at runtime, but we need to know ndim
v_shape = tensor.constant([], dtype='int64')
if ndim is None:
ndim = args_dim
else: else:
v_shape = tensor.as_tensor_variable(shape) v_shape = tensor.as_tensor_variable(shape)
if ndim is None:
ndim = tensor.get_vector_length(v_shape)
if not (v_shape.dtype.startswith('int') or v_shape.dtype.startswith('uint')): if not (v_shape.dtype.startswith('int') or v_shape.dtype.startswith('uint')):
raise TypeError('shape must be an integer vector or list') raise TypeError('shape must be an integer vector or list')
if ndim is None: if args_ndim > ndim:
#infer ndim raise ValueError('ndim should be at least as big as required by args value',
ndim = tensor.get_vector_length(v_shape) (ndim, args_ndim), args)
return ndim, v_shape return ndim, v_shape
def uniform(random_state, size=(), low=0.0, high=1.0, ndim=None): def uniform(random_state, size=None, low=0.0, high=1.0, ndim=None):
""" """
Sample from a uniform distribution between low and high. Sample from a uniform distribution between low and high.
If the size argument is ambiguous on the number of If the size argument is ambiguous on the number of dimensions, ndim
dimensions, the first argument may be a plain integer may be a plain integer to supplement the missing information.
to supplement the missing information.
If size is None, the output shape will be determined by the shapes
of low and high.
""" """
ndim, size = _infer_ndim(ndim, size) low = tensor.as_tensor_variable(low)
op = RandomFunction('uniform', high = tensor.as_tensor_variable(high)
ndim, size = _infer_ndim(ndim, size, low, high)
op = RandomFunction('uniform',
tensor.TensorType(dtype = 'float64', broadcastable = (False,)*ndim) ) tensor.TensorType(dtype = 'float64', broadcastable = (False,)*ndim) )
return op(random_state, size, low, high) return op(random_state, size, low, high)
def binomial(random_state, size=(), n=1, prob=0.5, ndim=None): def binomial(random_state, size=None, n=1, prob=0.5, ndim=None):
""" """
Sample n times with probability of success prob for each trial, return the number of Sample n times with probability of success prob for each trial, return the number of
successes. successes.
...@@ -216,12 +252,14 @@ def binomial(random_state, size=(), n=1, prob=0.5, ndim=None): ...@@ -216,12 +252,14 @@ def binomial(random_state, size=(), n=1, prob=0.5, ndim=None):
If the size argument is ambiguous on the number of dimensions, the first argument may be a If the size argument is ambiguous on the number of dimensions, the first argument may be a
plain integer to supplement the missing information. plain integer to supplement the missing information.
""" """
ndim, size = _infer_ndim(ndim, size) n = tensor.as_tensor_variable(n)
op = RandomFunction('binomial', prob = tensor.as_tensor_variable(prob)
ndim, size = _infer_ndim(ndim, size, n, prob)
op = RandomFunction('binomial',
tensor.TensorType(dtype = 'int64', broadcastable = (False,)*ndim) ) tensor.TensorType(dtype = 'int64', broadcastable = (False,)*ndim) )
return op(random_state, size, n, prob) return op(random_state, size, n, prob)
def normal(random_state, size=(), avg=0.0, std=1.0, ndim=None): def normal(random_state, size=None, avg=0.0, std=1.0, ndim=None):
""" """
Usage: normal(random_state, size, Usage: normal(random_state, size,
Sample from a normal distribution centered on avg with Sample from a normal distribution centered on avg with
...@@ -231,12 +269,14 @@ def normal(random_state, size=(), avg=0.0, std=1.0, ndim=None): ...@@ -231,12 +269,14 @@ def normal(random_state, size=(), avg=0.0, std=1.0, ndim=None):
dimensions, the first argument may be a plain integer dimensions, the first argument may be a plain integer
to supplement the missing information. to supplement the missing information.
""" """
ndim, size = _infer_ndim(ndim, size) avg = tensor.as_tensor_variable(avg)
op = RandomFunction('normal', std = tensor.as_tensor_variable(std)
ndim, size = _infer_ndim(ndim, size, avg, std)
op = RandomFunction('normal',
tensor.TensorType(dtype = 'float64', broadcastable = (False,)*ndim) ) tensor.TensorType(dtype = 'float64', broadcastable = (False,)*ndim) )
return op(random_state, size, avg, std) return op(random_state, size, avg, std)
def random_integers(random_state, size=(), low=0, high=1, ndim=None): def random_integers(random_state, size=None, low=0, high=1, ndim=None):
""" """
Usage: random_integers(random_state, size, low=0, high=1) Usage: random_integers(random_state, size, low=0, high=1)
Sample a random integer between low and high, both inclusive. Sample a random integer between low and high, both inclusive.
...@@ -245,8 +285,10 @@ def random_integers(random_state, size=(), low=0, high=1, ndim=None): ...@@ -245,8 +285,10 @@ def random_integers(random_state, size=(), low=0, high=1, ndim=None):
dimensions, the first argument may be a plain integer dimensions, the first argument may be a plain integer
to supplement the missing information. to supplement the missing information.
""" """
ndim, size = _infer_ndim(ndim, size) low = tensor.as_tensor_variable(low)
op = RandomFunction('random_integers', high = tensor.as_tensor_variable(high)
ndim, size = _infer_ndim(ndim, size, low, high)
op = RandomFunction('random_integers',
tensor.TensorType(dtype = 'int64', broadcastable = (False,)*ndim) ) tensor.TensorType(dtype = 'int64', broadcastable = (False,)*ndim) )
return op(random_state, size, low, high) return op(random_state, size, low, high)
...@@ -277,7 +319,7 @@ def permutation_helper(random_state, n, shape): ...@@ -277,7 +319,7 @@ def permutation_helper(random_state, n, shape):
print 'RETURNING', out.shape print 'RETURNING', out.shape
return out return out
def permutation(random_state, size=(), n=1, ndim=None): def permutation(random_state, size=None, n=1, ndim=None):
""" """
Returns permutations of the integers between 0 and n-1, as many times Returns permutations of the integers between 0 and n-1, as many times
as required by size. For instance, if size=(p,q), p*q permutations as required by size. For instance, if size=(p,q), p*q permutations
...@@ -292,12 +334,12 @@ def permutation(random_state, size=(), n=1, ndim=None): ...@@ -292,12 +334,12 @@ def permutation(random_state, size=(), n=1, ndim=None):
""" """
ndim, size = _infer_ndim(ndim, size) ndim, size = _infer_ndim(ndim, size)
print "NDIM", ndim, size print "NDIM", ndim, size
op = RandomFunction(permutation_helper, op = RandomFunction(permutation_helper,
tensor.TensorType(dtype='int64', broadcastable=(False,)*(ndim+1)), tensor.TensorType(dtype='int64', broadcastable=(False,)*(ndim+1)),
ndim_added=1) ndim_added=1)
return op(random_state, size, n) return op(random_state, size, n)
def multinomial(random_state, size=(), n=1, pvals=[0.5, 0.5], ndim=None): def multinomial(random_state, size=None, n=1, pvals=[0.5, 0.5], ndim=None):
""" """
Sample n times from a multinomial distribution defined by probabilities pvals, Sample n times from a multinomial distribution defined by probabilities pvals,
as many times as required by size. For instance, if size=(p,q), p*q as many times as required by size. For instance, if size=(p,q), p*q
...@@ -309,8 +351,10 @@ def multinomial(random_state, size=(), n=1, pvals=[0.5, 0.5], ndim=None): ...@@ -309,8 +351,10 @@ def multinomial(random_state, size=(), n=1, pvals=[0.5, 0.5], ndim=None):
.. note:: .. note::
Note that the output will then be of dimension ndim+1. Note that the output will then be of dimension ndim+1.
""" """
ndim, size = _infer_ndim(ndim, size) n = tensor.as_tensor_variable(n)
op = RandomFunction('multinomial', pvals = tensor.as_tensor_variable(pvals)
ndim, size = _infer_ndim(ndim, size, n, pvals[0])
op = RandomFunction('multinomial',
tensor.TensorType(dtype = 'int64', broadcastable = (False,)*(ndim+1)), tensor.TensorType(dtype = 'int64', broadcastable = (False,)*(ndim+1)),
ndim_added=1) ndim_added=1)
return op(random_state, size, n, pvals) return op(random_state, size, n, pvals)
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论