Repository: keras-team/keras

Issue:
Keras >= 2.2.1 no longer respects fit_generator(validation_steps=...)
It seems that starting with Keras 2.2.1 `fit_generator()` no longer stops the validation process after `validation_steps` steps, but continues through the entire sequence. See this example code:

```
import numpy
from keras import Input, Model
from keras.layers import Dense
from keras.utils import Sequence

class Gen(Sequence):
    def __init__(self, name):
        super().__init__()
        self.name = name

    def __len__(self):
        return 1000

    def __getitem__(self, index):
        print('Generate %s %d' % (self.name, index))
        return numpy.zeros(shape=(10, 10)), numpy.zeros(shape=(10, 2))

i = Input(shape=(10,))
o = Dense(units=2)(i)
m = Model(i, o)
m.compile('sgd', 'mse')
m.fit_generator(
    generator=Gen('training_data'),
    shuffle=False,
    steps_per_epoch=5,
    validation_data=Gen('validation_data'),
    validation_steps=5,
    workers=1,
    max_queue_size=1,
    verbose=0,
)
```

Which will output

```
Generate validation_data 0
Generate validation_data 1
Generate training_data 0
Generate training_data 1
Generate training_data 2
Generate training_data 3
Generate training_data 4
Generate training_data 5
Generate training_data 6
Generate validation_data 2
Generate validation_data 3
Generate validation_data 4
Generate validation_data 5
Generate validation_data 6
Generate validation_data 7
...
Generate validation_data 998
Generate validation_data 999
```

This was working fine in keras 2.2.0.


Discussion:
My bad, I'll submit a PR right away.

Culprit : https://github.com/keras-team/keras/blob/master/keras/engine/training_generator.py#L114



Resolving patch:
diff --git a/keras/engine/training_generator.py b/keras/engine/training_generator.py
--- a/keras/engine/training_generator.py
+++ b/keras/engine/training_generator.py
@@ -111,7 +111,7 @@ def fit_generator(model,
                 if isinstance(val_data, Sequence):
                     val_enqueuer = OrderedEnqueuer(val_data,
                                                    use_multiprocessing=use_multiprocessing)
-                    validation_steps = len(val_data)
+                    validation_steps = validation_steps or len(val_data)
                 else:
                     val_enqueuer = GeneratorEnqueuer(val_data,
                                                      use_multiprocessing=use_multiprocessing)


Test patch:
diff --git a/tests/keras/engine/test_training.py b/tests/keras/engine/test_training.py
--- a/tests/keras/engine/test_training.py
+++ b/tests/keras/engine/test_training.py
@@ -23,11 +23,13 @@ class RandomSequence(Sequence):
     def __init__(self, batch_size, sequence_length=12):
         self.batch_size = batch_size
         self.sequence_length = sequence_length
+        self.logs = []  # It will work for use_multiprocessing=False
 
     def __len__(self):
         return self.sequence_length
 
     def __getitem__(self, idx):
+        self.logs.append(idx)
         return ([np.random.random((self.batch_size, 3)),
                  np.random.random((self.batch_size, 3))],
                 [np.random.random((self.batch_size, 4)),
@@ -410,26 +412,31 @@ def gen_data():
                   sample_weight_mode=None)
     trained_epochs = []
     trained_batches = []
+    val_seq = RandomSequence(4)
     out = model.fit_generator(generator=RandomSequence(3),
                               steps_per_epoch=3,
                               epochs=5,
                               initial_epoch=0,
-                              validation_data=RandomSequence(4),
+                              validation_data=val_seq,
                               validation_steps=3,
+                              max_queue_size=1,
                               callbacks=[tracker_cb])
     assert trained_epochs == [0, 1, 2, 3, 4]
     assert trained_batches == list(range(3)) * 5
+    assert len(val_seq.logs) <= 4 * 5
 
     # steps_per_epoch will be equal to len of sequence if it's unspecified
     trained_epochs = []
     trained_batches = []
+    val_seq = RandomSequence(4)
     out = model.fit_generator(generator=RandomSequence(3),
                               epochs=5,
                               initial_epoch=0,
-                              validation_data=RandomSequence(4),
+                              validation_data=val_seq,
                               callbacks=[tracker_cb])
     assert trained_epochs == [0, 1, 2, 3, 4]
     assert trained_batches == list(range(12)) * 5
+    assert len(val_seq.logs) == 12 * 5
 
     # fit_generator will throw an exception
     # if steps is unspecified for regular generator