def dPdx_num(m, c, maxpts=25000, abseps=0.000001, releps=0): d = c.size(-1) res = torch.empty(d) p = Phi(0, m, c) h = 0.005 for i in range(d): mh = m.clone() mh[i] = mh[i] + h ph = Phi(0, mh, c) res[i] = (ph - p) / h return res
def dPdC_num(m, c): d = c.size(-1) res = torch.empty(d) p = Phi(0, m, c) h = 0.005 res = torch.empty(d, d) for i in range(d): for j in range(d): ch = c.clone() ch[i, j] = ch[i, j] + h / 2 ch[j, i] = ch[j, i] + h / 2 ph = Phi(0, m, ch) res[i, j] = (ph - p) / h return res
def d2Pdx2_num(m, c): h = 0.005 d = c.shape[-1] res = torch.zeros(d, d) for i in range(d): zz = zeros(d) zz[i] = 1 for j in range(d): yy = zeros(d) yy[j] = 1 res[i, j] = (1 / h**2 * (Phi(0, m + .5 * h * (zz + yy), c) - Phi(0, m + .5 * h * (-zz + yy), c) - (Phi(0, m + .5 * h * (zz - yy), c) - Phi(0, m + .5 * h * (-zz - yy), c)))).detach() return 0.5 * (res.transpose(-2, -1) + res)
] # do 16 probability computations in one tensor, can be a scalar ("[]") d = 23 # dimension of the random vector x = randn(*batch_dim, d) + 0.5 * sqrt(d) # Compute an arbitrary covariance D = randn(*batch_dim, d)**2 C = torch.diag_embed(D, dim1=-2, dim2=-1) # parameters of "from scipy.stats import mvn" integration.maxpts = 1000 * d # default integration.abseps = 1e-6 # default integration.releps = 1e-6 # default integration.n_jobs = 1 # joblib parameter t1 = time() print(Phi(x, covariance_matrix=C, diagonality_tolerance=-1)) t2 = time() print("With full matrix and " + str(integration.n_jobs) + " job(s):" + str(round(t2 - t1, 3)) + " s.") t1 = time() print(Phi(x, covariance_matrix=C, diagonality_tolerance=0)) t2 = time() print("With knowing it's actually diagonal and 1 job:" + str(round(t2 - t1, 3)) + " s.") t1 = time() print(Phi(x, covariance_matrix=C + 1e-4, diagonality_tolerance=2e-4)) t2 = time()
d = 3 A = torch.randn(d, d) C = torch.matmul(A, A.transpose(-2, -1)) + torch.diag_embed( torch.ones(d), dim1=-1, dim2=-2) integration.maxpts = 100000000 integration.abseps = 1e-8 integration.releps = 0 # Usually, maxpts doesn't need to be so high (and abseps&releps so small). It is set # high here to check derivatives using finite difference. # Finite difference requires extremely high precision (and computation time). mean = torch.zeros(d) mean.requires_grad = True C.requires_grad = True P = Phi(0, mean, C) dPdm, dPdC = grad(P, (mean, C), create_graph=True) print("___Gradient___ dPhi/dm") print("ANALYTICAL:") print(dPdm) print("NUMERICAL:") print(dPdx_num(mean, C)) print("___Packett's formula___ 1/2*d2Phi/dm2 == dPhi/dC") print("ANALYTICAL dPhi/dC:") print(dPdC) print("ANALYTICAL 1/2*d2Phi/dm2:") print(.5 * hessian(P, mean)) print("NUMERICAL dPhi/dC:") print(dPdC_num(mean, C))
# Compute an arbitrary covariance A = randn(batch_dim[-1], d, d) if len(batch_dim) > 0 else randn(d, d) C = torch.diag(torch.ones(d)) + 1 / d * matmul(A, A.transpose(-1, -2)) #### mean shape: [*batch_shape,d] (can be just "[d]") #### covariance shape: [*batch_shape,d,d] #### result prob shape: [*batch_shape] (tensor scalar if batch_shape is empty) # Batch_shape of tensors can broadcast: # for exemple m.shape == [3,4,6] and C.shape == [4,6,6] # parameters of "from scipy.stats import mvn" integration.maxpts = 1000 * d # default integration.abseps = 1e-6 # default integration.releps = 1e-6 # default integration.n_jobs = 1 # joblib parameter t1 = time() print(Phi(0, m, C)) t2 = time() print("With " + str(integration.n_jobs) + " job(s):" + str(round(t2 - t1, 3)) + " s.") integration.n_jobs = 10 t1 = time() print(Phi(0, m, C)) t2 = time() print("With " + str(integration.n_jobs) + " job(s):" + str(round(t2 - t1, 3)) + " s.")
import sys sys.path.append(".") import torch from torch.autograd import grad from mvnorm import multivariate_normal_cdf as Phi d = 3 x = torch.randn(d) m = torch.zeros(d) Croot = torch.randn(d, d) C = Croot.mm(Croot.t()) + torch.diag(torch.ones(d)) x.requires_grad = True m.requires_grad = True C.requires_grad = True P = Phi(x, m, C) dPdx, dPdm, dPdC = grad(P, (x, m, C)) print(dPdx) print(dPdm) print(dPdC)