广义矩阵乘积

8
我对MATLAB还很陌生。M x K 矩阵和 K x N 矩阵的普通矩阵乘法 -- C = A * B-- 满足 c_ij = sum(a_ik * b_kj, k = 1:K)。如果我想要改成c_ij = sum(op(a_ik, b_kj), k = 1:K),其中 op 是某个简单的二元运算符,有没有什么方法在 MATLAB 中进行向量化(或者甚至内置函数)?
编辑:这是目前我能做到的最好的程度。
% A is M x K, B is K x N
% op is min
C = zeros(M, N);
for i = 1:M:
    C(i, :) = sum(bsxfun(@min, A(i, :)', B));
end

这里列出的任何解决方案对您有用吗? - Divakar
4个回答

2

这篇文章介绍了一种向量化的方法,它使用 bsxfun 并利用 permute 创建 singleton 维度来满足 bsxfun 的需要,让 singleton-expansion 来完成其工作,从而本质上替代原始帖子中的循环。请注意,bsxfun 是一个内存密集型的实现,因此只有在不会过度拉伸它时才会带来加速效果。以下是最终的解决方案代码-

op = @min;   %// Edit this with your own function/ operation
C = sum(bsxfun(op, permute(A,[1 3 2]),permute(B,[3 2 1])),3)

NB - 上述解决方案的灵感来自于在Matlab中删除四个嵌套循环


bsxfun的文档没有表明它会占用大量内存。你是怎么确定这个事实的?我之前并不知道bsxfun会有这个问题。 - John
2
@John,根据其定义bsxfun在内部扩展单例维度,然后执行逐元素操作。这种扩展实际上需要一个如此大的连续内存区域。寻找连续内存意味着更多的运行时间。当基于bsxfun的代码运行时,可以通过观察系统监视器来确认其“贪婪”的内存特性。但使用bsxfun的好处是一旦分配了内存,操作就以超快的方式完成。希望这有些意义! - Divakar

1

如果运算符可以逐个元素操作(例如.*):

if(size(A,2)~=size(B,1))
    error(blah, blah, blah...);
end

C = zeros(size(A,1),size(B,2));
for i = 1:size(A,1)
    for j = 1:size(B,2)
        C(i,j) = sum(binaryOp(A(i,:)',B(:,j)));
    end
end

我实际上有一种方法可以使用一个for循环(使用bsxfun)来完成它。我想知道是否有一种纯向量化的方法来完成它。 - Nick
我已将我的当前算法添加到原始帖子中。 - Nick

0

你总是可以自己编写循环:

A = rand(2,3);
B = rand(3,4);

op = @times;            %# use your own function here
C = zeros(size(A,1),size(B,2));
for i=1:size(A,1)
    for j=1:size(B,2)
        for k=1:size(A,2)
            C(i,j) = C(i,j) + op(A(i,k),B(k,j));
        end
    end
end

isequal(C,A*B)

0

感谢您引起我对这个问题的注意! - Divakar
@Divakar感谢您提供的出色答案!如果您对另一个类似的挑战感兴趣,我已经发布了一个关于广义矩阵乘法的问题,目标是在优化方面进一步提高水平:https://dev59.com/eWAf5IYBdhLWcg3w0VYf - gaborous

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接