Why do I authorize the use of instance methods, which are functions of Theano but are not normal instance methods?

In the process of using joblib to parallelize some model fitting code that includes Anano functions, I came across some kind of behavior that seems strange to me.

Consider this simplified example:

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() 

I understand why the first time that fails, as .get_Y() is clearly an instance method TheanoModel . I don’t understand why the second case works, since X , Y and theano_get_Y() are declared only in the __init__() method of TheanoModel . theano_get_Y() cannot be evaluated until an instance of TheanoModel is created. Of course, then this should also be considered as an approximate method, and therefore should it be inaccessible? Actually, it even works if I explicitly declare X and Y attributes of an instance of TheanoModel .

Can anyone explain what is going on here?


Update

To illustrate why I think this behavior is particularly strange, here are a few examples of some other called member objects that do not accept self as their first argument:

 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() 

None of them can be selected, except for theano.function !

+6
source share
1 answer

Theano functions are not python functions. Instead, they are python objects that override __call__ . This means that you can call them exactly the same as a function, but internally they really are objects of some custom class. As a result, you can pickle them.

+3
source

Source: https://habr.com/ru/post/973976/


All Articles