我想生成一个关于轴的所有排列对称的随机(高斯)张量。最后,我希望所有条目具有相同的分布,因此对所有排列求和并通过 sqrt(k!) 重新缩放(其中 k 是我的张量的阶数)之类的技巧不起作用。例如:
import numpy as np
from itertools import permutations
noise_buffer = np.random.normal(size=n*n*n).reshape(n,n,n)/np.sqrt(6);
noise = np.zeros([n,n,n]);
for i in permutations([0,1,2]):
noise += np.transpose(noise_buffer,axes=list(i))
我可以遍历所有坐标(-1)并适当地重新缩放,但这很耗时。
您知道有哪个图书馆实现了这一点吗?或者你知道有什么快速实施方法吗?
您可以使用相当简单的元素明智方法,在时间上与张量大小呈线性关系(
d^n
,避免生成所有排列的阶乘开销),这也可以直接让您选择条目分布:
import itertools
import collections
import numpy as np
def random_symmetric(d, ndim, seed=None):
rng = np.random.default_rng(seed)
# choose your desired distribution here
value_store = collections.defaultdict(rng.normal)
x = np.empty((d,) * ndim, dtype=np.float64)
for coo in itertools.product(range(d), repeat=ndim):
key = [0] * d
for i in coo:
key[i] += 1
key = tuple(key)
x[coo] = value_store[key]
return x
解释一下,您只需访问每个元素及其坐标,将坐标“散列”到其各自的排列组中,然后生成或检索该排列组的随机值。例如,坐标
(0, 1, 0, 1, 2, 0, 1)
将具有键 (3, 3, 1)
,因为它有 3 个零、3 个一和 1 个二。生成的独特元素总数将为 comb(ndim + d - 1, d - 1)
。
x = random_symmetric(3, 12)
>1/2 百万个条目大约需要 0.3 秒。 cython/numba 版本应该非常容易适应并且可能更快。
其实,你提出的方法是有效的;它只需要一个小小的修改。
利用正态随机变量之和是另一个正态随机变量的方差之和的事实,例如看这里
问题似乎是您希望噪声条目来自某个分布,但如果您从该分布中获取noise_buffer,那么噪声将具有不同的分布。
解决方案是对noise_buffer使用不同的分布(具体来说,正态分布,标准差减少1/sqrt(k!)),那么噪声将具有正确的分布。