【问题标题】:Is there a way to pickle a scipy.interpolate.Rbf() object?有没有办法腌制 scipy.interpolate.Rbf() 对象?
【发布时间】:2014-06-10 19:17:36
【问题描述】:

我正在为一个相当大的数据集创建径向基函数插值模型。主调用 `scipy.interpolate.Rbf(,) 大约需要一分钟和 14 GB 的 RAM。 由于并非应该运行它的每台机器都能够做到这一点,并且由于程序将经常在同一个数据集上运行,所以我想将结果腌制到一个文件中。这是一个简化的例子:

import scipy.interpolate as inter
import numpy as np
import cPickle

x = np.array([[1,2,3],[3,4,5],[7,8,9],[1,5,9]])
y = np.array([1,2,3,4])

rbfi = inter.Rbf(x[:,0], x[:,1], x[:,2], y)

RBFfile = open('picklefile','wb')
RBFpickler = cPickle.Pickler(RBFfile,protocol=2)
RBFpickler.dump(rbfi)
RBFfile.close()

RBFpickler.dump() 调用导致can't pickle <type 'instancemethod'> 错误。 据我了解,这意味着那里有一个方法(嗯,rbfi() 是可调用的),由于某种我不太明白的原因,它不能被腌制。

有谁知道以其他方式腌制或以其他方式保存 inter.Rbf() 调用的结果的方法?

其中有一些形状为 (nd,n) 和 (n,n) 的数组(rbfi.Arbfi.xirbfi.di...),我假设它们存储了所有有趣的信息。我想我可以只腌制那些数组,但是我不确定如何再次将对象组合在一起......

编辑: 附加限制:我不允许在系统上安装其他库。我可以包含它们的唯一方法是它们是纯 Python,我可以将它们包含在脚本中,而无需编译任何东西。

【问题讨论】:

标签: python scipy pickle


【解决方案1】:

我会使用dill 来序列化结果……或者如果你想要一个缓存函数,你可以使用klepto 来缓存函数调用,这样你就可以最大限度地减少对函数的重新评估。

Python 2.7.6 (default, Nov 12 2013, 13:26:39) 
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import scipy.interpolate as inter
>>> import numpy as np
>>> import dill
>>> import klepto
>>> 
>>> x = np.array([[1,2,3],[3,4,5],[7,8,9],[1,5,9]])
>>> y = np.array([1,2,3,4])
>>> 
>>> # build an on-disk archive for numpy arrays,
>>> # with a dictionary-style interface  
>>> p = klepto.archives.dir_archive(serialized=True, fast=True)
>>> # add a caching algorithm, so when threshold is hit,
>>> # memory is dumped to disk
>>> c = klepto.safe.lru_cache(cache=p)
>>> # decorate the target function with the cache
>>> c(inter.Rbf)
<function Rbf at 0x104248668>
>>> rbf = _
>>> 
>>> # 'rbf' is now cached, so all repeat calls are looked up
>>> # from disk or memory
>>> d = rbf(x[:,0], x[:,1], x[:,2], y)
>>> d
<scipy.interpolate.rbf.Rbf object at 0x1042454d0>
>>> d.A
array([[ 1.        ,  1.22905719,  2.36542472,  1.70724365],
       [ 1.22905719,  1.        ,  1.74422655,  1.37605151],
       [ 2.36542472,  1.74422655,  1.        ,  1.70724365],
       [ 1.70724365,  1.37605151,  1.70724365,  1.        ]])
>>> 

继续……

>>> # the cache is serializing the result object behind the scenes
>>> # it also works if we directly pickle and unpickle it
>>> _d = dill.loads(dill.dumps(d))
>>> _d
<scipy.interpolate.rbf.Rbf object at 0x104245510>
>>> _d.A
array([[ 1.        ,  1.22905719,  2.36542472,  1.70724365],
       [ 1.22905719,  1.        ,  1.74422655,  1.37605151],
       [ 2.36542472,  1.74422655,  1.        ,  1.70724365],
       [ 1.70724365,  1.37605151,  1.70724365,  1.        ]])
>>>

在此处获取kleptodillhttps://github.com/uqfoundation

【讨论】:

  • klepto 和 dill 中有二进制内容吗?我忘了补充一点,我不允许在应该运行的系统上安装新库,除非我可以将它们添加为主项目的非二进制组件。
  • 上周找到了我自己的解决方案,没有额外的库(但更具体到 RBF),所以我会坚持我现在所知道的。不过,你的似乎更普遍。
  • 如果您不想使用磁盘后端缓存函数,而只想要dumpload,只需使用带有dumpload 的最后一段代码而不是@ 987654332@ 和loads。 (另见您的评论)
【解决方案2】:

好的,Mike 的解决方案似乎是一个不错的解决方案,但我同时找到了另一个解决方案:

Rbf 对象只有两部分不能直接腌制,而且它们很容易从头开始重新创建。因此我的代码现在只保存数据部分:

import scipy.interpolate as inter
import numpy as np
import cPickle

x = np.array([[1,2,3],[3,4,5],[7,8,9],[1,5,9]])
y = np.array([1,2,3,4])

rbfi = inter.Rbf(x[:,0], x[:,1], x[:,2], y)

RBFfile = open('picklefile','wb')
RBFpickler = cPickle.Pickler(RBFfile,protocol=2)

# RBF can't be pickled directly, so save everything required for reconstruction
RBFdict = {}            
for key in rbfi.__dict__.keys():
    if key != '_function' and key!= 'norm':
        RBFdict[key] = rbfi.__getattribute__(key)   

RBFpickler.dump(RBFdict)
RBFfile.close()

这给了我一个文件,其中包含存储在对象中的所有信息。 rbfi._function()rbfi.norm 未保存。幸运的是,它们可以通过初始化任何(任意简单的)Rbf 对象从头开始重新创建:

## create a bare-bones RBF object ##
rbfi = inter.Rbf(np.array([1,2,3]), np.array([10,20,30]), \
                      np.array([1,2,3]), function = RBFdict['function'] )

然后这个对象的数据部分被保存的数据替换:

RBFfile = open('picklefile','rb')
RBFunpickler = cPickle.Unpickler(RBFfile)
RBFdict = RBFunpickler.load()
RBFfile.close()

## replace rbfi's contents with what was saved ##
for key,value in RBFdict.iteritems():
    rbfi.__setattr__(key, value)

>>> rbfi(2,3,4)
array(1.4600661386382146)

显然,甚至没有必要为新的 Rbf 对象提供与原始对象相同的维数,因为所有这些都会被覆盖。

也就是说,Mike 的解决方案可能是更普遍适用的解决方案,而这个解决方案更独立于平台。我在平台之间移动腌制克里金模型时遇到了问题,但是这种用于 RBF 模型的方法似乎更健壮——不过,我还没有对它进行太多测试,所以不能保证。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-14
  • 1970-01-01
  • 2020-04-07
  • 2016-03-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多