Repository: keras-team/keras

Issue:
convert weights of CuDNNLSTM causes error when using load_model to load an LSTM without bias
Please make sure that the boxes below are checked before you submit your issue. If your issue is an implementation question, please ask your question on [StackOverflow](http://stackoverflow.com/questions/tagged/keras) or [join the Keras Slack channel](https://keras-slack-autojoin.herokuapp.com/) and ask there instead of filing a GitHub issue.

Thank you!

- [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

- [ ] If running on TensorFlow, check that you are up-to-date with the latest version. The installation instructions can be found [here](https://www.tensorflow.org/get_started/os_setup).

- [ ] 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).

Using CNTK backend.

Sample script
```
from keras.models import load_model, Sequential
from keras.layers import LSTM

model = Sequential()
model.add(LSTM(10,
	input_shape=(1, 10),
	batch_size=1,
	use_bias=False))
model.compile(loss='mse', optimizer='adam', metrics=['accuracy'])
model.save('test.h5')

model2 = load_model('test.h5')
```

Error:
File "...\Python36\lib\site-packages\keras\engine\topology.py", line 3037, in preprocess_weights_for_loading
    bias = weights[2]
IndexError: list index out of range


Discussion:

Resolving patch:
diff --git a/keras/engine/topology.py b/keras/engine/topology.py
--- a/keras/engine/topology.py
+++ b/keras/engine/topology.py
@@ -3029,9 +3029,10 @@ def preprocess_weights_for_loading(layer, weights,
                 weights[1] = np.transpose(weights[1], (3, 2, 0, 1))
 
     # convert the weights of CuDNNLSTM so that they could be loaded into LSTM
-    if layer.__class__.__name__ == 'LSTM':
+    if layer.__class__.__name__ == 'LSTM' and len(weights) == 3:
         # determine if we're loading a CuDNNLSTM layer from the number of bias weights:
         # CuDNNLSTM has (units * 8) weights; while LSTM has (units * 4)
+        # if there's no bias weight in the file, skip this conversion
         units = weights[1].shape[0]
         bias = weights[2]
         if len(bias) == units * 8:


Test patch:
diff --git a/tests/test_model_saving.py b/tests/test_model_saving.py
--- a/tests/test_model_saving.py
+++ b/tests/test_model_saving.py
@@ -370,5 +370,22 @@ def test_saving_recurrent_layer_with_init_state():
     loaded_model = load_model(fname)
     os.remove(fname)
 
+
+@keras_test
+def test_saving_recurrent_layer_without_bias():
+    vector_size = 8
+    input_length = 20
+
+    input_x = Input(shape=(input_length, vector_size))
+    lstm = LSTM(vector_size, use_bias=False)(input_x)
+    model = Model(inputs=[input_x], outputs=[lstm])
+
+    _, fname = tempfile.mkstemp('.h5')
+    model.save(fname)
+
+    loaded_model = load_model(fname)
+    os.remove(fname)
+
+
 if __name__ == '__main__':
     pytest.main([__file__])