【问题标题】:pickle cython class泡菜cython类
【发布时间】:2012-09-28 19:47:58
【问题描述】:

我必须保存并加载一个 cython 类实例。 我的cython类就是这个加上几个方法:

import numpy as np
cimport numpy as np
cimport cython    
cdef class Perceptron_avg_my:
    cdef int wlen,freePos
    cdef np.ndarray w,wtot,wac,wtotc #np.ndarray[np.int32_t]
    cdef np.ndarray wmean  #np.ndarray[np.float32_t]    
    cdef public dict fpos    

    def __cinit__(self,np.int64_t wlen=4*10**7):
        self.fpos= dict()
        self.freePos=1
        self.wlen=wlen
        self.w=np.zeros(wlen,np.int32)
        self.wtot=np.zeros(wlen,np.int32)
        self.wac=np.zeros(wlen,np.int32)
        self.wtotc=np.zeros(wlen,np.int32)
        self.wmean=np.zeros(wlen,np.float32)

    cpdef evaluate_noavg(self,list f):
        cdef np.ndarray[np.int32_t] w = self.w
        cdef dict fpos = self.fpos        
        cdef bytes ff
        cdef int i
        cdef long int score=0

        for ff in f:
            i=fpos.get(ff,0)  
            if i != 0: 
                score += w[i]
        return score

我正在考虑使用 cPickle 模块。 我知道我必须实现一个 __reduce__(self) 方法,但是我很难找到一个例子并很好地理解文档

我尝试在 Perceptron_avg_my 中添加类似的内容但不起作用:

    def rebuild(self,l):
        self.fpos=l[0]
        self.freePos=l[1]

    def __reduce__(self):
        #print 'reduce call'
        return (Perceptron_avg_my.rebuild,(self.fpos,self.freePos))

有什么建议吗? 非常感谢!!!

【问题讨论】:

标签: python class pickle cython reduce


【解决方案1】:

我不知道你有没有找到,但是官方 Python 文档有 a section on pickling extension types(不幸的是,这个文档似乎没有 Python 3 版本,但它在 Python 3 中的工作方式相同)。

我认为你在这里有三个问题。首先,__reduce__ 返回的函数应该从头开始创建一个新对象并将其返回,而您的rebuild 函数只是设置一些属性。其次,__reduce__ 返回的元组本身必须是可腌制的,而作为一种方法,Perceptron_avg_my.rebuild 是不可腌制的(我认为这在 python 3.3 或 3.4 中有望得到修复)。相反,您可以将其转换为模块级函数。最后,参数 (self.fpos,self.freePos) 单独传递给 rebuild - 您不必自己解包元组。

以下似乎对我有用(尽管您可能也想存储其他属性的值,否则它们将只有__init__ 设置的初始值):

#inside the class definition
def __reduce__(self):
    return (rebuild, (self.wlen, self.fpos, self.freePos))

#standalone function
def rebuild(wlen, fpos, freePos):
    p = Perceptron_avg_my(wlen)
    p.fpos = fpos
    p.freePos = freePos
    return p

【讨论】:

  • 谢谢你詹姆斯,如果我现在回复我很抱歉!!!我认为还有另一个问题:_reduce_返回的函数不能在cython模块中(老实说我不明白为什么)。我将添加一个对我有用的解决方法的答案......但我不知道是否有更好的解决方案。
  • 这很奇怪:它在模块中定义时对我有用。您不会不小心使用cdef 而不是def 来定义函数,是吗?或者我们只是使用不同版本的 cython 或 python(我用 python 3.2.3 / cython 0.17 和 python 2.7.2 / cython 0.15.1 尝试过)。
  • 我使用 python 2.7.3 / cython 0.17。
  • 如果我将 cython 模块放在子包中 ./ml/ 您的解决方案不起作用:cPickle.PicklingError: Can't pickle : 模块感知器的导入失败。我在我的 main.py from ml.perceptron import Perceptron 中使用。我的 ./ml/__init__.py 是空的。我的分包有问题吗?
  • 效果很好,感谢文档本身并不简洁,并且在没有简单示例的情况下深入研究了许多极端情况。
【解决方案2】:

