【问题标题】:Efficiently recalculating the gradient of a numpy array with unknown dimensionality有效地重新计算未知维度的 numpy 数组的梯度
【发布时间】:2013-07-20 09:57:36
【问题描述】:

我有一个 N 维 numpy 数组 S。每次迭代,这个数组中只有一个值会改变。

我有第二个数组G,它存储S 的梯度,由numpy 的gradient() 函数计算得出。目前,每次更新S 时,我的代码都会不必要地重新计算所有G,但这是不必要的,因为S 中只有一个值发生了变化,所以我只需要重新计算@987654329 中的1+d*2 值@,其中dS 中的维数。

如果我知道数组的维数,这将是一个更容易解决的问题,但是在没有这些知识的情况下我提出的解决方案效率非常低(并不比重新计算所有 G 好很多) )。

有没有一种有效的方法来仅重新计算G 中的必要值?

编辑:根据要求添加我的尝试

该函数返回一个向量,表示S 在每个维度上coords 处的梯度。它计算这个而不计算S在每一点的梯度,但问题是它似乎不是很有效。

它在某些方面看起来与已经发布的答案相似,但也许有一些效率很低的地方?

想法如下:我遍历每个维度,创建一个仅在该维度中作为向量的切片。对于这些切片中的每一个,我都会计算梯度并将该梯度中的适当值放入返回的向量grad 中的正确位置。

min()max()的使用是为了处理边界条件。

    def getSGradAt(self,coords) :
        """Returns the gradient of S at position specified by
           the vector argument 'coords'.

           self.nDim : the number of dimensions of S
           self.nBins : the width of S (same in every dim)
           self.s : S  """
        grad = zeros(self.nDim)
        for d in xrange(self.nDim) :
            # create a slice through S that has size > 1 only in the current
            # dimension, d. 
            slices = list(coords)
            slices[d] = slice(max(0,coords[d]-1),min(self.nBins,coords[d]+2))
            # take the middle value from the gradient vector
            grad[d] = gradient(self.s[sl])[1] 
        return grad

问题是它运行得不是很快。事实上,只取整个数组的梯度S 似乎跑得更快(对于nBins = 25nDim = 4)。

再次编辑,添加我的最终解决方案

这是我最终使用的。此函数更新S,将X 的值更改为change。然后,它使用 Jaime 提出的技术的变体更新 G

    def changeSField(self,X,change) :
        # change s 
        self.s[X] += change

        # update g (gradient field)
        slices = tuple(slice(None if j-2 <= 0 else j-2, j+3, 1) for j in X)
        newGrads = gradient(self.s[slices])
        for i in arange(self.nDim) :
            self.g[i][slices] = newGrads[i]

【问题讨论】:

  • gradient 如果输入是一维的,则返回一个数组;如果输入的维数不是 1,则返回一个数组列表。看起来它不适合与运行时确定维度的数组,并且该列表将排除您可以对数组进行的大多数巧妙的切片分配。

标签: python numpy multidimensional-array slice


【解决方案1】:

嗯,如果我有一个例子,我可以做得更好,但是创建一个辅助数组 S2 怎么样(顺便说一下,我会为你的变量选择更长和更有意义的名称)并重新计算它的梯度, G2,然后将其引入G?

另一个问题是:如果你不知道 S 的维数,你是如何改变这个变化的特定元素的?你只是重新计算整个 S 吗?

我建议您澄清这些事情,以便人们可以更好地帮助您。 干杯!

【讨论】:

  • 我知道数组在运行时的维数,但在那之前不知道。
  • 感谢您的回复,但我不知道辅助阵列 S2 会有什么帮助。你能澄清一下吗?再次感谢。
  • 我当然可以试着澄清一下。你不舒服的是重新计算整个数组的梯度,S。如果你改变 S[ii,jj](假设二维),唯一会改变的梯度值就是那些 whitin [ii-1: ii+2] 和 [jj-1:jj+2],即以 [ii,jj] 为中心的 3x3 正方形。其余的都不会受到变化的影响,对吧?所以,我建议在 [ii,jj] 周围“切割”一片 S,以便我们重新计算梯度,然后将其插入 G。为此,您需要在 [ii,jj] 周围有一个 5x5 的正方形将采取您需要的 3x3。
  • 我明白你的意思了。是的,这是我试图采用的方法,但挑战是我直到运行时才知道数组的维数。发布的其他回复与我的第一次尝试类似,现在我将其添加到上面的问题文本中。
【解决方案2】:

您的问题很容易得到一个好的答案:发布您的低效代码总是一个好主意,以便潜在的回答者可以更好地帮助您。无论如何,假设您知道已更改点的坐标,并将这些坐标存储在名为coords 的元组中。首先,让我们构建一个包含您的点的切片元组:

slices = tuple(slice(None if j-1 <= 0 else j-1, j+2, 1) for j in coords)

您可能希望将限制扩展到j-2j+3,以便尽可能使用中心差来计算梯度,但这会更慢。

您现在可以执行以下操作来更新您的数组:

G[slices] = np.gradient(N[slices])

【讨论】:

  • 感谢您的回复。这似乎是正确的方向。为了使其与渐变兼容(参见上面 user2357112 的评论),分配需要比您建议的多一点。 for i in arange(len(g)) : g[i][slices] = s[i]
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-11
  • 2014-02-11
  • 1970-01-01
  • 2019-11-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多