2

I have made a custom generator in which I need my model's prediction, during training, to do some calculations on it, before it is trained against the true labels. Therefore, I save the model first and then call model.predict() on the current state.

from keras.models import load_model
def custom_generator(model):
  while True:
    state, target_labels = next(train_it)

    model.save('my_model.h5')
    #pause training and do some calculations on the output of the model trained so far     
    print(state)
    print(target_labels)
    model.predict(state)         
    #resume training
    #model = load_model('my_model.h5')

    yield state, target_labels

model3.fit_generator(custom_generator(model3), steps_per_epoch=1, epochs = 10)
loss = model3.evaluate_generator(test_it, steps=1)
loss

I get the following error due to calling model.predict(model) in the custom_generator()

Error:

ValueError: Tensor Tensor("dense_2/Softmax:0", shape=(?, 200), dtype=float32) is not an element of this graph.

Kindly, help me how to get model predictions(or last layer output) in a custom generator during training.

This is my model:

#libraries
import keras
from keras.models import Sequential
from keras.layers import Dense
from keras.optimizers import SGD
from matplotlib import pyplot
from keras.applications.vgg16 import VGG16

model = VGG16(include_top=False, weights='imagenet')
print(model.summary())

#add layers
z = Conv2D(1, (3, 3), activation='relu')(model.output)
z = Conv2D(1,(1,1), activation='relu')(z)
z = GlobalAveragePooling2D()(z)
predictions3 = Dense(200, activation='softmax')(z)
model3 = Model(inputs=model.input, outputs=predictions3)
for layer in model3.layers[:20]:
   layer.trainable = False
for layer in model3.layers[20:]:
   layer.trainable = True
model3.compile(optimizer=SGD(lr=0.0001, momentum=0.9), loss='categorical_crossentropy')

Image data generators for loading training and testing data

from keras.preprocessing.image import ImageDataGenerator
# create a data generator
datagen = ImageDataGenerator()
# load and iterate training dataset
train_it = datagen.flow_from_directory('DATA/C_Train/', class_mode='categorical', batch_size=1)
test_it = datagen.flow_from_directory('DATA/C_Test/', class_mode='categorical', batch_size=1)
Umair Javaid
  • 421
  • 2
  • 7
  • 22
  • could you please provide `train_it` and `test_it`? – Muhammad Nizami Oct 03 '19 at 00:34
  • sure those are just image data generators, used to load training and testing data – Umair Javaid Oct 03 '19 at 01:47
  • When you load a model, the saved model doesn't get fully deleted from the running kernel - this can be troublesome; try deleting the saved model before loading and after predicting - or do: predict -> save -> del -> load -- see [here](https://stackoverflow.com/questions/58137677/keras-model-training-memory-leak/58138230#58138230) – OverLordGoldDragon Oct 03 '19 at 02:05
  • Try insert `model._make_predict_function()` after you load the model (see [here](https://github.com/keras-team/keras/issues/6462)). – Gary Goh Oct 03 '19 at 02:10
  • @OverLordGoldDragon predicting directly from a model that is currently being trained doesn't work... – Umair Javaid Oct 03 '19 at 08:07
  • @GaryGoh that doesn't work either. It throws "Tensor Tensor("dense_6/Softmax:0", shape=(?, 200), dtype=float32) is not an element of this graph." error – Umair Javaid Oct 03 '19 at 08:48
  • @UmairJavaid Do you depend on the functionality of `fit_generator` somehow (e.g. multiprocessing)? What you seek can be easily accomplished via `train_on_batch` and data fed in a for/while-loop – OverLordGoldDragon Oct 03 '19 at 15:42
  • @OverLordGoldDragon Can u show/give me an example please – Umair Javaid Oct 04 '19 at 00:13
  • @UmairJavaid It'd look something like [this](https://github.com/OverLordGoldDragon/keras-adamw#example) (see "for epoch in range..."); if you're fine with it, I can write a complete answer – OverLordGoldDragon Oct 04 '19 at 00:20
  • @OverLordGoldDragon Wouldn't it be very slow? – Umair Javaid Oct 04 '19 at 00:21
  • @UmairJavaid Unless your `fit_generator` sets `use_multiprocessing=True`, it'll be just as fast, if not faster -- I train all my models via `train_on_batch` as it gives me greater control and minimizes redundant processes used by `fit` and `fit_generator` – OverLordGoldDragon Oct 04 '19 at 00:22
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/200370/discussion-between-umair-javaid-and-overlordgolddragon). – Umair Javaid Oct 04 '19 at 00:23

1 Answers1

1

Your best bet may be to write a custom train loop via train_on_batch or fit; the former's only disadvantaged if use_multiprocessing=True, or using callbacks - which isn't the case. Below is an implementation with train_on_batch - if you use fit instead (for multiprocessing, callbacks, etc), make sure you feed only one batch at a time, and provide no validation data (use model.evaluate instead) - else the control flow breaks. (Also, a custom Callback is a valid, but involved alternative)


CUSTOM TRAIN LOOP
iters_per_epoch = len(train_it) // batch_size
num_epochs = 5
outs_store_freq = 20 # in iters
print_loss_freq = 20 # in iters

iter_num = 0
epoch_num = 0
model_outputs = []
loss_history  = []

while epoch_num < num_epochs:
    while iter_num < iters_per_epoch:
        x_train, y_train = next(train_it)
        loss_history += [model3.train_on_batch(x_train, y_train)]

        x_test, y_test = next(test_it)
        if iter_num % outs_store_freq == 0:
            model_outputs += [model3.predict(x_test)]
        if iter_num % print_loss_freq == 0:
            print("Iter {} loss: {}".format(iter_num, loss_history[-1]))

        iter_num += 1
    print("EPOCH {} FINISHED".format(epoch_num + 1))
    epoch_num += 1
    iter_num = 0 # reset counter


FULL CODE
from keras.models import Sequential
from keras.layers import Dense, Conv2D, GlobalAveragePooling2D
from keras.models import Model
from keras.optimizers import SGD
from keras.applications.vgg16 import VGG16
from keras.preprocessing.image import ImageDataGenerator

model = VGG16(include_top=False, weights='imagenet')
print(model.summary())

#add layers
z = Conv2D(1, (3, 3), activation='relu')(model.output)
z = Conv2D(1,(1,1), activation='relu')(z)
z = GlobalAveragePooling2D()(z)
predictions3 = Dense(2, activation='softmax')(z)
model3 = Model(inputs=model.input, outputs=predictions3)

for layer in model3.layers[:20]:
   layer.trainable = False
for layer in model3.layers[20:]:
   layer.trainable = True

model3.compile(optimizer=SGD(lr=0.0001, momentum=0.9), 
               loss='categorical_crossentropy')
batch_size = 1
datagen = ImageDataGenerator()
train_it = datagen.flow_from_directory('DATA/C_Train/', 
                                        class_mode='categorical', 
                                        batch_size=batch_size)
test_it = datagen.flow_from_directory('DATA/C_Test/', 
                                      class_mode='categorical', 
                                      batch_size=batch_size)

[custom train loop here]


BONUS CODE: to get outputs of any layer, use below:

def get_layer_outputs(model, layer_name, input_data, learning_phase=1):
    outputs   = [layer.output for layer in model.layers if layer_name in layer.name]
    layers_fn = K.function([model.input, K.learning_phase()], outputs)
    return [layers_fn([input_data,learning_phase])][0]

outs = get_layer_outputs(model, 'dense_1', x_test, 0) # 0 == inference mode
Umair Javaid
  • 421
  • 2
  • 7
  • 22
OverLordGoldDragon
  • 1
  • 9
  • 53
  • 101