NTMC-Community / MatchZoo

Facilitating the design, comparison and sharing of deep text matching models.
Apache License 2.0
3.82k stars 898 forks source link

AttributeError: 'RankCrossEntropyLoss' object has no attribute '__name__' for Keras model save #753

Closed cmacdonald closed 5 years ago

cmacdonald commented 5 years ago

Describe the bug

I wanted to try to save the Keras "backend" model. But model.backend.save("dssm.keras.model.h5") didnt work:

AttributeError: 'RankCrossEntropyLoss' object has no attribute 'name'

To Reproduce

See gist at https://gist.github.com/cmacdonald/8d86d433c3ca154f746b9864cc2b91de

Describe your attempts

uduse commented 5 years ago

I confirmed it's a bug. On the keras side, using a customized loss only requires the loss to be callable but saving it requires its __name__ field (the keras dev was being careless, assuming all callables are functions), which matchzoo losses don't have since matchzoo losses are callable class instances instead of functions or methods. Matchzoo losses are class instances instead of fixed functions because their behavior depends on specific parameters (e.g. num_neg). As a result, in order for keras to serialize a matchzoo loss, you have to give the instance a __name__ field and add the instance to keras' model loading environment.

We may provide a workaround internally later, but here's a band-aid fix:

loss = mz.losses.RankCrossEntropyLoss(num_neg=4)
loss.__name__ = 'my_loss'
ranking_task = mz.tasks.Ranking(loss)
# ......
model.backend.save("dssm.keras.model.h5")
# ......
keras.models.load_model("dssm.keras.model.h5", custom_objects={'my_loss': loss})
cmacdonald commented 5 years ago

Thanks. I confirm that the band-aid works.