def test_validate_cp_tensor(): rng = tl.check_random_state(12345) true_shape = (3, 4, 5) true_rank = 3 cp_tensor = random_cp(true_shape, true_rank) (weights, factors) = cp_normalize(cp_tensor) # Check correct rank and shapes are returned shape, rank = _validate_cp_tensor((weights, factors)) assert_equal( shape, true_shape, err_msg='Returned incorrect shape (got {}, expected {})'.format( shape, true_shape)) assert_equal( rank, true_rank, err_msg='Returned incorrect rank (got {}, expected {})'.format( rank, true_rank)) # One of the factors has the wrong rank factors[0], copy = tl.tensor(rng.random_sample((4, 4))), factors[0] with assert_raises(ValueError): _validate_cp_tensor((weights, factors)) # Not the correct amount of weights factors[0] = copy wrong_weights = weights[1:] with assert_raises(ValueError): _validate_cp_tensor((wrong_weights, factors)) # Not enough factors with assert_raises(ValueError): _validate_cp_tensor((weights[:1], factors[:1]))
def test_cp_copy(): shape = (3, 4, 5) rank = 4 cp_tensor = random_cp(shape, rank) weights, factors = cp_tensor weights_normalized, factors_normalized = cp_normalize(cp_tensor.cp_copy()) # Check that modifying copy tensor doesn't change the original tensor assert_array_almost_equal(cp_to_tensor((weights, factors)), cp_to_tensor(cp_tensor))
def test_cp_normalize(): shape = (3, 4, 5) rank = 4 cp_tensor = random_cp(shape, rank) weights, factors = cp_normalize(cp_tensor) expected_norm = tl.ones(rank) for f in factors: assert_array_almost_equal(tl.norm(f, axis=0), expected_norm) assert_array_almost_equal(cp_to_tensor((weights, factors)), cp_to_tensor(cp_tensor))
def test_cp_flip_sign(): shape = (3, 4, 5) rank = 4 cp_tensor = random_cp(shape, rank) weights, factors = cp_flip_sign(cp_tensor) assert_(tl.all(tl.mean(factors[1], axis=0) > 0)) assert_(tl.all(tl.mean(factors[2], axis=0) > 0)) assert_equal(cp_tensor.rank, cp_tensor.rank) assert_array_equal(cp_tensor.weights, weights) assert_array_almost_equal(cp_to_tensor((weights, factors)), cp_to_tensor(cp_tensor))
def test_cp_norm(): """Test for cp_norm """ shape = (8, 5, 6, 4) rank = 25 cp_tensor = random_cp(shape=shape, rank=rank, full=False, normalise_factors=True) tol = 10e-5 rec = tl.cp_to_tensor(cp_tensor) true_res = tl.norm(rec, 2) res = cp_norm(cp_tensor) assert_(tl.abs(true_res - res) <= tol)
def test_cp_lstsq_grad(): """Validate the gradient calculation between a CP and dense tensor.""" shape = (2, 3, 4) rank = 2 cp_tensor = random_cp(shape, rank, normalise_factors=False) # If we're taking the gradient of comparison with self it should be 0 cp_grad = cp_lstsq_grad(cp_tensor, cp_to_tensor(cp_tensor)) assert_(cp_norm(cp_grad) <= 10e-5) # Check that we can solve for a direction of descent dense = random_cp(shape, rank, full=True, normalise_factors=False) cost_before = tl.norm(cp_to_tensor(cp_tensor) - dense) cp_grad = cp_lstsq_grad(cp_tensor, dense) cp_new = CPTensor(cp_tensor) for ii in range(len(shape)): cp_new.factors[ii] = cp_tensor.factors[ii] - 1e-3 * cp_grad.factors[ii] cost_after = tl.norm(cp_to_tensor(cp_new) - dense) assert_(cost_before > cost_after)
def test_cp_to_tensor_with_weights(): A = tl.reshape(tl.arange(1,5), (2,2)) B = tl.reshape(tl.arange(5,9), (2,2)) weigths = tl.tensor([2,-1], **tl.context(A)) out = cp_to_tensor((weigths, [A,B])) expected = tl.tensor([[-2,-2], [6, 10]]) # computed by hand assert_array_equal(out, expected) (weigths, factors) = random_cp((5, 5, 5), rank=5, normalise_factors=True, full=False) true_res = tl.dot(tl.dot(factors[0], tl.diag(weigths)), tl.transpose(tl.tenalg.khatri_rao(factors[1:]))) true_res = tl.fold(true_res, 0, (5, 5, 5)) res = cp_to_tensor((weigths, factors)) assert_array_almost_equal(true_res, res, err_msg='weights incorrectly incorporated in cp_to_tensor')
def test_sort(): """ Test that sorting does not affect anything. """ tOrig, mOrig = createCube() tFac = random_cp(tOrig.shape, 3) tFac.mFactor = np.random.randn(mOrig.shape[1], 3) R2X = calcR2X(tFac, tOrig, mOrig) tRec = tl.cp_to_tensor(tFac) mRec = buildGlycan(tFac) tFac = sort_factors(tFac) sR2X = calcR2X(tFac, tOrig, mOrig) stRec = tl.cp_to_tensor(tFac) smRec = buildGlycan(tFac) np.testing.assert_allclose(R2X, sR2X) np.testing.assert_allclose(tRec, stRec) np.testing.assert_allclose(mRec, smRec)
def test_unfolding_dot_khatri_rao(): """Test for unfolding_dot_khatri_rao Check against other version check sparse safe """ shape = (10, 10, 10, 4) rank = 5 tensor = tl.tensor(np.random.random(shape)) weights, factors = random_cp(shape=shape, rank=rank, full=False, normalise_factors=True) for mode in range(tl.ndim(tensor)): # Version forming explicitely the khatri-rao product unfolded = unfold(tensor, mode) kr_factors = khatri_rao(factors, weights=weights, skip_matrix=mode) true_res = tl.dot(unfolded, kr_factors) # Efficient sparse-safe version res = unfolding_dot_khatri_rao(tensor, (weights, factors), mode) assert_array_almost_equal(true_res, res, decimal=3)
def test_cp_mode_dot(): """Test for cp_mode_dot We will compare cp_mode_dot (which operates directly on decomposed tensors) with mode_dot (which operates on full tensors) and check that the results are the same. """ rng = tl.check_random_state(12345) shape = (5, 4, 6) rank = 3 cp_ten = random_cp(shape, rank=rank, orthogonal=True, full=False) full_tensor = tl.cp_to_tensor(cp_ten) # matrix for mode 1 matrix = tl.tensor(rng.random_sample((7, shape[1]))) # vec for mode 2 vec = tl.tensor(rng.random_sample(shape[2])) # Test cp_mode_dot with matrix res = cp_mode_dot(cp_ten, matrix, mode=1, copy=True) # Note that if copy=True is not respected, factors will be changes # And the next test will fail res = tl.cp_to_tensor(res) true_res = mode_dot(full_tensor, matrix, mode=1) assert_array_almost_equal(true_res, res) # Check that the data was indeed copied rec = tl.cp_to_tensor(cp_ten) assert_array_almost_equal(full_tensor, rec) # Test cp_mode_dot with vec res = cp_mode_dot(cp_ten, vec, mode=2, copy=True) res = tl.cp_to_tensor(res) true_res = mode_dot(full_tensor, vec, mode=2) assert_equal(res.shape, true_res.shape) assert_array_almost_equal(true_res, res)
def initialize_cp(tensor, rank, init='svd', svd='numpy_svd', random_state=None, non_negative=False, normalize_factors=False): r"""Initialize factors used in `parafac`. The type of initialization is set using `init`. If `init == 'random'` then initialize factor matrices using `random_state`. If `init == 'svd'` then initialize the `m`th factor matrix using the `rank` left singular vectors of the `m`th unfolding of the input tensor. Parameters ---------- tensor : ndarray rank : int init : {'svd', 'random'}, optional svd : str, default is 'numpy_svd' function to use to compute the SVD, acceptable values in tensorly.SVD_FUNS non_negative : bool, default is False if True, non-negative factors are returned Returns ------- factors : CPTensor An initial cp tensor. """ rng = check_random_state(random_state) if init == 'random': # factors = [tl.tensor(rng.random_sample((tensor.shape[i], rank)), **tl.context(tensor)) for i in range(tl.ndim(tensor))] # kt = CPTensor((None, factors)) return random_cp(tl.shape(tensor), rank, normalise_factors=False, random_state=rng, **tl.context(tensor)) elif init == 'svd': try: svd_fun = tl.SVD_FUNS[svd] except KeyError: message = 'Got svd={}. However, for the current backend ({}), the possible choices are {}'.format( svd, tl.get_backend(), tl.SVD_FUNS) raise ValueError(message) factors = [] for mode in range(tl.ndim(tensor)): U, S, _ = svd_fun(unfold(tensor, mode), n_eigenvecs=rank) # Put SVD initialization on the same scaling as the tensor in case normalize_factors=False if mode == 0: idx = min(rank, tl.shape(S)[0]) U = tl.index_update(U, tl.index[:, :idx], U[:, :idx] * S[:idx]) if tensor.shape[mode] < rank: # TODO: this is a hack but it seems to do the job for now # factor = tl.tensor(np.zeros((U.shape[0], rank)), **tl.context(tensor)) # factor[:, tensor.shape[mode]:] = tl.tensor(rng.random_sample((U.shape[0], rank - tl.shape(tensor)[mode])), **tl.context(tensor)) # factor[:, :tensor.shape[mode]] = U random_part = tl.tensor( rng.random_sample( (U.shape[0], rank - tl.shape(tensor)[mode])), **tl.context(tensor)) U = tl.concatenate([U, random_part], axis=1) factors.append(U[:, :rank]) kt = CPTensor((None, factors)) elif isinstance(init, (tuple, list, CPTensor)): # TODO: Test this try: kt = CPTensor(init) except ValueError: raise ValueError( 'If initialization method is a mapping, then it must ' 'be possible to convert it to a CPTensor instance') else: raise ValueError( 'Initialization method "{}" not recognized'.format(init)) if non_negative: kt.factors = [tl.abs(f) for f in kt[1]] if normalize_factors: kt = cp_normalize(kt) return kt