【发布时间】:2014-08-18 14:13:09
【问题描述】:
在使用 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()
我明白为什么第一种情况会失败,因为.get_Y() 显然是TheanoModel 的实例方法。我不明白为什么第二种情况有效,因为X、Y 和theano_get_Y() 仅在TheanoModel 的__init__() 方法中声明。在创建 TheanoModel 实例之前,无法评估 theano_get_Y()。那么,当然,它也应该被认为是一个实例方法,因此应该是不可腌制的?事实上,如果我将 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()
除了theano.function! 之外,它们都不是可腌制的!
【问题讨论】:
-
很好的发现——我不认为你的
theano_get_Y是实例方法,就像<bound method ... etc>那样被该测试捕获。此外,对theano.function的调用使theano 编译您定义的表达式,基本上使结果完全独立于__init__范围内定义的所有其他变量。因此,我认为它应该被视为一个未绑定的可调用对象。 (我有点犹豫,因为我什至不确定 41.9% 这究竟在内部是如何工作的) -
@eickenberg 有趣 - 我明白为什么
theano_get_Y在创建后不需要引用X和Y,但它仍然引用/被 @ 引用987654344@ 实例。在所有其他类似类型的无法腌制的可调用对象的上下文中,这似乎特别奇怪。 -
也许您可以使用@Winsto Ewert 的回答中描述的可调用类实例添加测试。
标签: python oop numpy pickle theano