tensorly.tenalg
.unfolding_dot_khatri_rao
- unfolding_dot_khatri_rao(tensor, cp_tensor, mode)[source]
mode-n unfolding times khatri-rao product of factors
- Parameters:
- tensortl.tensor
tensor to unfold
- factorstl.tensor list
list of matrices of which to the khatri-rao product
- modeint
mode on which to unfold tensor
- Returns:
- mttkrp
dot(unfold(tensor, mode), khatri-rao(factors))
Notes
This is a variant of:
unfolded = unfold(tensor, mode) kr_factors = khatri_rao(factors, skip_matrix=mode) mttkrp2 = tl.dot(unfolded, kr_factors)
Multiplying with the Khatri-Rao product is equivalent to multiplying, for each rank, with the kronecker product of each factor. In code:
mttkrp_parts = [] for r in range(rank): component = tl.tenalg.multi_mode_dot(tensor, [f[:, r] for f in factors], skip=mode) mttkrp_parts.append(component) mttkrp = tl.stack(mttkrp_parts, axis=1) return mttkrp
This can be done by taking n-mode-product with the full factors (faster but more memory consuming):
projected = multi_mode_dot(tensor, factors, skip=mode, transpose=True) ndims = T.ndim(tensor) res = [] for i in range(factors[0].shape[1]): index = tuple([slice(None) if k == mode else i for k in range(ndims)]) res.append(projected[index]) return T.stack(res, axis=-1)
The same idea could be expressed using einsum:
ndims = tl.ndim(tensor) tensor_idx = ''.join(chr(ord('a') + i) for i in range(ndims)) rank = chr(ord('a') + ndims + 1) op = tensor_idx for i in range(ndims): if i != mode: op += ',' + ''.join([tensor_idx[i], rank]) else: result = ''.join([tensor_idx[i], rank]) op += '->' + result factors = [f for (i, f) in enumerate(factors) if i != mode] return tl_einsum(op, tensor, *factors)