Как реализовать тензорное произведение для тензоров произвольного порядка в октаве? - PullRequest
0 голосов
/ 04 июня 2018

У меня нет доступа к matlab, поэтому я пробую кое-что с октавой .Как бы вы эффективно реализовали тензорное произведение, описанное в следующей формуле?

enter image description here

Мой подход для тензоров произвольного порядка a и b следующий

% Tensor product
function out = tp(a,b)
  if isvector(a)
    da = prod(size(a));
  else
    da = size(a);
  endif
  if isvector(b)
    db = prod(size(b));
  else
    db = size(b);
  endif
  out = reshape(a(:)*(b(:)'),[da,db]);
endfunction

ifоператоры существуют только для того, чтобы уловить случай, когда a или b являются векторами.Я не знаю, является ли это эффективным подходом, так как я обычно не программирую, и я новичок в октаве.Каков будет ваш подход?

Я буду использовать норму Фробениуса, см. Рисунок ниже, чтобы увидеть, есть ли разница с явным вычислением.

enter image description here

Ниже приведены некоторые явные вычисления для проверки реализации.Это прекрасно работает, но я хотел спросить, есть ли лучший способ сделать это для тензоров произвольного порядка.Спасибо!

% Frobenius norm
function out = nf(a)
  out = sqrt(a(:)'*a(:));
endfunction

% Tests for (m,n)
% (1,1)
disp("(1,1)")
a = rand(4,1);
b = rand(7,1);
c1 = tp(a,b);
c2 = zeros(4,7);
for i1=1:4 for i2=1:7
  c2(i1,i2) = a(i1)*b(i2);
endfor endfor
size(c1)
size(c2)
nf(c1-c2)

%(1,2)
disp("(1,2)")
a = rand(4,1);
b = rand(7,3);
c1 = tp(a,b);
c2 = zeros(4,7,3);
for i1=1:4 for i2=1:7 for i3=1:3
  c2(i1,i2,i3) = a(i1)*b(i2,i3);
endfor endfor endfor
size(c1)
size(c2)
nf(c1-c2)

%(2,1)
disp("(2,1)")
a = rand(4,2);
b = rand(1,3);
c1 = tp(a,b);
c2 = zeros(4,2,3);
for i1=1:4 for i2=1:2 for i3=1:3
  c2(i1,i2,i3) = a(i1,i2)*b(i3);
endfor endfor endfor
size(c1)
size(c2)
nf(c1-c2)

%(3,2)
disp("(3,2)")
a = rand(4,2,5);
b = rand(7,3);
c1 = tp(a,b);
c2 = zeros(4,2,5,7,3);
for i1=1:4 for i2=1:2 for i3=1:5 for i4=1:7 for i5=1:3
  c2(i1,i2,i3,i4,i5) = a(i1,i2,i3)*b(i4,i5);
endfor endfor endfor endfor endfor
size(c1)
size(c2)
nf(c1-c2)

РЕДАКТИРОВАТЬ

Я взглянул на пакет tenorlab, см. Ответ Метахоминида ниже, и это фантастика.Просто для любопытства я хотел проверить производительность по времени между моей реализацией, реализацией Андраса Дика (см. Его ответ ниже) и пакетом tennslab.

% See Andras Deak answer
function c=tensorprod(a, b)
   b_inj = reshape(b, [ones(1,ndims(a)), size(b)]);
   c = a.*b_inj;
end

% Tests
a = rand(10,11,12);
b = rand(9,8,7);
tic; c1=outprod(a,b); t1=toc % tensorlab, see Metahominid's answer
tic; c2=tp(a,b); t2=toc % my approach
tic; c3=tensorprod(a,b); t3=toc % Andras Deak's approach
disp("Check size")
size(c1)
size(c2)
size(c3)
disp("Check Frobenius norm")
frob(c1) % from tensorlab
nf(c2)
disp("Check equality of elements")
nf(c1-c2)
nf(c1-c3)
disp("Compare time performance relative to tp(a,b)")
t1/t2
t3/t2

Соотношение времени вычислений t1 реализации тензорного потока outprod (соответствующего моему tp) и t2 для tp для рассматриваемых измерений около 2-4 (по крайней мере, на моем компьютере).Это, безусловно, так, поскольку в моей реализации я не проверяю наличие ошибок на входе и не отлавливаю неопределенные случаи.Почти то же самое наблюдается для t3 / t2, сравнивая подход Андраса Дика к моему.Пожалуйста, не поймите меня неправильно, я не пытаюсь похвастаться, но хочу дать несколько заключительных замечаний для людей, которые могут быть заинтересованы в этом.Вывод: если вам нужно что-то для небольших тензоров на ходу, моя простая реализация может быть полезна для вас, если вам нужно больше вещей, вам определенно стоит взглянуть на тензорный меч (см. Ответ Метахоминида ниже).Спасибо за ответы и отзывы!

Ответы [ 2 ]

0 голосов
/ 05 июня 2018

То, что у вас есть, является обобщенным продуктом Кронекера.Определение идеально подходит для использования вещания массива в Octave.Для этого вам нужно только ввести столько ведущих одноэлементных измерений в один из ваших массивов, сколько измерений другого массива.Этого достаточно, поскольку каждый массив имеет бесконечное число неявных конечных измерений.

function c=tensorprod(a, b)
   b_inj = reshape(b, [ones(1,ndims(a)), size(b)]);
   c = a.*b_inj;
end

Если a имеет размер (i,j,k), а b имеет (m,n), b_inj имеет размер (1,1,1,m,n)и a уже неявно совместим с размером (i,j,k,1,1).Таким образом, умножение этих двух массивов поэлементно дает желаемый результат.

Доказательство того, что оно должно работать так, как вы хотите:

octave:29> a = rand(2,3);
octave:30> b = rand(4,5);
octave:31> c = tensorprod(a,b);
octave:32> size(c)
ans =

   2   3   4   5

octave:33> c(1,3,2,3) == a(1,3)*b(2,3) % indices chosen by fair dice roll
ans =  1

Если вы хотите обрабатывать векторы по-разному (т.е. вы хотитетензорное произведение двух векторов на 2d-матрицу), вам нужно обрабатывать этот особый случай самостоятельно из-за способа, которым Octave обрабатывает векторы как матрицы строк / столбцов.Это только тривиальное осложнение.

0 голосов
/ 04 июня 2018

Существует нечто, называемое Tensorlab , которое, насколько я могу судить, можно использовать с Octave. .Вы просто должны загрузить его, получив ссылку.

Редактировать: он имеет оба из них и будет значительно быстрее.

[H,Heff] = hankelize(linspace(0,1,1000),'order',3);
tic; disp(frob(H)); toc; % Using the dense tensor H
tic; disp(frob(Heff)); toc; % Using the efficient representation of H
3.2181e+03
Elapsed time is 0.026401 seconds.
3.2181e+03
Elapsed time is 0.000832 seconds.

outprod(T1,T2)

- другая команда, которую вы хотите.

...