def randn(*sizes, device=None): """ Returns a tensor with normally distributed elements. Samples are generated using the Box-Muller transform with optimizations for numerical precision and MPC efficiency. """ u = crypten.rand(*sizes, device=device).flatten() odd_numel = u.numel() % 2 == 1 if odd_numel: u = crypten.cat([u, crypten.rand((1, ), device=device)]) n = u.numel() // 2 u1 = u[:n] u2 = u[n:] # Radius = sqrt(- 2 * log(u1)) r2 = -2 * u1.log(input_in_01=True) r = r2.sqrt() # Theta = cos(2 * pi * u2) or sin(2 * pi * u2) cos, sin = u2.sub(0.5).mul(6.28318531).cossin() # Generating 2 independent normal random variables using x = r.mul(sin) y = r.mul(cos) z = crypten.cat([x, y]) if odd_numel: z = z[1:] return z.view(*sizes)
def test_rand(self): """Tests uniform random variable generation on [0, 1)""" for size in [(10, ), (10, 10), (10, 10, 10)]: randvec = crypten.rand(*size) self.assertTrue(randvec.size() == size, "Incorrect size") tensor = randvec.get_plain_text() self.assertTrue((tensor >= 0).all() and (tensor < 1).all(), "Invalid values") randvec = crypten.rand(int(1e6)).get_plain_text() mean = torch.mean(randvec) var = torch.var(randvec) self.assertTrue( torch.isclose(mean, torch.Tensor([0.5]), rtol=1e-3, atol=1e-3)) self.assertTrue( torch.isclose(var, torch.Tensor([1.0 / 12]), rtol=1e-3, atol=1e-3))
def weighted_index(self, dim=None): """ Returns a tensor with entries that are one-hot along dimension `dim`. These one-hot entries are set at random with weights given by the input `self`. Examples:: >>> encrypted_tensor = MPCTensor(torch.tensor([1., 6.])) >>> index = encrypted_tensor.weighted_index().get_plain_text() # With 1 / 7 probability torch.tensor([1., 0.]) # With 6 / 7 probability torch.tensor([0., 1.]) """ if dim is None: return self.flatten().weighted_index(dim=0).view(self.size()) x = self.cumsum(dim) max_weight = x.index_select( dim, torch.tensor(x.size(dim) - 1, device=self.device)) r = crypten.rand(max_weight.size(), device=self.device) * max_weight gt = x.gt(r) shifted = gt.roll(1, dims=dim) shifted.data.index_fill_(dim, torch.tensor(0, device=self.device), 0) return gt - shifted
def dropout(self, p=0.5, training=True, inplace=False): r""" Randomly zeroes some of the elements of the input tensor with probability :attr:`p`. Args: p: probability of a channel to be zeroed. Default: 0.5 training: apply dropout if is ``True``. Default: ``True`` inplace: If set to ``True``, will do this operation in-place. Default: ``False`` """ if p == 0.0: return self elif p == 1.0: return self - self assert p > 0.0 and p < 1.0, "dropout probability has to be between 0 and 1" if training and inplace: logging.warning( "CrypTen dropout does not support inplace computation during training." ) if not training: if inplace: return self else: return self.clone() rand_tensor = crypten.rand(self.size(), device=self.device) dropout_tensor = rand_tensor > p if inplace: result_tensor = self.div_(1 - p) result_tensor = result_tensor.mul_(dropout_tensor) else: result_tensor = self.div(1 - p) result_tensor = result_tensor.mul(dropout_tensor) return result_tensor
def score_func(scores, A_inv, b, context): explore = crypten.bernoulli(torch.tensor([epsilon])) rand_scores = crypten.rand(*scores.size()) scores.mul_(1 - explore).add_(rand_scores.mul(explore))
def bernoulli(self): """Returns a tensor with elements in {0, 1}. The i-th element of the output will be 1 with probability according to the i-th value of the input tensor.""" return self > crypten.rand(self.size(), device=self.device)