Как создать тест для функции partial_tucker из тензорного метода?

Я пытаюсь разработать тест, чтобы убедиться, что partial_tuckerфункция от tenorly работает так, как я ожидаю. Другими словами, я хочу создать вход дляpartial_tucker функция вместе с соответствующим ожидаемым результатом.

Итак, я попытался взять начальный случайный тензор A (порядка 4), вычислите его разложение таккера "низкого ранга" вручную, затем восстановите тензор той же формы, что и исходный тензор, скажем A_tilde. я думаюA_tilde тензор тогда является "приближением низкого ранга" исходного тензора A. Я прав?

Тогда я хотел бы нам partial_tucker функция на этом A_tildeтензор, и я ожидаю, что результат будет таким же, как разложение Таккера, которое я вычислил вручную. Это не тот случай, поэтому я думаю, что моя ручная декомпозиция таккера неверна. Если да, то почему?

import tensorly
import numpy as np

h, w, c, f = 3, 3, 64, 128
c_prim, f_prim = 16, 32
base_tensor = np.random.rand(h, w, c, f)


# compute tucker decomposition by hand using higher order svd describred here: https://www.alexejgossmann.com/tensor_decomposition_tucker/.
lst_fac = []
for k in [2, 3]:
    mod_k_unfold = tensorly.base.unfold(base_tensor, k)
    U, _, _ = np.linalg.svd(mod_k_unfold)
    lst_fac.append(U)

real_in_fac, real_out_fac = lst_fac[0], lst_fac[1]
real_core = multi_mode_dot(base_tensor, [real_in_fac.T, real_out_fac.T], modes=(2,3))
del base_tensor  # no need of it anymore

# what i call the "low rank tucker decomposition"
real_core = real_core[:,:,:c_prim,:f_prim]
real_in_fac = real_in_fac[:, :c_prim]
real_out_fac = real_out_fac[:, :f_prim]

# low rank approximation
base_tensor_low_rank = multi_mode_dot(real_core, [real_in_fac, real_out_fac], modes=(2,3))
in_rank, out_rank = c_prim, f_prim
core_tilde, (in_fac_tilde, out_fac_tilde) = partial_tucker(base_tensor_low_rank, modes=(2, 3), ranks=(in_rank, out_rank), init='svd')
base_tensor_tilde = multi_mode_dot(core_tilde, [in_fac_tilde, out_fac_tilde], modes=(2,3))
assert np.allclose(base_tensor_tilde, base_tensor_low_rank) # this is OK

assert np.allclose(in_fac_tilde, real_in_fac) # this fails

Обратите внимание, что я попытался вычислить in_fac_tilde.T @ real_in_fac чтобы увидеть, была ли это идентичность или что-то в этом роде, и я заметил, что только первый столбец был коллинеарен в обеих матрицах и ортогонален всем остальным.

1 ответ

Решение

Здесь вы неявно делаете много предположений: вы предполагаете, например, что вы можете просто обрезать разложение по рангу R, чтобы получить разложение по рангу (R-1). Это вообще не так. Также обратите внимание, что используемое вами разложение Такера - это не просто SVD высшего порядка (HO-SVD). Вместо этого для инициализации используется HO-SVD, за которым следует ортогональная итерация более высокого порядка (HOOI).

Вы также предполагаете, что разложение низкого ранга уникально для любого данного ранга, что позволит вам напрямую сравнивать факторы разложения. Это также не так (даже в матричном случае и с сильными ограничениями, такими как ортонормированность, у вас все равно будет неопределенность знака).

Вместо этого вы можете, например, проверить относительную ошибку реконструкции. Предлагаю вам взглянуть на тесты в TensorLy. Если вы начинаете с тензоров, по этому поводу есть много хороших ссылок. Например, плодотворная работа Колды и Бадера; для Такера, в частности, работа Де Латхауэра и др. (например, о наилучшем приближении тензоров низкого ранга) и т. д.

Другие вопросы по тегам