def testBackwardGrayscaleAnalysisMode(self, datatype, nchs, nrows, ncols, mus): rtol, atol = 1e-3, 1e-6 omgs = OrthonormalMatrixGenerationSystem(dtype=datatype, partial_difference=False) # Parameters nSamples = 8 nChsTotal = sum(nchs) nAngles = int((nChsTotal - 2) * nChsTotal / 8) angles = torch.randn(nAngles, dtype=datatype) # nSamples x nRows x nCols x nChsTotal X = torch.randn(nSamples, nrows, ncols, nChsTotal, dtype=datatype, requires_grad=True) dLdZ = torch.randn(nSamples, nrows, ncols, nChsTotal, dtype=datatype) # Expected values ps, pa = nchs UnT = omgs(angles, mus).T # dLdX = dZdX x dLdZ expctddLdX = dLdZ.clone() Ya = dLdZ[:, :, :, ps:].view(nSamples * nrows * ncols, pa).T # pa * n Za = UnT @ Ya expctddLdX[:, :, :, ps:] = Za.T.view(nSamples, nrows, ncols, pa) # dLdWi = <dLdZ,(dVdWi)X> expctddLdW_U = torch.zeros(nAngles, dtype=datatype) omgs.partial_difference = True for iAngle in range(nAngles): dUn = omgs(angles, mus, index_pd_angle=iAngle) Xa = X[:, :, :, ps:].view(-1, pa).T Za = dUn @ Xa # pa x n expctddLdW_U[iAngle] = torch.sum(Ya * Za) # Instantiation of target class layer = NsoltIntermediateRotation2dLayer(number_of_channels=nchs, mode='Analysis', name='Vn') layer.orthTransUn.angles.data = angles layer.orthTransUn.mus = mus # Actual values torch.autograd.set_detect_anomaly(True) Z = layer.forward(X) layer.zero_grad() Z.backward(dLdZ) actualdLdX = X.grad actualdLdW_U = layer.orthTransUn.angles.grad # Evaluation self.assertEqual(actualdLdX.dtype, datatype) self.assertEqual(actualdLdW_U.dtype, datatype) self.assertTrue( torch.allclose(actualdLdX, expctddLdX, rtol=rtol, atol=atol)) self.assertTrue( torch.allclose(actualdLdW_U, expctddLdW_U, rtol=rtol, atol=atol)) self.assertTrue(Z.requires_grad)
def testPartialDifference8x8RandAngPdAng13(self, datatype): rtol, atol = 1e-1, 1e-3 # Expcted values pdAng = 13 delta = 1e-3 angs0 = 2 * math.pi * torch.rand(28) angs1 = angs0.clone() angs2 = angs0.clone() angs1[pdAng] = angs0[pdAng] - delta / 2 angs2[pdAng] = angs0[pdAng] + delta / 2 # Instantiation of target class omgs = OrthonormalMatrixGenerationSystem(dtype=datatype, partial_difference=False) expctdM = (omgs(angles=angs2, mus=1) - omgs(angles=angs1, mus=1)) / delta # Instantiation of target class omgs.partial_difference = True actualM = omgs(angles=angs0, mus=1, index_pd_angle=pdAng) # Evaluation self.assertTrue(torch.allclose(actualM, expctdM, rtol=rtol, atol=atol))
def testBackwardWithRandomAnglesNoDcLeackage(self, datatype, nchs, stride, nrows, ncols, mus): rtol, atol = 1e-2, 1e-5 omgs = OrthonormalMatrixGenerationSystem(dtype=datatype, partial_difference=False) # Parameters nSamples = 8 nDecs = stride[0] * stride[1] # math.prod(stride) nChsTotal = sum(nchs) nAnglesH = int((nChsTotal - 2) * nChsTotal / 8) anglesW = torch.randn(nAnglesH, dtype=datatype) anglesU = torch.randn(nAnglesH, dtype=datatype) # nSamples x nRows x nCols x nChs X = torch.randn(nSamples, nrows, ncols, nChsTotal, dtype=datatype, requires_grad=True) dLdZ = torch.randn(nSamples, nrows, ncols, nDecs, dtype=datatype) # Expected values ps, pa = nchs anglesWNoDcLeak = anglesW.clone() anglesWNoDcLeak[:ps - 1] = torch.zeros(ps - 1, dtype=datatype) musW, musU = mus * torch.ones(ps, dtype=datatype), mus * torch.ones( pa, dtype=datatype) musW[0] = 1 W0 = omgs(anglesWNoDcLeak, musW) U0 = omgs(anglesU, musU) # dLdX = dZdX x dLdZ ms, ma = int(math.ceil(nDecs / 2.)), int(math.floor(nDecs / 2.)) Ys = dLdZ[:, :, :, :ms].view(nSamples * nrows * ncols, ms).T # ms x n Ya = dLdZ[:, :, :, ms:].view(nSamples * nrows * ncols, ma).T # ma x n Y = torch.cat( ( W0[:, :ms] @ Ys, # ps x ms @ ms x n U0[:, :ma] @ Ya), dim=0) # pa x ma @ ma x n expctddLdX = Y.T.view(nSamples, nrows, ncols, nChsTotal) # n x (ps+pa) -> N x R x C X P # dLdWi = <dLdZ,(dVdWi)X> expctddLdW_W = torch.zeros(nAnglesH, dtype=datatype) expctddLdW_U = torch.zeros(nAnglesH, dtype=datatype) omgs.partial_difference = True for iAngle in range(nAnglesH): dW0_T = omgs(anglesWNoDcLeak, musW, index_pd_angle=iAngle).T dU0_T = omgs(anglesU, musU, index_pd_angle=iAngle).T Xs = X[:, :, :, :ps].view(-1, ps).T Xa = X[:, :, :, ps:].view(-1, pa).T Zs = dW0_T[:ms, :] @ Xs # ms x n Za = dU0_T[:ma, :] @ Xa # ma x n expctddLdW_W[iAngle] = torch.sum(Ys[:ms, :] * Zs) expctddLdW_U[iAngle] = torch.sum(Ya[:ma, :] * Za) # Instantiation of target class layer = NsoltFinalRotation2dLayer(number_of_channels=nchs, decimation_factor=stride, no_dc_leakage=True, name='V0~') layer.orthTransW0T.angles.data = anglesW layer.orthTransW0T.mus = mus layer.orthTransU0T.angles.data = anglesU layer.orthTransU0T.mus = mus # Actual values torch.autograd.set_detect_anomaly(True) Z = layer.forward(X) layer.zero_grad() Z.backward(dLdZ) actualdLdX = X.grad actualdLdW_W = layer.orthTransW0T.angles.grad actualdLdW_U = layer.orthTransU0T.angles.grad # Evaluation self.assertEqual(actualdLdX.dtype, datatype) self.assertEqual(actualdLdW_W.dtype, datatype) self.assertEqual(actualdLdW_U.dtype, datatype) self.assertTrue( torch.allclose(actualdLdX, expctddLdX, rtol=rtol, atol=atol)) self.assertTrue( torch.allclose(actualdLdW_W, expctddLdW_W, rtol=rtol, atol=atol)) self.assertTrue( torch.allclose(actualdLdW_U, expctddLdW_U, rtol=rtol, atol=atol)) self.assertTrue(Z.requires_grad)
def testBackwardGrayscaleWithRandomAngles(self, nchs, stride, nrows, ncols, datatype): rtol,atol=1e-3,1e-6 omgs = OrthonormalMatrixGenerationSystem(dtype=datatype,partial_difference=False) # Parameters nSamples = 8 nDecs = stride[0]*stride[1] # math.prod(stride) nChsTotal = sum(nchs) nAnglesH = int((nChsTotal-2)*nChsTotal/8) anglesW = torch.randn(nAnglesH,dtype=datatype) anglesU = torch.randn(nAnglesH,dtype=datatype) mus = 1 # nSamples x nRows x nCols x nDecs X = torch.randn(nSamples,nrows,ncols,nDecs,dtype=datatype,requires_grad=True) dLdZ = torch.randn(nSamples,nrows,ncols,nChsTotal,dtype=datatype) # Expected values ps,pa = nchs W0T = omgs(anglesW,mus).T U0T = omgs(anglesU,mus).T # dLdX = dZdX x dLdZ ms,ma = int(math.ceil(nDecs/2.)),int(math.floor(nDecs/2.)) Ys = dLdZ[:,:,:,:ps].view(nSamples*nrows*ncols,ps).T # ps * n Ya = dLdZ[:,:,:,ps:].view(nSamples*nrows*ncols,pa).T # pa * n Y = torch.cat( ( W0T[:ms,:] @ Ys, # ms x ps @ ps x n U0T[:ma,:] @ Ya ), dim=0) # ma x pa @ pa x n expctddLdX = Y.T.view(nSamples,nrows,ncols,nDecs) # n x (ms+ma) # dLdWi = <dLdZ,(dVdWi)X> expctddLdW_W = torch.zeros(nAnglesH,dtype=datatype) expctddLdW_U = torch.zeros(nAnglesH,dtype=datatype) omgs.partial_difference = True for iAngle in range(nAnglesH): dW0 = omgs(anglesW,mus,index_pd_angle=iAngle) Xs = X[:,:,:,:ms].view(-1,ms).T Zs = dW0[:,:ms] @ Xs # ps x n expctddLdW_W[iAngle] = torch.sum(Ys * Zs) # ps x n if ma>0: dU0 = omgs(anglesU,mus,index_pd_angle=iAngle) Xa = X[:,:,:,ms:].view(-1,ma).T Za = dU0[:,:ma] @ Xa # pa x n expctddLdW_U[iAngle] = torch.sum(Ya * Za) # pa x n # Instantiation of target class layer = NsoltInitialRotation2dLayer( number_of_channels=nchs, decimation_factor=stride, name='V0') layer.orthTransW0.angles.data = anglesW layer.orthTransW0.mus = mus layer.orthTransU0.angles.data = anglesU layer.orthTransU0.mus = mus # Actual values torch.autograd.set_detect_anomaly(True) Z = layer.forward(X) layer.zero_grad() Z.backward(dLdZ) actualdLdX = X.grad actualdLdW_W = layer.orthTransW0.angles.grad actualdLdW_U = layer.orthTransU0.angles.grad # Evaluation self.assertEqual(actualdLdX.dtype,datatype) self.assertEqual(actualdLdW_W.dtype,datatype) self.assertEqual(actualdLdW_U.dtype,datatype) self.assertTrue(torch.allclose(actualdLdX,expctddLdX,rtol=rtol,atol=atol)) self.assertTrue(torch.allclose(actualdLdW_W,expctddLdW_W,rtol=rtol,atol=atol)) self.assertTrue(torch.allclose(actualdLdW_U,expctddLdW_U,rtol=rtol,atol=atol)) self.assertTrue(Z.requires_grad)