我无法访问matlab,因此我尝试使用 octave 进行一些操作。您如何有效地实施以下公式中描述的张量产品?
我对任意订单张量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
作为向量。我不知道这是否是一种有效的方法,因为我通常不编程,而且我是八度新手。你的方法是什么?
我将使用Frobenius规范,见下图,看看是否与显式计算存在差异。
下面是一些用于检查实现的显式计算。它工作正常,但我想问,如果有更好的方法来执行任意订单张量。谢谢!
% 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)
修改
我看了一下tensorlab包,看下面的Metahominid答案,这太棒了。出于好奇,我想检查我的实现,Andras Deak的实现(见下面的答案)和tensorlab包之间的时间性能。
% 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
outprod(对应于我的tp)的tenorlab实现的计算时间t1与tp的t2的比率是针对2-4左右的考虑尺寸(至少在我的计算机上)。这肯定是这种情况,因为在我的实现中我不检查输入中的任何错误,也不会捕获任何未定义的情况。对于t3 / t2,与Andras Deak的方法相比,几乎观察到相同的情况。请不要误解我,我不是要吹嘘,而是要为可能对此感兴趣的人发表一些最后的评论。结论:如果你需要一些适合小型张量的东西,我的简单实现可能对你有用,如果你需要更多东西,你一定要看看tensorlab(参见下面的Metahominid答案)。感谢您的答案和参考资料!
答案 0 :(得分:3)
您拥有的是广义的Kronecker产品。该定义非常适合在Octave中使用array broadcasting实现。为此,您只需将多个前导单例维度注入其中一个数组中作为另一个数组的维度。这就足够了,因为每个数组都有无限数量的隐式尾随维度。
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
隐式兼容。因此,将这两个数组元素相乘可以得到所需的结果。
证明它应该按照您希望的方式工作:
userID
如果你想以不同的方式处理向量(即你希望两个向量的张量积是2d矩阵),你需要自己处理这种特殊情况,因为Octave如何将向量作为行/列矩阵处理。这只是一个微不足道的复杂因素。
答案 1 :(得分:2)
有一个名为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)
是您想要的其他命令。