【问题标题】:Use of bsxfun with singleton expansion with matrixes of three dimensions将 bsxfun 与具有三维矩阵的单例扩展一起使用
【发布时间】:2016-01-13 21:52:05
【问题描述】:

我正在使用bsxfun 对具有大小矩阵之间的单例扩展的操作进行矢量化:

MS: (nms, nls)
KS: (nks, nls)

该运算是1:nmsMS(m,l)m1:nls 中每个l 以及1:nks 中每个KS(k,l)k 之间的绝对差之和。

我是通过代码实现的:

[~, nls] = size(MS);
MS = reshape(MS',1,nls,[]);
R = sum(abs(bsxfun(@minus,MS,KS)));

R 的大小为 (nls, nms)

我想将此操作推广到样本列表,因此新大小将是:

MS: (nxs, nls, nms)
KS: (nxs, nls, nks)

这可以通过为每个二维矩阵执行第一段代码的 for 循环轻松实现,但我怀疑通过添加新维度来概括以前的代码,性能可能会更好。

R 的大小为:(nxs, nls, nms)

我试图将MS 重塑为 4 维,但没有成功。这可以通过重塑和bsxfun来完成吗?

【问题讨论】:

  • 可以,但是您对尺寸的描述对我来说有点不清楚。你能举个小例子吗?或者解释一下新尺寸与旧尺寸的关系?
  • 我添加了一个基于bsxfunpermute 的答案。如果您的尺寸很大并且性能很重要,那么将permute 放在首位可能会更快,以便summation 作用于连续的内存块。
  • 你的意思是在 MS 上置换?
  • @jruizaranguren 我的意思是使用sum(permute(abs(bsxfun(...)),[4 1 2 3]),1),其中... 与以前相同。或者类似的东西,我不确定什么是有效的。
  • @jruizaranguren 事实证明我的天真想法太天真了......我用可能的工作加速更新了我的答案。

标签: matlab matrix vectorization bsxfun


【解决方案1】:

你可能需要这个:

% generate small dummy data
nxs = 2;
nls = 3;
nms = 4;
nks = 5;
MS = rand(nxs, nls, nms);
KS = rand(nxs, nls, nks);

R = sum(abs(bsxfun(@minus,MS,permute(KS,[1,2,4,3]))),4)

这将产生一个大小为[2,3,4] 的矩阵,即[nxs,nls,nms]。每个元素[k1,k2,k3] 将对应

R(k1,k2,k3) == sum_k abs(MS(k1,k2,k3) - KS(k1,k2,k))

例如,在我的随机运行中

R(2,1,3)

ans =

   1.255765020150647

>> sum(abs(MS(2,1,3)-KS(2,1,:)))

ans =

   1.255765020150647

诀窍是用permute 引入单例维度:permute(KS,[1,2,4,3]) 的大小为[nxs,nls,1,nks],而MS 的大小为[nxs,nls,nms] 的大小也隐含地为[nxs,nls,nms,1]:假定MATLAB 中的每个数组拥有可数无限数量的尾随单例维度。从这里很容易看出如何bsxfun 将大小分别为[nxs,nls,nms,1][nxs,nls,1,nks] 的数组组合在一起,以获得大小为[nxs,nls,nms,nks] 的数组。沿维度 4 求和即可达成交易。


我在评论中指出,将 permute 放在首位可能会更快。事实证明,这本身会使代码运行变慢。但是,通过重塑数组以减小维度大小,整体性能会提高(由于优化的内存访问)。比较一下:

% generate larger dummy data
nxs = 20;
nls = 30;
nms = 40;
nks = 500;
MS = rand(nxs, nls, nms);
KS = rand(nxs, nls, nks);

MS2 = permute(MS,[4 3 2 1]);
KS2 = permute(KS,[3 4 2 1]);
R3 = permute(squeeze(sum(abs(bsxfun(@minus,MS2,KS2)),1)),[3 2 1]);

我所做的是将求和的nks 维度放在首位,然后按降序排列其余维度。这可以自动完成,我只是不想使示例过于复杂。在您的用例中,您可能无论如何都会知道尺寸的大小。

具有上述两个代码的运行时:原始代码为 0.07028 秒,重新排序的代码为 0.051162 秒(最好是 5 个)。不幸的是,更大的示例现在不适合我的记忆。

【讨论】:

  • 4D 置换!不错!!
  • @Divakar 谢谢!:) 我希望有一天能达到你的 6D 水平;)
  • @AndrasDeak,我已经能够重现相同的行为。在我的情况下,尺寸保持 nxs >> nks > nms ~ nls,所以我可以事先安排它。尽管如此,一旦 nxs 排在首位,我并没有得到明显的改善。
  • @jruizaranguren 你有没有试过我写的,求和维度是第一位的,而其余的是按降序排列的?要么,要么“nxs first”,要么未置换的原始版本应该是最快的。
  • @AndrasDeak,对不起,我读得太快了。使用大小为 (10000, 10, 100) 的矩阵,我可以使用原始代码获得更好的性能。
猜你喜欢
  • 1970-01-01
  • 2016-05-08
  • 1970-01-01
  • 1970-01-01
  • 2013-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-25
相关资源
最近更新 更多