Как мне создать тест для функцииpart_tucker из тензорного? - PullRequest
0 голосов
/ 04 апреля 2020

Я пытаюсь разработать тест, чтобы убедиться, что функция partial_tucker из тензорно работает так, как я ожидаю, что она будет работать. Другими словами, я хочу спроектировать вход для функции 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 Ответ

1 голос
/ 23 апреля 2020

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

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

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

...