transcranial / keras-js

Run Keras models in the browser, with GPU support using WebGL
https://transcranial.github.io/keras-js
MIT License
4.96k stars 503 forks source link

Keras.js won't load .bin model after retraining #112

Closed randaller closed 6 years ago

randaller commented 6 years ago

keras==2.1.2 keras.js==latest only browser, no nodejs or so

Let me show it using MNIST example:

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras import backend as K
from keras.models import load_model

batch_size = 128
num_classes = 10
epochs = 12
img_rows, img_cols = 28, 28

(x_train, y_train), (x_test, y_test) = mnist.load_data()

if K.image_data_format() == 'channels_first':
   x_train = x_train.reshape(x_train.shape[0], 1, img_rows, img_cols)
   x_test = x_test.reshape(  x_test.shape[0] , 1, img_rows, img_cols)
   input_shape = (1, img_rows, img_cols)
else:
   x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)
   x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1)
   input_shape = (img_rows, img_cols, 1)

x_train  = x_train.astype('float32')
x_test   = x_test.astype('float32')
x_train /= 255
x_test  /= 255
print('x_train shape:', x_train.shape)
print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')

y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)

model   = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3), activation='relu',  input_shape=input_shape))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation='softmax'))

model.compile(loss=keras.losses.categorical_crossentropy,  optimizer=keras.optimizers.Adadelta(),  metrics=['accuracy'])

model.fit(x_train, y_train,  batch_size=batch_size,  epochs=5,   verbose=1, validation_data=(x_test, y_test))

model.save('my_first.h5')

# python encoder.py my_first.h5 - outputs my_first.bin that keras.js eats and works then well

model = load_model('my_first.h5')

model.fit(x_train, y_train,  batch_size=batch_size,  epochs=5,   verbose=1, validation_data=(x_test, y_test))

model.save('my_second.h5')     # <-- saved file now have +56 bytes more size

#  python encoder.py my_second.h5 - outputs my_second.bin (+26 bytes longer than first.bin)
#  but now keras.js falls with error, while trying to load this file!!!

# but keras works still well with this
# model.predict... Ok

and the error is:

keras.min.js:1 Uncaught (in promise) Error: [Model] error loading weights.
    at keras.min.js:1:416384
    at Array.map (<anonymous>)
    at t (keras.min.js:1:416262)
    at keras.min.js:1:415413
    at Array.forEach (<anonymous>)
    at t (keras.min.js:1:414516)
    at t (keras.min.js:1:411541)
    at r (keras.min.js:1:448933)
    at Generator.i [as _invoke] (keras.min.js:1:449980)
    at Generator.t.(anonymous function) [as next] (keras.min.js:1:449112)
    at i (keras.min.js:1:164843)
    at a (keras.min.js:1:164938)
    at <anonymous>

I am loading models using only .bin file, and it works great (except of this case). Probably, need to load models using json, weights & pb file?

model = new KerasJS.Model({
                filepath : "my_second.bin",
                gpu      : true
        });

It is not so easy to train my networks without interruption sometimes, but I'm unable to use models, that have been stopped and then continued training, may be anybody else faced this issue?

randaller commented 6 years ago

I have found the solution, this is really not keras.js, but Keras issue. Instead of loading all the model, just load only the weights, when you want to continue training.

model = load_model('my_first.h5')
# replace with
model.load_weights('my_first.h5')
# and then my_second.h5 will be the same size as my_first and keras.js will load converted .bin file well