Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

model_from_json fails with "TypeError: arg 5 (closure) must be tuple" #2814

Closed
asmith26 opened this issue May 25, 2016 · 6 comments
Closed

Comments

@asmith26
Copy link
Contributor

Having saved a successfully trained model with:

with open(os.path.join(MODEL_PATH, 'model.json'), 'w') as f:
    f.write(model.to_json())

When trying to reload it, I'm getting:

>>> from keras.models import model_from_json
Using Theano backend.
>>> model = model_from_json(open('model.json').read())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/andyandy/git/keras/keras/models.py", line 37, in model_from_json
    return layer_from_config(config, custom_objects=custom_objects)
  File "/home/andyandy/git/keras/keras/utils/layer_utils.py", line 35, in layer_from_config
    return layer_class.from_config(config['config'])
  File "/home/andyandy/git/keras/keras/engine/topology.py", line 2197, in from_config
    custom_objects=custom_objects)
  File "/home/andyandy/git/keras/keras/utils/layer_utils.py", line 35, in layer_from_config
    return layer_class.from_config(config['config'])
  File "/home/andyandy/git/keras/keras/layers/core.py", line 489, in from_config
    function = python_types.FunctionType(function, globals())
TypeError: arg 5 (closure) must be tuple

I'm using the functional API if it helps. Thanks

  • [x ] Check that you are up-to-date with the master branch of Keras. You can update with:
    pip install git+git://github.com/fchollet/keras.git --upgrade --no-deps
  • [x ] If running on Theano, check that you are up-to-date with the master branch of Theano. You can update with:
    pip install git+git://github.com/Theano/Theano.git --upgrade --no-deps
  • [x ] Provide a link to a GitHub Gist of a Python script that can reproduce your issue (or just copy the script here if it is short).
@fchollet
Copy link
Member

Provide a link to a GitHub Gist of a Python script that can reproduce your issue (or just copy the script here if it is short).

@asmith26
Copy link
Contributor Author

asmith26 commented May 26, 2016

Apologies @fchollet, I forgot to add the model.json gist: https://gist.github.com/asmith26/2da836496825dbf2d7735dbe84dfe1cd

I'm using the stochastic_depth_keras model - you can quickly create a Stochastic Depth model.json (or model.yaml) using my create_SDmodel_json_or_yaml.py script.

@asmith26
Copy link
Contributor Author

(I just tried writing the same StochasticDepth model using the yaml method, but this fails on the write step - traceback linked here)

@gw0
Copy link
Contributor

gw0 commented Aug 30, 2016

Any success? I am trying to use model_from_yaml() with a custom function in a lambda merge.

TypeError: arg 5 (closure) must be tuple

@asmith26
Copy link
Contributor Author

I have not had any success I'm afraid.

@gw0
Copy link
Contributor

gw0 commented Aug 31, 2016

I have fixed it in PR #3639. Although it works fine, one needs to be aware of how to properly use closures (if you want to use them).

Only the code of lambda functions was serialized, missing was their defaults and closure (essential for successful deserialization). To reconstruct a custom function completely one would need:

fn = types.FunctionType(func.func_code,
                        func.func_globals.copy(),
                        name=func.func_name,
                        argdefs=func.func_defaults,
                        closure=func.func_closure)

Also these .func_* arguments are necessary for compatibility before Python 2.6 (see docs). Because Keras is on 2.7, we can ditch them.

The solution is based a solution that does not introduce new dependencies on StackOverflow. One may test it with something like:

    def get_closure(x):
        def the_closure(a, b=1):
            return a * x + b
        return the_closure

    f = get_closure(10)
    code, defaults, closure = func_dump(f)
    dump = pickle.dumps((code, defaults, closure))
    code, defaults, closure = pickle.loads(dump)
    f = func_load(code, defaults=defaults, closure=closure, globals=globals())

    print f(2)

For the lambda merge layer I am using something like the following. The value of i gets preserved because of the defaults attribute.

i = ...
def mul_sum((x1, x2), i=i):
    return x1 + x2 * i
def mul_sum_shape((s, _)):
    return s
x = merge([x1, x2], mode=mul_sum, output_shape=mul_sum_shape)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants