Loading model with custom function with additional arguments

3,247 views
Skip to first unread message

tpar...@gmail.com

unread,
Sep 11, 2018, 12:47:10 PM9/11/18
to Keras-users
Hi,

I am Tanmay Parekh, new to the community and have started working on keras off-late. (Please bear for any nooby mistakes)

This post stands with a reference to the issue raised here. I am using a custom partial loss function which requires additional arguments. The third argument is actually an input node in the model. Attaching a snippet from the model corresponding to it:

def sparse_weighted_loss(target, output, weights):
     
return tf.multiply(tf.keras.backend.sparse_categorical_crossentropy(target, output), weights)


weights_tensor
= Input(shape=(None,), dtype='float32', name='weights_input')
lossFct
= partial(sparse_weighted_loss, weights=weights_tensor)
update_wrapper
(lossFct, sparse_weighted_loss)

I use `lossFct` as my custom loss function (which is basically a element-wise weighted cross-entropy loss). Now I redefine the custom function `sparse_weighted_loss` in the `custom_objects` as follows while loading the model:

def sparse_weighted_loss(target, output, weights):
     
return tf.multiply(tf.keras.backend.sparse_categorical_crossentropy(target, output), weights)
custom_obj
= {}
custom_obj
['sparse_weighted_loss'] = sparse_weighted_loss
model
= keras.models.load_model(modelPath, custom_objects=custom_obj)

During runtime, it still throws this error while loading the model:

Traceback (most recent call last):
 
File "Train_Product_NER_weighted_softmax.py", line 112, in <module>
    model
= BiLSTM.loadModel(sys.argv[2])
 
File "/BiLSTM_weightedloss.py", line 653, in loadModel
    model
= keras.models.load_model(modelPath, custom_objects=custom_obj)
 
File "/usr/local/lib/python3.4/site-packages/Keras-2.1.6-py3.4.egg/keras/models.py", line 388, in load_model
 
File "/usr/local/lib/python3.4/site-packages/Keras-2.1.6-py3.4.egg/keras/engine/training.py", line 837, in compile
 
File "/usr/local/lib/python3.4/site-packages/Keras-2.1.6-py3.4.egg/keras/engine/training.py", line 429, in weighted
TypeError: sparse_weighted_loss() missing 1 required positional argument: 'weights'


I don't know why we define the custom objects in the first place and how it works internally and hence, might be making some minor mistake. But could anyone help me out here?

Sergey O.

unread,
Sep 11, 2018, 1:29:35 PM9/11/18
to tpar...@gmail.com, Keras-users
Hi Tanmay,
Welcome to the community!

You don't actually need to define the "weights" as an input argument in your custom loss function. You can actually use any of the layers/tensors directly inside the loss function. 
Just make sure you (def)ine your loss function after you've defined the weights layer (so that weights are global and can be accessed inside the function).

-Sergey

--
You received this message because you are subscribed to the Google Groups "Keras-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to keras-users+unsubscribe@googlegroups.com.
To view this discussion on the web, visit https://groups.google.com/d/msgid/keras-users/2f73c3a1-33bb-4532-a7c6-77aad5511f77%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

tpar...@gmail.com

unread,
Sep 12, 2018, 2:31:50 AM9/12/18
to Keras-users
Hi Sergey,

That's a good fix, but I run into another issue here.

I re-modified my code by as suggestion as follows:

weights_tensor = Input(shape=(None,), dtype='float32', name='weights_input')

inputNodes
.append(weights_tensor)

def sparse_weighted_loss(target, output):
     
return tf.multiply(tf.keras.backend.sparse_categorical_crossentropy(target, output), weights_tensor)

But, now, when I re-define the function before loading the model, 'weights_tensor' is not defined.

def sparse_weighted_loss(target, output):
     
return tf.multiply(tf.keras.backend.sparse_categorical_crossentropy(target, output), weights_tensor)


custom_obj
= {}
custom_obj
['sparse_weighted_loss'] = sparse_weighted_loss

model
= keras.models.load_model(modelPath, custom_objects=custom_obj)

This eventually throws: NameError: name 'weights_tensor' is not defined.

Thank you in advance,
Tanmay Parekh
To unsubscribe from this group and stop receiving emails from it, send an email to keras-users...@googlegroups.com.

Ted Yu

unread,
Sep 12, 2018, 10:26:55 PM9/12/18
to tpar...@gmail.com, keras...@googlegroups.com
I used your code from the second snippet.

I didn't reproduce the error.

Is it possible to show how the model is saved ?

Thanks

tpar...@gmail.com

unread,
Sep 13, 2018, 3:40:18 AM9/13/18
to Keras-users
Okay. This might be something to do with the structure of the code maybe then. I have a class for BiLSTM and creating a model and saving as one of it's elements. I then use a static function to just load the model given a model path.

My load function:

@staticmethod
def loadModel(modelPath):
   
import h5py
   
import json
   
from .keraslayers.ChainCRF import create_custom_objects

   
# Define weighted loss

   
def sparse_weighted_loss(target, output):
       
return tf.multiply(tf.keras.backend.sparse_categorical_crossentropy(target, output), weights_tensor)

    custom_obj
= {}
    custom_obj
['sparse_weighted_loss'] = sparse_weighted_loss

    model
= keras.models.load_model(modelPath, custom_objects=custom_obj)


   
with h5py.File(modelPath, 'r') as f:
        mappings
= json.loads(f.attrs['mappings'])
       
params = json.loads(f.attrs['params'])
        modelName
= f.attrs['modelName']
        labelKey
= f.attrs['labelKey']

    bilstm
= BiLSTM(params)
    bilstm
.setMappings(mappings, None)
    bilstm
.models = {modelName: model}
    bilstm
.labelKeys = {modelName: labelKey}
    bilstm
