如何在pytorch中创建一个正常的二维分布

How to create a normal 2d distribution in pytorch

给定一个包含 N 个点的张量,用 [x,y] 表示,我想围绕每个点创建一个二维高斯分布,将它们绘制在一个空的特征图上。

例如,左图显示了一个给定的点(在特征图上注册为一个像素,其值设置为1)。右图在其周围添加了 2D 高斯分布。

如何为每个点添加这样的分布? pytorch 中有 API 吗?

从多元正态分布中抽样

您可以使用 MultivariateNormal 从多元正态样本中抽样。

>>> h, w = 200, 200
>>> fmap = torch.zeros(h, w)

用原点填充fmap

>>> pts = torch.rand(20, 2)
>>> pts *= torch.tensor([h, w])
>>> x, y = pts.T.long()
>>> x, y = x.clip(0, h), y.clip(0, w)

>>> fmap[x, y] = 1

在此之后,我们可以从以下分布中采样(您可以相应地调整协方差矩阵):

>>> sampler = MultivariateNormal(pts.T, 10*torch.eye(len(pts)))

>>> for x in range(10):
...    x, y = sampler.sample()
...    x, y = x.clip(0, h).long(), y.clip(0, w).long()
...    fmap[x, y] = 1

因此,您可能会得到如下结果:

Origin points Normal sampling

这没有很好地记录,但您可以将样本形状传递给 sample 函数。这允许您在每次调用中采样多个点,您只需要一个来填充您的canvas。

这是一个从MultivariateNormal:

中提取的函数
def multivariate_normal_sampler(mean, cov, k):
    sampler = MultivariateNormal(mean, cov)
    return sampler.sample((k,)).swapaxes(0,1).flatten(1)

那么你可以这样称呼它:

>>> x, y = multivariate_normal_sampler(mean=pts.T, cov=50*torch.eye(len(pts)), k=1000)

剪辑示例:

>>> x, y = x.clip(0, h-1).long(), y.clip(0, w-1).long()

最后插入fmap并绘制:

>>> fmap[x, y] += .1

这是一个示例预览:

k=1,000 k=50,000

效用函数可用 torch.distributions.multivariate_normal.MultivariateNormal


使用 pdf

计算密度图

或者,您可以根据概率密度函数 (pdf) 计算密度值,而不是从正态分布中抽样:

A particular example of a two-dimensional Gaussian function is:

原点:

>>> h, w = 50, 50
>>> x0, y0 = torch.rand(2, 20)
>>> origins = torch.stack((x0*h, y0*w)).T

定义 gaussian 2D pdf:

def gaussian_2d(x=0, y=0, mx=0, my=0, sx=1, sy=1):
    return 1 / (2*math.pi*sx*sy) * \
      torch.exp(-((x - mx)**2 / (2*sx**2) + (y - my)**2 / (2*sy**2)))

构造网格并从每个原点累积高斯:

x = torch.linspace(0, h, h)
y = torch.linspace(0, w, w)
x, y = torch.meshgrid(x, y)

z = torch.zeros(h, w)
for x0, y0 in origins:
  z += gaussian_2d(x, y, mx=x0, my=y0, sx=h/10, sy=w/10)
Multivariate normal distributions

绘制值网格的代码只是使用 matplotlib.pyplot.pcolormeshplt.pcolormesh(x, y, z).