def multinomial( self, size=None, n=1, pvals=None, ndim=None, dtype="int64", nstreams=None, **kwargs, ): # TODO : need description for parameter and return """ Sample `n` (`n` needs to be >= 1, default 1) times from a multinomial distribution defined by probabilities pvals. Example : pvals = [[.98, .01, .01], [.01, .49, .50]] and n=1 will probably result in [[1,0,0],[0,0,1]]. When setting n=2, this will probably result in [[2,0,0],[0,1,1]]. Notes ----- -`size` and `ndim` are only there keep the same signature as other uniform, binomial, normal, etc. TODO : adapt multinomial to take that into account -Does not do any value checking on pvals, i.e. there is no check that the elements are non-negative, less than 1, or sum to 1. passing pvals = [[-2., 2.]] will result in sampling [[0, 0]] """ if pvals is None: raise TypeError("You have to specify pvals") pvals = as_tensor_variable(pvals) pvals = undefined_grad(pvals) if size is not None: if any([isinstance(i, int) and i <= 0 for i in size]): raise ValueError( "The specified size contains a dimension with value <= 0", size) if size is not None: raise ValueError( "Provided a size argument to MRG_RandomStreams.multinomial, " "which does not use the size argument.") if ndim is not None: raise ValueError( "Provided an ndim argument to MRG_RandomStreams.multinomial, " "which does not use the ndim argument.") if pvals.ndim == 2: size = pvals[:, 0].shape * n unis = self.uniform(size=size, ndim=1, nstreams=nstreams, **kwargs) op = multinomial.MultinomialFromUniform(dtype) n_samples = as_tensor_variable(n) return op(pvals, unis, n_samples) else: raise NotImplementedError("MRG_RandomStreams.multinomial only" " implemented for pvals.ndim = 2")
def binomial(self, size=None, n=1, p=0.5, ndim=None, dtype='int64', nstreams=None): # TODO : need description for method, parameter and return if n == 1: p = undefined_grad(as_tensor_variable(p)) x = self.uniform(size=size, nstreams=nstreams) return cast(x < p, dtype) else: raise NotImplementedError("MRG_RandomStreams.binomial with n > 1")
def binomial(self, size=None, n=1, p=0.5, ndim=None, dtype='int64', nstreams=None, **kwargs): # TODO : need description for method, parameter and return if n == 1: p = undefined_grad(as_tensor_variable(p)) x = self.uniform(size=size, nstreams=nstreams, **kwargs) return cast(x < p, dtype) else: raise NotImplementedError("MRG_RandomStreams.binomial with n > 1")
def multinomial(self, size=None, n=1, pvals=None, ndim=None, dtype='int64', nstreams=None): # TODO : need description for parameter and return """ Sample `n` (`n` needs to be >= 1, default 1) times from a multinomial distribution defined by probabilities pvals. Example : pvals = [[.98, .01, .01], [.01, .49, .50]] and n=1 will probably result in [[1,0,0],[0,0,1]]. When setting n=2, this will probably result in [[2,0,0],[0,1,1]]. Notes ----- -`size` and `ndim` are only there keep the same signature as other uniform, binomial, normal, etc. TODO : adapt multinomial to take that into account -Does not do any value checking on pvals, i.e. there is no check that the elements are non-negative, less than 1, or sum to 1. passing pvals = [[-2., 2.]] will result in sampling [[0, 0]] """ if pvals is None: raise TypeError("You have to specify pvals") pvals = as_tensor_variable(pvals) pvals = undefined_grad(pvals) if size is not None: if any([isinstance(i, integer_types) and i <= 0 for i in size]): raise ValueError( "The specified size contains a dimension with value <= 0", size) if size is not None: raise ValueError( "Provided a size argument to MRG_RandomStreams.multinomial, " "which does not use the size argument.") if ndim is not None: raise ValueError( "Provided an ndim argument to MRG_RandomStreams.multinomial, " "which does not use the ndim argument.") if pvals.ndim == 2: size = pvals[:, 0].shape * n unis = self.uniform(size=size, ndim=1, nstreams=nstreams) op = multinomial.MultinomialFromUniform(dtype) n_samples = as_tensor_variable(n) return op(pvals, unis, n_samples) else: raise NotImplementedError(("MRG_RandomStreams.multinomial only" " implemented for pvals.ndim = 2"))
def normal(self, size, avg=0.0, std=1.0, ndim=None, dtype=None, nstreams=None): # TODO : need description for method """ Parameters ---------- size Can be a list of integers or Theano variables (ex: the shape of another Theano Variable). dtype The output data type. If dtype is not specified, it will be inferred from the dtype of low and high, but will be at least as precise as floatX. nstreams Number of streams. """ # We need an even number of ]0,1[ samples. Then we split them # in two halves. First half becomes our U1's for Box-Muller, # second half our U2's. See Wikipedia page: # http://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform avg = as_tensor_variable(avg) avg = undefined_grad(avg) std = as_tensor_variable(std) std = undefined_grad(std) if dtype is None: dtype = scal.upcast(config.floatX, avg.dtype, std.dtype) avg = cast(avg, dtype) std = cast(std, dtype) evened = False constant = False if (isinstance(size, tuple) and all( [isinstance(i, (np.integer, integer_types)) for i in size])): constant = True # Force dtype because it defaults to float when size is empty n_samples = np.prod(size, dtype='int64') if n_samples % 2 == 1: n_samples += 1 evened = True else: # if even, don't change, if odd, +1 n_samples = prod(size) + (prod(size) % 2) flattened = self.uniform(size=(n_samples, ), dtype=dtype, nstreams=nstreams) if constant: U1 = flattened[:n_samples // 2] U2 = flattened[n_samples // 2:] else: U1 = flattened[:prod(flattened.shape) // 2] U2 = flattened[prod(flattened.shape) // 2:] # normal_samples = zeros_like(flattened) sqrt_ln_U1 = sqrt(-2.0 * log(U1)) # TypeError: 'TensorVariable' object does not support item assignment # so this doesn't work... # normal_samples[:n_samples/2] = sqrt_ln_U1 * cos(2.0*np.pi*U2) # normal_samples[n_samples/2:] = sqrt_ln_U1 * sin(2.0*np.pi*U2) # so trying this instead first_half = sqrt_ln_U1 * cos(np.array(2.0 * np.pi, dtype=dtype) * U2) second_half = sqrt_ln_U1 * sin(np.array(2.0 * np.pi, dtype=dtype) * U2) normal_samples = join(0, first_half, second_half) final_samples = None if evened: final_samples = normal_samples[:-1] elif constant: final_samples = normal_samples else: final_samples = normal_samples[:prod(size)] if not size: # Force the dtype to be int64, otherwise reshape complains size = tensor.constant(size, dtype='int64') final_samples = final_samples.reshape(size) final_samples = avg + std * final_samples assert final_samples.dtype == dtype return final_samples
def choice(self, size=1, a=None, replace=True, p=None, ndim=None, dtype='int64', nstreams=None): """ Sample `size` times from a multinomial distribution defined by probabilities `p`, and returns the indices of the sampled elements. Sampled values are between 0 and `p.shape[1]-1`. Only sampling without replacement is implemented for now. Parameters ---------- size: integer or integer tensor (default 1) The number of samples. It should be between 1 and `p.shape[1]-1`. a: int or None (default None) For now, a should be None. This function will sample values between 0 and `p.shape[1]-1`. When a != None will be implemented, if `a` is a scalar, the samples are drawn from the range 0,...,a-1. We default to 2 as to have the same interface as RandomStream. replace: bool (default True) Whether the sample is with or without replacement. Only replace=False is implemented for now. p: 2d numpy array or theano tensor the probabilities of the distribution, corresponding to values 0 to `p.shape[1]-1`. Example : p = [[.98, .01, .01], [.01, .49, .50]] and size=1 will probably result in [[0],[2]]. When setting size=2, this will probably result in [[0,1],[2,1]]. Notes ----- -`ndim` is only there keep the same signature as other uniform, binomial, normal, etc. -Does not do any value checking on pvals, i.e. there is no check that the elements are non-negative, less than 1, or sum to 1. passing pvals = [[-2., 2.]] will result in sampling [[0, 0]] -Only replace=False is implemented for now. """ if replace: raise NotImplementedError( "MRG_RandomStreams.choice only works without replacement " "for now.") if a is not None: raise TypeError("For now, a has to be None in " "MRG_RandomStreams.choice. Sampled values are " "beween 0 and p.shape[1]-1") if p is None: raise TypeError("For now, p has to be specified in " "MRG_RandomStreams.choice.") p = as_tensor_variable(p) p = undefined_grad(p) if ndim is not None: raise ValueError("ndim argument to " "MRG_RandomStreams.choice " "is not used.") if p.ndim != 2: raise NotImplementedError( "MRG_RandomStreams.choice is only implemented for p.ndim = 2") shape = p[:, 0].shape * size unis = self.uniform(size=shape, ndim=1, nstreams=nstreams) op = multinomial.ChoiceFromUniform(odtype=dtype) return op(p, unis, as_tensor_variable(size))
def uniform(self, size, low=0.0, high=1.0, ndim=None, dtype=None, nstreams=None): # TODO : need description for parameter 'size', 'ndim', 'nstreams' """ Sample a tensor of given size whose element from a uniform distribution between low and high. If the size argument is ambiguous on the number of dimensions, ndim may be a plain integer to supplement the missing information. Parameters ---------- low Lower bound of the interval on which values are sampled. If the ``dtype`` arg is provided, ``low`` will be cast into dtype. This bound is excluded. high Higher bound of the interval on which values are sampled. If the ``dtype`` arg is provided, ``high`` will be cast into dtype. This bound is excluded. size Can be a list of integer or Theano variable (ex: the shape of other Theano Variable). dtype The output data type. If dtype is not specified, it will be inferred from the dtype of low and high, but will be at least as precise as floatX. """ low = as_tensor_variable(low) high = as_tensor_variable(high) if dtype is None: dtype = scal.upcast(config.floatX, low.dtype, high.dtype) low = cast(low, dtype=dtype) high = cast(high, dtype=dtype) low = undefined_grad(low) high = undefined_grad(high) if isinstance(size, tuple): msg = "size must be a tuple of int or a Theano variable" assert all([ isinstance(i, (np.integer, integer_types, Variable)) for i in size ]), msg if any([ isinstance(i, (np.integer, integer_types)) and i <= 0 for i in size ]): raise ValueError( "The specified size contains a dimension with value <= 0", size) else: if not (isinstance(size, Variable) and size.ndim == 1): raise TypeError("size must be a tuple of int or a Theano " "Variable with 1 dimension, got " + str(size) + " of type " + str(type(size))) orig_nstreams = nstreams if nstreams is None: nstreams = self.n_streams(size) rstates = self.get_substream_rstates(nstreams, dtype) node_rstate = shared(rstates) u = self.pretty_return(node_rstate, *mrg_uniform.new(node_rstate, ndim, dtype, size), size=size, nstreams=orig_nstreams) # Add a reference to distinguish from other shared variables node_rstate.tag.is_rng = True r = u * (high - low) + low if u.type.broadcastable != r.type.broadcastable: raise NotImplementedError( 'Increase the size to match the broadcasting pattern of ' '`low` and `high` arguments') assert r.dtype == dtype return r
def normal(self, size, avg=0.0, std=1.0, ndim=None, dtype=None, nstreams=None): # TODO : need description for method """ Parameters ---------- size Can be a list of integers or Theano variables (ex: the shape of another Theano Variable). dtype The output data type. If dtype is not specified, it will be inferred from the dtype of low and high, but will be at least as precise as floatX. nstreams Number of streams. """ # We need an even number of ]0,1[ samples. Then we split them # in two halves. First half becomes our U1's for Box-Muller, # second half our U2's. See Wikipedia page: # http://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform avg = as_tensor_variable(avg) avg = undefined_grad(avg) std = as_tensor_variable(std) std = undefined_grad(std) if dtype is None: dtype = scal.upcast(config.floatX, avg.dtype, std.dtype) avg = cast(avg, dtype) std = cast(std, dtype) evened = False constant = False if (isinstance(size, tuple) and all([isinstance(i, (np.integer, integer_types)) for i in size])): constant = True # Force dtype because it defaults to float when size is empty n_samples = np.prod(size, dtype='int64') if n_samples % 2 == 1: n_samples += 1 evened = True else: # if even, don't change, if odd, +1 n_samples = prod(size) + (prod(size) % 2) flattened = self.uniform(size=(n_samples,), dtype=dtype, nstreams=nstreams) if constant: U1 = flattened[:n_samples // 2] U2 = flattened[n_samples // 2:] else: U1 = flattened[:prod(flattened.shape) // 2] U2 = flattened[prod(flattened.shape) // 2:] # normal_samples = zeros_like(flattened) sqrt_ln_U1 = sqrt(-2.0 * log(U1)) # TypeError: 'TensorVariable' object does not support item assignment # so this doesn't work... # normal_samples[:n_samples/2] = sqrt_ln_U1 * cos(2.0*np.pi*U2) # normal_samples[n_samples/2:] = sqrt_ln_U1 * sin(2.0*np.pi*U2) # so trying this instead first_half = sqrt_ln_U1 * cos( np.array(2.0 * np.pi, dtype=dtype) * U2) second_half = sqrt_ln_U1 * sin( np.array(2.0 * np.pi, dtype=dtype) * U2) normal_samples = join(0, first_half, second_half) final_samples = None if evened: final_samples = normal_samples[:-1] elif constant: final_samples = normal_samples else: final_samples = normal_samples[:prod(size)] if not size: # Force the dtype to be int64, otherwise reshape complains size = tensor.constant(size, dtype='int64') final_samples = final_samples.reshape(size) final_samples = avg + std * final_samples assert final_samples.dtype == dtype return final_samples
def uniform(self, size, low=0.0, high=1.0, ndim=None, dtype=None, nstreams=None): # TODO : need description for parameter 'size', 'ndim', 'nstreams' """ Sample a tensor of given size whose element from a uniform distribution between low and high. If the size argument is ambiguous on the number of dimensions, ndim may be a plain integer to supplement the missing information. Parameters ---------- low Lower bound of the interval on which values are sampled. If the ``dtype`` arg is provided, ``low`` will be cast into dtype. This bound is excluded. high Higher bound of the interval on which values are sampled. If the ``dtype`` arg is provided, ``high`` will be cast into dtype. This bound is excluded. size Can be a list of integer or Theano variable (ex: the shape of other Theano Variable). dtype The output data type. If dtype is not specified, it will be inferred from the dtype of low and high, but will be at least as precise as floatX. """ low = as_tensor_variable(low) low = undefined_grad(low) high = as_tensor_variable(high) high = undefined_grad(high) if dtype is None: dtype = scal.upcast(config.floatX, low.dtype, high.dtype) low = cast(low, dtype=dtype) high = cast(high, dtype=dtype) if isinstance(size, tuple): msg = "size must be a tuple of int or a Theano variable" assert all([isinstance(i, (np.integer, integer_types, Variable)) for i in size]), msg if any([isinstance(i, (np.integer, integer_types)) and i <= 0 for i in size]): raise ValueError( "The specified size contains a dimension with value <= 0", size) else: if not (isinstance(size, Variable) and size.ndim == 1): raise TypeError("size must be a tuple of int or a Theano " "Variable with 1 dimension, got " + str(size) + " of type " + str(type(size))) orig_nstreams = nstreams if nstreams is None: nstreams = self.n_streams(size) rstates = self.get_substream_rstates(nstreams, dtype) node_rstate = shared(rstates) u = self.pretty_return(node_rstate, *mrg_uniform.new(node_rstate, ndim, dtype, size), size=size, nstreams=orig_nstreams) # Add a reference to distinguish from other shared variables node_rstate.tag.is_rng = True r = u * (high - low) + low if u.type.broadcastable != r.type.broadcastable: raise NotImplementedError( 'Increase the size to match the broadcasting pattern of ' '`low` and `high` arguments') assert r.dtype == dtype return r
def normal(self, size, avg=0.0, std=1.0, ndim=None, dtype=None, nstreams=None, truncate=False, **kwargs): """ Sample a tensor of values from a normal distribution. Parameters ---------- size : int_vector_like Array dimensions for the output tensor. avg : float_like, optional The mean value for the truncated normal to sample from (defaults to 0.0). std : float_like, optional The standard deviation for the truncated normal to sample from (defaults to 1.0). truncate : bool, optional Truncates the normal distribution at 2 standard deviations if True (defaults to False). When this flag is set, the standard deviation of the result will be less than the one specified. ndim : int, optional The number of dimensions for the output tensor (defaults to None). This argument is necessary if the size argument is ambiguous on the number of dimensions. dtype : str, optional The data-type for the output tensor. If not specified, the dtype is inferred from avg and std, but it is at least as precise as floatX. kwargs Other keyword arguments for random number generation (see uniform). Returns ------- samples : TensorVariable A Theano tensor of samples randomly drawn from a normal distribution. """ size = _check_size(size) avg = undefined_grad(as_tensor_variable(avg)) std = undefined_grad(as_tensor_variable(std)) if dtype is None: dtype = scal.upcast(config.floatX, avg.dtype, std.dtype) avg = tensor.cast(avg, dtype=dtype) std = tensor.cast(std, dtype=dtype) # generate even number of uniform samples # Do manual constant folding to lower optiimizer work. if isinstance(size, theano.Constant): n_odd_samples = size.prod(dtype='int64') else: n_odd_samples = tensor.prod(size, dtype='int64') n_even_samples = n_odd_samples + n_odd_samples % 2 uniform = self.uniform((n_even_samples, ), low=0., high=1., ndim=1, dtype=dtype, nstreams=nstreams, **kwargs) # box-muller transform u1 = uniform[:n_even_samples // 2] u2 = uniform[n_even_samples // 2:] r = tensor.sqrt(-2.0 * tensor.log(u1)) theta = np.array(2.0 * np.pi, dtype=dtype) * u2 cos_theta, sin_theta = tensor.cos(theta), tensor.sin(theta) z0 = r * cos_theta z1 = r * sin_theta if truncate: # use valid samples to_fix0 = (z0 < -2.) | (z0 > 2.) to_fix1 = (z1 < -2.) | (z1 > 2.) z0_valid = z0[tensor.nonzero(~to_fix0)] z1_valid = z1[tensor.nonzero(~to_fix1)] # re-sample invalid samples to_fix0 = tensor.nonzero(to_fix0)[0] to_fix1 = tensor.nonzero(to_fix1)[0] n_fix_samples = to_fix0.size + to_fix1.size lower = tensor.constant(1. / np.e**2, dtype=dtype) u_fix = self.uniform((n_fix_samples, ), low=lower, high=1., ndim=1, dtype=dtype, nstreams=nstreams, **kwargs) r_fix = tensor.sqrt(-2. * tensor.log(u_fix)) z0_fixed = r_fix[:to_fix0.size] * cos_theta[to_fix0] z1_fixed = r_fix[to_fix0.size:] * sin_theta[to_fix1] # pack everything together to a useful result norm_samples = tensor.join(0, z0_valid, z0_fixed, z1_valid, z1_fixed) else: norm_samples = tensor.join(0, z0, z1) if isinstance(n_odd_samples, theano.Variable): samples = norm_samples[:n_odd_samples] elif n_odd_samples % 2 == 1: samples = norm_samples[:-1] else: samples = norm_samples samples = tensor.reshape(samples, newshape=size, ndim=ndim) samples *= std samples += avg return samples
def normal( self, size, avg=0.0, std=1.0, ndim=None, dtype=None, nstreams=None, truncate=False, **kwargs, ): """ Sample a tensor of values from a normal distribution. Parameters ---------- size : int_vector_like Array dimensions for the output tensor. avg : float_like, optional The mean value for the truncated normal to sample from (defaults to 0.0). std : float_like, optional The standard deviation for the truncated normal to sample from (defaults to 1.0). truncate : bool, optional Truncates the normal distribution at 2 standard deviations if True (defaults to False). When this flag is set, the standard deviation of the result will be less than the one specified. ndim : int, optional The number of dimensions for the output tensor (defaults to None). This argument is necessary if the size argument is ambiguous on the number of dimensions. dtype : str, optional The data-type for the output tensor. If not specified, the dtype is inferred from avg and std, but it is at least as precise as floatX. kwargs Other keyword arguments for random number generation (see uniform). Returns ------- samples : TensorVariable A Theano tensor of samples randomly drawn from a normal distribution. """ size = _check_size(size) avg = undefined_grad(as_tensor_variable(avg)) std = undefined_grad(as_tensor_variable(std)) if dtype is None: dtype = scal.upcast(config.floatX, avg.dtype, std.dtype) avg = tensor.cast(avg, dtype=dtype) std = tensor.cast(std, dtype=dtype) # generate even number of uniform samples # Do manual constant folding to lower optiimizer work. if isinstance(size, theano.Constant): n_odd_samples = size.prod(dtype="int64") else: n_odd_samples = tensor.prod(size, dtype="int64") n_even_samples = n_odd_samples + n_odd_samples % 2 uniform = self.uniform( (n_even_samples, ), low=0.0, high=1.0, ndim=1, dtype=dtype, nstreams=nstreams, **kwargs, ) # box-muller transform u1 = uniform[:n_even_samples // 2] u2 = uniform[n_even_samples // 2:] r = tensor.sqrt(-2.0 * tensor.log(u1)) theta = np.array(2.0 * np.pi, dtype=dtype) * u2 cos_theta, sin_theta = tensor.cos(theta), tensor.sin(theta) z0 = r * cos_theta z1 = r * sin_theta if truncate: # use valid samples to_fix0 = (z0 < -2.0) | (z0 > 2.0) to_fix1 = (z1 < -2.0) | (z1 > 2.0) z0_valid = z0[tensor.nonzero(~to_fix0)] z1_valid = z1[tensor.nonzero(~to_fix1)] # re-sample invalid samples to_fix0 = tensor.nonzero(to_fix0)[0] to_fix1 = tensor.nonzero(to_fix1)[0] n_fix_samples = to_fix0.size + to_fix1.size lower = tensor.constant(1.0 / np.e**2, dtype=dtype) u_fix = self.uniform( (n_fix_samples, ), low=lower, high=1.0, ndim=1, dtype=dtype, nstreams=nstreams, **kwargs, ) r_fix = tensor.sqrt(-2.0 * tensor.log(u_fix)) z0_fixed = r_fix[:to_fix0.size] * cos_theta[to_fix0] z1_fixed = r_fix[to_fix0.size:] * sin_theta[to_fix1] # pack everything together to a useful result norm_samples = tensor.join(0, z0_valid, z0_fixed, z1_valid, z1_fixed) else: norm_samples = tensor.join(0, z0, z1) if isinstance(n_odd_samples, theano.Variable): samples = norm_samples[:n_odd_samples] elif n_odd_samples % 2 == 1: samples = norm_samples[:-1] else: samples = norm_samples samples = tensor.reshape(samples, newshape=size, ndim=ndim) samples *= std samples += avg return samples