为什么我允许使用作为Theano函数的pickle实例方法,而不是正常的instanceomethods?

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并且YTheanoModel实例的属性,甚至仍然可以工作.

谁能解释一下这里发生了什么?


更新

只是为了说明为什么我认为这种行为特别奇怪,这里有一些其他可调用成员对象的例子,它们不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!之外,它们都不是可挑选的!

Win*_*ert 4

Theano 函数不是 python 函数。相反,它们是覆盖__call__. 这意味着您可以像调用函数一样调用它们,但在内部它们实际上是某些自定义类的对象。结果,你可以腌制它们。