从 Cython 0.26(2017 年 7 月发布)开始,不再需要实现 pickle 协议。所有不包含指针或联合的 cdef 类都可以自动腌制。对于包含结构的类,由于(除其他原因)高代码开销,默认情况下禁用自动酸洗。可以使用 @cython.auto_pickle(True) 装饰器为具有结构的类启用自动酸洗。

更多信息可以在changelogthe website of Stefan Behnel上找到。

【讨论】:

  • 很高兴看到新版本!但是我仍然必须实现自己的酸洗机制 b/c TypeError: no default __reduce__ due to non-trivial __cinit__
  • 包含指针的 cdef 类呢?
  • @ibarrond 我最近没有关注 Cython 的开发。我不知道这是否可行,或者您必须做些什么才能使其发挥作用。如果你发现了,请告诉我们;)
【解决方案3】:

我使用了这个可行的解决方法,但我不确定它是否是最佳解决方案。

我创建了一个新的支持文件来声明reduce调用的函数(如果我把它放在cython模块中它不起作用):

#perceptron_supp.py

from perceptron import Perceptron

def rebuild_perceptron(wlen,freePos,fpos,w,nw_avg,wtot_avg,wsup_avg,wmean_avg,wtot_my,wac_my,wtotc_my,wmean_my):
    return Perceptron(wlen,True,freePos,fpos,w,nw_avg,wtot_avg,wsup_avg,wmean_avg,wtot_my,wac_my,wtotc_my,wmean_my)

然后我在 cython 模块中导入这个函数:

#perceptron.pyx

import numpy as np
cimport numpy as np
cimport cython

#added
from perceptron_supp import rebuild_perceptron

cdef class Perceptron:
    cdef int wlen,freePos
    cdef dict fpos

    cdef np.ndarray w #np.ndarray[np.int32_t]

    cdef int nw_avg
    cdef np.ndarray wtot_avg,wsup_avg #np.ndarray[np.int32_t]
    cdef np.ndarray wmean_avg  #np.ndarray[np.float64_t]

    cdef np.ndarray wtot_my,wac_my,wtotc_my #np.ndarray[np.int32_t]
    cdef np.ndarray wmean_my  #np.ndarray[np.float64_t]

    def __cinit__(self,int wlen=4*10**7,setValues=False,freePos=0,fpos=0,w=0,nw_avg=0,wtot_avg=0,wsup_avg=0,wmean_avg=0,wtot_my=0,wac_my=0,wtotc_my=0,wmean_my=0):
        if not setValues:            
            self.wlen=wlen
            self.freePos=1
            self.fpos= dict()

            self.w=np.zeros(wlen,np.int32)

            self.nw_avg=1
            self.wtot_avg=np.zeros(wlen,np.int32)            
            self.wsup_avg=np.zeros(wlen,np.int32)
            self.wmean_avg=np.zeros(wlen,np.float64)

            self.wtot_my=np.zeros(wlen,np.int32)    
            self.wac_my=np.zeros(wlen,np.int32)
            self.wtotc_my=np.zeros(wlen,np.int32)
            self.wmean_my=np.zeros(wlen,np.float64)
        else:           
            self.wlen=wlen
            self.freePos=freePos
            self.fpos=fpos

            self.w=w

            self.nw_avg=nw_avg
            self.wtot_avg=wtot_avg
            self.wsup_avg=wsup_avg
            self.wmean_avg=wmean_avg

            self.wtot_my=wtot_my
            self.wac_my=wac_my
            self.wtotc_my=wtotc_my
            self.wmean_my=wmean_my

    def __reduce__(self):
        return (rebuild_perceptron,(self.wlen,self.freePos,self.fpos,self.w,self.nw_avg,self.wtot_avg,self.wsup_avg,self.wmean_avg,self.wtot_my,self.wac_my,self.wtotc_my,self.wmean_my))

当我使用我的感知器模块时,我只需要做:从感知器导入感知器,现在我可以在需要时执行 cPyckle.dump 或 cPickle.load。

如果有人有更好的解决方案,非常感谢!!!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-09-15
    • 2012-06-06
    • 1970-01-01
    • 2015-02-28
    • 2012-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多