Sunday, July 10, 2016

Keras pre-trained models how-to

In keras Functional API there are few examples for  combining models in a different way, but if you want to mix and match parts of models , like combine new classifier-head with a headless pre-trained model, you might encounter some issues. Let's explain how it works behind the scenes.

A saved model is a combination of three things:
  1. Layer definitions like "Dense" layer with it's regularizes ,output_dim and name
  2. Layer graph: which layer is connected to which other, and from which direction (in/out)
  3. Layer weights: for layers which do have them (dropout do not , for example)


When you call: model.to_json() , you get the first two. When you call model.save_weights() you get the third, where the key is the layer-name from (1)
If you want to save and load the exact same model, just call m=model_from_json(json) and then m.load_weights(file).  Easy.
If you want to create a head-less model, which does not contain the last few layers, you will have to re-create the model by code, create the connectivity and then use your own function to read the weights file(.h5).  The h5 API is quite clean and it's an easy-enough task.

If you want to create a new model from a headless-one and a new head you created, again you will have to define (1) and (2) in code, and then manually load-weights per layer.

Code for connectivity between layers
# assuming this was called already: graph = Graph() 
# graph.add_input(name='input1', ndim=2)

new_layer = (Dense(32, 4)  #define layer
graph.add_node(new_layer , name='dense1'         ,input='input1') #connect layer to input
#note that if you want two inputs, just use instead  ,inputs=['input1,'input2']

# and in the end .... graph.add_output(name='output', input='...')

The functional API hides the Graph API and allows you to create a layer and connect it to a node in one line
#assuming input- Input(shape=784,)
Dense(32,4)(input)  

It's important to remember that the node connectivity is actually added to the layer instance itself, this sadly means you can't re-use the layer in multiple graphs with totally different connectivity.
You will have to re-instantiate (redefine) a new identical, unconnected, layer.

FAQ:
"UserWarning: Model inputs must come from a Keras Input layer, they cannot be the output of a previous non-Input layer"
You can't instantiate a Model which does not start with Input layer, in other words, you can't just cut the few last layers of an existing model and call Model (input='other_input', output='...same')



No comments: