2016-05-14 72 views
1

一些背景的问题:用Cython:移调memoryview

我试图优化定制的神经网络代码。 它很大程度上依赖循环,我决定使用cython来加速计算。

我按照常规的在线技巧:用适当的cdefs声明所有本地变量并关闭边界检查和非检查。这几乎没有给我10%的表现。

那么,我的代码依赖于许多类的成员。所以我决定把整个班级转换成一个cdef班级。原来,cython不允许numpy ndarrays作为类成员的类型。相反,人们必须使用记忆体。 不幸的是,这两种类型似乎极不相容。

我已经遇到了这样的问题:Cython memoryview transpose: Typeerror

概括起来:你可以存储np.ndarray在memoryview。您可以转置它并将返回的数组存储在memview中。但是,如果该memview是一个类成员,则不会。然后,您必须创建一个中间memview,将结果存储在该中,并将中间memview分配给类成员。

下面的代码(非常感谢DavidW)

def double[:,:,:,:] temporary_view_of_transpose 

# temporary_view_of_transpose now "looks at" the memory allocated by transpose 
# no square brackets! 
temporary_view_of_transpose = out_image.transpose(1, 0, 2, 3) 

# data is copied from temporary_view_of_transpose to self.y 
self.y[...] = temporary_view_of_transpose # (remembering that self.y must be the correct shape before this assignment). 

现在,我已经有了一个新的问题。 上面的代码来自所谓的“前传”。还有一个相应的反向通道,它可以反向执行所有的计算(对于分析梯度)。

这意味着,对于向后通,我必须转置memoryview并将其存储在一个阵列numpy的:

cdef np.ndarray[DTYPE_t, ndim=4] d_out_image = self.d_y.transpose(1, 0, 2,3) 

d_y必须是一个类的成员,因此它必须是一个memoryview。 Memoryviews不允许转置。他们有一个.T方法,但这对我没有帮助。

实际问题:

  • 如何正确地存储numpy的数组作为CDEF类中的一个成员?
  • 如果答案是:“作为一个内存视图”,我该如何转置一个内存视图?

回答

3

我认为最好的答案是“你存储numpy的作为非类型化的Python对象”

cdef class C: 
    cdef object array 

    def example_function(self): 
     # if you want to use the fast Cython array indexing in a function 
     # you can do: 
     cdef np.ndarray[np.float64_t,ndim=4] self_array = self.array 
     # or 
     cdef np.float64_t[:,:,:,:] self_array2 = self.array 

     # note that neither of these are copies - they're references 
     # to exactly the same array and so if you modify one it'll modify 
     # self.array too 

    def function2(self): 
     return self.array.transpose(1,0,2,3) # works fine! 

小成本做这种方式是,有一点点在启动类型检查example_function检查它实际上是一个4D numpy数组与正确的dtype。只要你在功能上做了一些不重要的工作。


作为替代(如果你决定你真的想将它们存储为memoryviews),你可以use np.asarray to convert it back to a numpy array without making a copy(即它们共享数据)。

例如

cdef np.ndarray[DTYPE_t, ndim=4] d_out_image = np.asarray(self.d_y).transpose(1, 0, 2,3) 
+0

这看起来像个好主意。再一次,我会尽快检查我的家。感谢您的快速回答 – lhk

+0

作品,谢谢 – lhk