【问题标题】:Can numpy optimized code recieve significant increase in speed by rewriting it in Cython?numpy 优化的代码可以通过在 Cython 中重写来显着提高速度吗?
【发布时间】:2018-07-16 15:12:39
【问题描述】:

我有一些 python 代码在 2d 和 3d numpy 数组上进行数值计算。代码的优化方式是不使用任何 for 循环,只使用 numpy 操作。所有操作都在float 类型上完成。

这些是使用的numpy操作:numpy.zeros、numpy.reshape、numpy.where、numpy.logical_or.reduce、numpy.put、numpy.add、numpy.subtract、numpy.true_devide、numpy.rint

我运行了一些测试,开销位于 numpy.where、numpy.put 和 numpy.rintoperations 内。

我的问题是,因为我已经优化了代码,因为它只使用了 numpy 操作,如果我在 Cython 中重写我的一段代码时可以期待任何显着的加速。或者可能有其他选择?其余代码在 Python 中,并且必须保留在 Python 中。一个显着的增长将是平均速度提高约 20%。

EDIT1:

# <im> is a 2d floating point numpy array
# <w,h> are the width and hight of <im>    

pdt = np.rint(np.add(pix[:,None,:], np.multiply(depthValOfU[:,None], features[:,0]))).astype(int)
d_two = np.zeros(2000*500)
pdt = np.reshape(pdt, (2000*500, 2))
np.put(d_two, np.where(np.logical_or.reduce((pdt[:,0] < 0, pdt[:,0] > w, pdt[:,1] < 0, pdt[:,1] > h))), self.const)
zero_ind = np.where(d_two < 1000)  
np.put(d_two, zero_ind, im[pdt[zero_ind,0], pdt[zero_ind,1]])

为了使这段代码可以运行,我需要提供相当多的代码,但我希望这有助于理解它。

【问题讨论】:

  • 如果没有看到代码,真的不可能说任何加速的重要性。非常普遍:如果在任何地方都可以对整个数组进行短路评估,或者如果可以在一个循环中对值应用多个操作,那么 Cython 可以提供帮助(这些是只是两个例子)。如果可以的话,请分享您代码的相关部分(或类似代码的相关 sn-p)。
  • 感谢您的回复。我编辑了我的问题以提供一段不可运行的代码。
  • 如果没有可运行的代码,很难说建议的改进是否会有所帮助。在大多数情况下,您可以使用im=np.randn(w,h); pix=randn(????) 等内容轻松创建输入。只要大小与您的实际数据大致相同,这将有助于显示可能有效的方法。
  • 研究 cython 文档的 typed memoryviews 页面
  • 应该是可以通过的。对于性能测试,有必要提供一段运行代码,包括代表性的输入和输出测试数据。矢量化的 numpy 函数通常在性能方面并不差,但在更大的问题上,缓存利用率可能会很差。也有可能多线程你的代码......

标签: python-2.7 performance numpy cython


【解决方案1】:

您对长行和np.put 的使用难以阅读。我认为这是等价的:

pdt = pix[:,None,:] + depthValOfU[:,None]*features[:,0]
pdt = np.rint(pdt).astype(int)
pdt = np.reshape(pdt, (2000*500, 2))

d_two = np.zeros(2000*500)

idx = np.where(np.logical_or.reduce((pdt[:,0] < 0, 
                                     pdt[:,0] > w, 
                                     pdt[:,1] < 0, 
                                     pdt[:,1] > h)))
d_two[idx] = self.const

zero_ind = np.where(d_two < 1000)  
d_two[zero_ind] = im[pdt[zero_ind,0], pdt[zero_ind,1]]

根据我的经验,索引分配很快。 where 也很快。 or.reduce 的构造可能会被简化。

如果您按原样将其放入cython,您将不会获得明显的加速。如果您生成 -a html,您会看到很多黄色 - 对 python 和 numpy 的调用。指定数组的形状和类型可能会有所帮助。但是如果没有循环,cython 就没有什么可以改进的了。

类型化的 memeoryviews 可以使用“本机”cython 代码执行许多数组操作,但它们几乎没有 numpy 数组的功能。

另一种选择是将其重写为纯粹的迭代操作 - 循环在其所有荣耀中。与良好的矢量化 numpy 相反。然后让 cython 将其转换为纯 C。但这将是很多工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多