我的张量大小为(1000、30、16、16)。我正在就如何对其进行标准化进行实验。我正在尝试对各种情况进行标准化,可能是频率轴等。
以下作品:
a = np.random.rand(1000, 30, 16, 16)
a - a.mean(axis=(0, )) #==> it works
a - a.mean(axis=(0, 1)) #==> successful broadcast
a - a.mean(axis=(0, 1, 2)) #==> works well
a - a.mean(axis=(0, 1, 2, 3)) #==> succesful broadcast of scalar mean to all a values
#Those however fail:
a - a.mean(axis=(2, 3))
#OR:
a - a.mean(axis=(0, 2, 3))
我得到:
ValueError:操作数不能与形状(1000,30,16,16)(30,)一起广播
在像这样的简单情况下,它似乎成功完成了缺失的轴 (30,16,16)
(16,16)
(16,)
(1,)
但是当缺少的轴位于右侧而不是左侧时失败,例如: (1000,30),并且无法将其广播到(1000,30,16,16)。
要具体说明我的问题,我该如何规定广播的进行方式? 例如,我有(30,),我想将其广播到(1000,30,16,16)
由于无法广播,将引发错误。我有一个 hacky 解决方案,该解决方案可以对轴进行排列并使得(30,)排在最后,以便广播能够正常工作,但是我想知道是否有一种方法可以指示应该如何进行广播。而且,为什么不自动执行此操作?
答案 0 :(得分:2)
默认情况下,NumPy通过在左侧添加新轴 进行广播。例如,如果数组的形状为(30, 16, 16)
,则它可以自动广播到形状为(1, 30, 16, 16)
。长度为1的新轴可以进一步广播,以匹配其要广播到的阵列所需的任何大小。
这说明了为什么广播在所有这些情况下都有效:
a = np.random.rand(1000, 30, 16, 16)
a - a.mean(axis=(0, )) #==> it works
a - a.mean(axis=(0, 1)) #==> successful broadcast
a - a.mean(axis=(0, 1, 2)) #==> works well
a - a.mean(axis=(0, 1, 2, 3)) #==> succesful broadcast of scalar mean to all a values
在每种情况下,a.mean(...)
都会从左侧移出轴,(可能)在右侧移出轴。
因此广播没有问题,可以自动在左侧重新添加新轴。
相反,a - a.mean(axis=(2, 3))
失败是因为a.mean(axis=(2,3))
的形状为(1000, 30)
,
并且只能播放(1, 1000, 30)
或(1, 1, 1000, 30)
之类的形状。由于a
的形状为(1000, 30, 16, 16)
,因此从右边开始的最后两个轴的长度是冲突的。
在这种情况下,要成功广播,您需要使用{p>
a - a.mean(axis=(2, 3))[..., np.newaxis, np.newaxis]
或
a - a.mean(axis=(2, 3))[..., None, None]
现在a.mean(axis=(2, 3))[..., None, None]
的形状为(1000, 30, 1, 1)
,最多可以广播(1000, 30, 16, 16)
,使其形状与a
兼容。
explicitly add new axes通过说来解释广播
根据广播规则限制这些数组的尾轴大小,表明它们是兼容的:
Image (3d array): 256 x 256 x 3
Scale (1d array): 3
Result (3d array): 256 x 256 x 3
请注意,对齐是通过右对齐形状来完成的。空轴填充为1s。说在左侧添加新轴只是谈论此想法的另一种方式。
答案 1 :(得分:1)
您可以创建要显式广播的其他轴,而不是隐式广播,方法是对要添加的每个轴使用None
进行切片。
要广播(30,)至(1000,30,16,16),像这样切片:
a[None,:,None,None]
您会看到第二个轴被:
切片,这意味着“所有数据”,其余的轴是None
,这意味着“在此处创建一个新的轴进行广播”。
考虑一下,隐式广播最好具有严格的工作规则。想象一下,它可以以此方式自动广播-如果是这样,它将如何广播(30)到(30,30)?这将是模棱两可的。按照当前的规则,它并不是模棱两可的。