.idx2Labels = {}
    bilstm
.idx2Labels[modelName] = {v: k for k, v in bilstm.mappings[labelKey].items()}
   
return bilstm

And here is the save function:

def saveModel(self, modelName):
   
import json
   
import h5py

   
if self.modelSavePath == None:
       
raise ValueError('modelSavePath not specified.')

    directory
= os.path.dirname(savePath)
   
if not os.path.exists(directory):
        os
.makedirs(directory)

   
if os.path.isfile(savePath):
        logging
.info("Model "+savePath+" already exists. Model will be overwritten")

   
self.models[modelName].save(savePath, True)

   
with h5py.File(savePath, 'a') as h5file:
        h5file
.attrs['mappings'] = json.dumps(self.mappings)
        h5file
.attrs['params'] = json.dumps(self.params)
        h5file
.attrs['modelName'] = modelName
        h5file
.attrs['labelKey'] = self.datasets[modelName]['label']

I basically call the load function from outside:

from neuralnets.BiLSTM_weightedloss import BiLSTM


model
= BiLSTM.loadModel(sys.argv[2])

As you can see, in my static load function I don't have any access to "weights_tensor" variable, and hence the error I get there.

This error might have to do with the structure of the code, but how do I get to fix it?

Thanks in advance,
Tanmay Parekh

Sergey O.

unread,
Sep 13, 2018, 4:44:43 AM9/13/18
to Tanmay Parekh, Keras-users
If you need to go down the route of custom save and load functions... It seems like it would be easier (and safer) to just save the weights.

In your script you can recreate the model and then simply reload the saved weights. 

tpar...@gmail.com

unread,
Sep 13, 2018, 12:15:45 PM9/13/18
to Keras-users
Okay. I adapted to save and load the weights and it works well now. Thanks a lot! :D

But just curious on the flexibility provided by Keras on loading and saving models. We don't have a very neat way to get by, it seems.

shareef babu

unread,
Sep 28, 2018, 1:21:11 AM9/28/18
to Keras-users

Hi i'm shareef,

I'm also having the same kind of probelm... please help me regarding....

I used a custom initializers in my dense layer, fitted the model and saved. Now i tried to load the model using "load_model", it throwedmea an error telling you custom initializer not defined.  I tried to give that but it is still throwing the error.


Here is the snipet code what i used
 My definition
def my_init(shape, dtype=None):
    mean_file
=str('means')
    mean_gmm
= np.loadtxt(mean_file, dtype=np.object, delimiter=" ")
    mean_gmm
= mean_gmm.astype(np.float)
    eq_norm
= np.sqrt(np.sum(mean_gmm**2, axis=1))
    norm_mean
= np.transpose(mean_gmm/eq_norm[:, np.newaxis])
    kvar
= K.variable(value=norm_mean, dtype='float32')
   
   
return kvar



model.add(Dense(256, input_dim=60, activation='relu', kernel_initializer=my_init))
saved this model and called like this

custom_obj = {}
custom_obj
['my_init'] = my_init

saved_nn
= load_model('model_saved.h5',custom_objects=custom_obj)

error
Traceback (most recent call last):

 
File "zstat_compute_DNN_withgmm_means.py", line 57, in <module>
    saved_nn
= load_model('tr_mfcc_zstat_ht_3layers_256_512_256_assign_mean_asWeights.h5',custom_objects=custom_obj)
 
File "/home/shareef/miniconda2/lib/python2.7/site-packages/keras/models.py", line 243, in load_model
    model
= model_from_config(model_config, custom_objects=custom_objects)
 
File "/home/shareef/miniconda2/lib/python2.7/site-packages/keras/models.py", line 317, in model_from_config
   
return layer_module.deserialize(config, custom_objects=custom_objects)
 
File "/home/shareef/miniconda2/lib/python2.7/site-packages/keras/layers/__init__.py", line 55, in deserialize
    printable_module_name
='layer')
 
File "/home/shareef/miniconda2/lib/python2.7/site-packages/keras/utils/generic_utils.py", line 143, in deserialize_keras_object
    list
(custom_objects.items())))
 
File "/home/shareef/miniconda2/lib/python2.7/site-packages/keras/models.py", line 1352, in from_config
    layer
= layer_module.deserialize(conf, custom_objects=custom_objects)
 
File "/home/shareef/miniconda2/lib/python2.7/site-packages/keras/layers/__init__.py", line 55, in deserialize
    printable_module_name
='layer')
 
File "/home/shareef/miniconda2/lib/python2.7/site-packages/keras/utils/generic_utils.py", line 145, in deserialize_keras_object
   
return cls.from_config(config['config'])
 
File "/home/shareef/miniconda2/lib/python2.7/site-packages/keras/engine/topology.py", line 1269, in from_config
   
return cls(**config)
 
File "/home/shareef/miniconda2/lib/python2.7/site-packages/keras/legacy/interfaces.py", line 91, in wrapper
   
return func(*args, **kwargs)
 
File "/home/shareef/miniconda2/lib/python2.7/site-packages/keras/layers/core.py", line 824, in __init__
   
self.kernel_initializer = initializers.get(kernel_initializer)
 
File "/home/shareef/miniconda2/lib/python2.7/site-packages/keras/initializers.py", line 498, in get
   
return deserialize(config)
 
File "/home/shareef/miniconda2/lib/python2.7/site-packages/keras/initializers.py", line 490, in deserialize
    printable_module_name
='initializer')
 
File "/home/shareef/miniconda2/lib/python2.7/site-packages/keras/utils/generic_utils.py", line 152, in deserialize_keras_object
   
return cls(**config['config'])
TypeError: my_init() takes at least 1 argument (0 given)



Please help me regarding this

Thanks
Reply all
Reply to author
Forward
0 new messages