ali*_*i_m 7 python oop numpy pickle theano
在使用joblib并行化一些涉及Theano函数的模型拟合代码的过程中,我偶然发现了一些对我来说很奇怪的行为.
考虑这个非常简单的例子:
from joblib import Parallel, delayed
import theano
from theano import tensor as te
import numpy as np
class TheanoModel(object):
def __init__(self):
X = te.dvector('X')
Y = (X ** te.log(X ** 2)).sum()
self.theano_get_Y = theano.function([X], Y)
def get_Y(self, x):
return self.theano_get_Y(x)
def run(niter=100):
x = np.random.randn(1000)
model = TheanoModel()
pool = Parallel(n_jobs=-1, verbose=1, pre_dispatch='all')
# this fails with `TypeError: can't pickle instancemethod objects`...
results = pool(delayed(model.get_Y)(x) for _ in xrange(niter))
# # ... but this works! Why?
# results = pool(delayed(model.theano_get_Y)(x) for _ in xrange(niter))
if __name__ == '__main__':
run()
Run Code Online (Sandbox Code Playgroud)
我理解为什么第一个案例失败了,因为.get_Y()
这显然是一个实例方法TheanoModel
.我不明白的是为什么第二种情况起作用,因为X
,Y
并且theano_get_Y()
只在__init__()
方法中声明TheanoModel
.在创建实例theano_get_Y()
之前无法对其进行评估TheanoModel
.当然,它也应该被视为一种实例方法,因此应该是不可推荐的?实际上,如果我明确声明X
并且Y
是TheanoModel
实例的属性,甚至仍然可以工作.
谁能解释一下这里发生了什么?
只是为了说明为什么我认为这种行为特别奇怪,这里有一些其他可调用成员对象的例子,它们不self
作为第一个参数:
from joblib import Parallel, delayed
import theano
from theano import tensor as te
import numpy as np
class TheanoModel(object):
def __init__(self):
X = te.dvector('X')
Y = (X ** te.log(X ** 2)).sum()
self.theano_get_Y = theano.function([X], Y)
def square(x):
return x ** 2
self.member_function = square
self.static_method = staticmethod(square)
self.lambda_function = lambda x: x ** 2
def run(niter=100):
x = np.random.randn(1000)
model = TheanoModel()
pool = Parallel(n_jobs=-1, verbose=1, pre_dispatch='all')
# # not allowed: `TypeError: can't pickle function objects`
# results = pool(delayed(model.member_function)(x) for _ in xrange(niter))
# # not allowed: `TypeError: can't pickle function objects`
# results = pool(delayed(model.lambda_function)(x) for _ in xrange(niter))
# # also not allowed: `TypeError: can't pickle staticmethod objects`
# results = pool(delayed(model.static_method)(x) for _ in xrange(niter))
# but this is totally fine!?
results = pool(delayed(model.theano_get_Y)(x) for _ in xrange(niter))
if __name__ == '__main__':
run()
Run Code Online (Sandbox Code Playgroud)
除了theano.function
!之外,它们都不是可挑选的!
Theano 函数不是 python 函数。相反,它们是覆盖__call__
. 这意味着您可以像调用函数一样调用它们,但在内部它们实际上是某些自定义类的对象。结果,你可以腌制它们。