web-dev-qa-db-fra.com

Erreur de mémoire lors de l'utilisation de Keras ImageDataGenerator

J'essaie de prédire les caractéristiques de l'imagerie à l'aide de keras avec un backend TensorFlow. Plus précisément, j'essaie d'utiliser un keras ImageDataGenerator . Le modèle est configuré pour fonctionner pendant 4 époques et fonctionne correctement jusqu'à la 4e époque où il échoue avec une erreur de mémoire.

J'exécute ce modèle sur une instance AWS g2.2xlarge exécutant Ubuntu Server 16.04 LTS (HVM), type de volume SSD.

Les images de formation sont des tuiles de pixels RVB 256x256 (8 bits non signés) et le masque de formation est des données en mosaïque 256x256 à bande unique (8 bits non signées) où 255 == une caractéristique intéressante et 0 == tout le reste.

Les 3 fonctions suivantes sont celles pertinentes pour cette erreur.

Comment puis-je résoudre cette erreur MemoryError?


def train_model():
        batch_size = 1
        training_imgs = np.lib.format.open_memmap(filename=os.path.join(data_path, 'data.npy'),mode='r+')
        training_masks = np.lib.format.open_memmap(filename=os.path.join(data_path, 'mask.npy'),mode='r+')
        dl_model = create_model()
        print(dl_model.summary())
        model_checkpoint = ModelCheckpoint(os.path.join(data_path,'mod_weight.hdf5'), monitor='loss',verbose=1, save_best_only=True)
        dl_model.fit_generator(generator(training_imgs, training_masks, batch_size), steps_per_Epoch=(len(training_imgs)/batch_size), epochs=4,verbose=1,callbacks=[model_checkpoint])

def generator(train_imgs, train_masks=None, batch_size=None):

# Create empty arrays to contain batch of features and labels#

        if train_masks is not None:
                train_imgs_batch = np.zeros((batch_size,y_to_res,x_to_res,bands))
                train_masks_batch = np.zeros((batch_size,y_to_res,x_to_res,1))

                while True:
                        for i in range(batch_size):
                                # choose random index in features
                                index= random.choice(range(len(train_imgs)))
                                train_imgs_batch[i] = train_imgs[index]
                                train_masks_batch[i] = train_masks[index]
                        yield train_imgs_batch, train_masks_batch
        else:
                rec_imgs_batch = np.zeros((batch_size,y_to_res,x_to_res,bands))
                while True:
                        for i in range(batch_size):
                                # choose random index in features
                                index= random.choice(range(len(train_imgs)))
                                rec_imgs_batch[i] = train_imgs[index]
                        yield rec_imgs_batch

def train_generator(train_images,train_masks,batch_size):
        data_gen_args=dict(rotation_range=90.,horizontal_flip=True,vertical_flip=True,rescale=1./255)
        image_datagen = ImageDataGenerator()
        mask_datagen = ImageDataGenerator()
# # Provide the same seed and keyword arguments to the fit and flow methods
        seed = 1
        image_datagen.fit(train_images, augment=True, seed=seed)
        mask_datagen.fit(train_masks, augment=True, seed=seed)
        image_generator = image_datagen.flow(train_images,batch_size=batch_size)
        mask_generator = mask_datagen.flow(train_masks,batch_size=batch_size)
        return Zip(image_generator, mask_generator)

Ce qui suit est la sortie du modèle détaillant les époques et le message d'erreur:

Epoch 00001: loss improved from inf to 0.01683, saving model to /home/ubuntu/deep_learn/client_data/mod_weight.hdf5
Epoch 2/4
7569/7569 [==============================] - 3394s 448ms/step - loss: 0.0049 - binary_crossentropy: 0.0027 - jaccard_coef_int: 0.9983  

Epoch 00002: loss improved from 0.01683 to 0.00492, saving model to /home/ubuntu/deep_learn/client_data/mod_weight.hdf5
Epoch 3/4
7569/7569 [==============================] - 3394s 448ms/step - loss: 0.0049 - binary_crossentropy: 0.0026 - jaccard_coef_int: 0.9982  

Epoch 00003: loss improved from 0.00492 to 0.00488, saving model to /home/ubuntu/deep_learn/client_data/mod_weight.hdf5
Epoch 4/4
7569/7569 [==============================] - 3394s 448ms/step - loss: 0.0074 - binary_crossentropy: 0.0042 - jaccard_coef_int: 0.9975  

Epoch 00004: loss did not improve
Traceback (most recent call last):
  File "image_rec.py", line 291, in <module>
    train_model()
  File "image_rec.py", line 208, in train_model
    dl_model.fit_generator(train_generator(training_imgs,training_masks,batch_size),steps_per_Epoch=1,epochs=1,workers=1)
  File "image_rec.py", line 274, in train_generator
    image_datagen.fit(train_images, augment=True, seed=seed)
  File "/home/ubuntu/pyvirt_test/local/lib/python2.7/site-packages/keras/preprocessing/image.py", line 753, in fit
    x = np.copy(x)
  File "/home/ubuntu/pyvirt_test/local/lib/python2.7/site-packages/numpy/lib/function_base.py", line 1505, in copy
    return array(a, order=order, copy=True)
MemoryError
15
Borealis

il semble que votre problème soit dû aux données trop volumineuses. Je peux voir deux solutions. La première consiste à exécuter votre code dans un système distribué au moyen de spark, je suppose que vous n'avez pas ce support, alors passons à l'autre.

Le deuxième est, je pense, viable. Je couperais les données et j'essaierais d'alimenter le modèle de manière incrémentielle. Nous pouvons le faire avec Dask. Cette bibliothèque peut découper les données et les enregistrer dans des objets que vous pourrez ensuite récupérer à partir du disque, uniquement dans la partie souhaitée.

Si vous avez une image dont la taille est une matrice de 100x100, nous pouvons récupérer chaque tableau sans avoir besoin de charger les 100 tableaux en mémoire. Nous pouvons charger tableau par tableau en mémoire (en libérant le précédent), ce qui serait l'entrée dans votre réseau neuronal.

Pour ce faire, vous pouvez transformer votre np.array en tableau dask et affecter les partitions. Par exemple:

>>> k = np.random.randn(10,10) # Matrix 10x10
>>> import dask.array as da
>>> k2 = da.from_array(k,chunks = 3)
dask.array<array, shape=(10, 10), dtype=float64, chunksize=(3, 3)>
>>> k2.to_delayed()
array([[Delayed(('array-a08c1d25b900d497cdcd233a7c5aa108', 0, 0)),
    Delayed(('array-a08c1d25b900d497cdcd233a7c5aa108', 0, 1)),
    Delayed(('array-a08c1d25b900d497cdcd233a7c5aa108', 0, 2)),
    Delayed(('array-a08c1d25b900d497cdcd233a7c5aa108', 0, 3))],
   [Delayed(('array-a08c1d25b900d497cdcd233a7c5aa108', 1, 0)),
    Delayed(('array-a08c1d25b900d497cdcd233a7c5aa108', 1, 1)),
    Delayed(('array-a08c1d25b900d497cdcd233a7c5aa108', 1, 2)),
    Delayed(('array-a08c1d25b900d497cdcd233a7c5aa108', 1, 3))],
   [Delayed(('array-a08c1d25b900d497cdcd233a7c5aa108', 2, 0)),
    Delayed(('array-a08c1d25b900d497cdcd233a7c5aa108', 2, 1)),
    Delayed(('array-a08c1d25b900d497cdcd233a7c5aa108', 2, 2)),
    Delayed(('array-a08c1d25b900d497cdcd233a7c5aa108', 2, 3))],
   [Delayed(('array-a08c1d25b900d497cdcd233a7c5aa108', 3, 0)),
    Delayed(('array-a08c1d25b900d497cdcd233a7c5aa108', 3, 1)),
    Delayed(('array-a08c1d25b900d497cdcd233a7c5aa108', 3, 2)),
    Delayed(('array-a08c1d25b900d497cdcd233a7c5aa108', 3, 3))]],
  dtype=object)

Ici, vous pouvez voir comment les données sont enregistrées dans des objets, puis vous pouvez les récupérer en plusieurs parties pour alimenter votre modèle.

Pour implémenter cette solution, vous devez introduire une boucle dans votre fonction qui appelle chaque partition et alimente le NN pour obtenir l'entraînement incrémentiel.

Pour plus d'informations, consultez la documentation Dask

9
Julio CamPlaz

Vous avez fourni un code assez déroutant (à mon avis), c'est-à-dire. aucun appel à _train_generator_ n'est visible. Je ne suis pas sûr que ce soit un problème de mémoire insuffisante en raison d'un big data, puisque vous utilisez memmap pour cela, mais supposons que pour l'instant c'est le cas.

  • Si les données sont assez volumineuses et puisque vous chargez les images à partir du répertoire de toute façon, il peut être utile d'envisager d'utiliser la méthode _flow_from_directory_ de ImageDataGenerator. Cela nécessiterait un léger changement de conception, cependant, ce qui pourrait ne pas être ce que vous voulez.

Vous pouvez le charger de la manière suivante:

_train_datagen = ImageDataGenerator()
train_generator = train_datagen.flow_from_directory(
        'data/train',
        target_size=(256, 256),
        batch_size=batch_size,
        ...  # other configurations)
_

Plus d'informations à ce sujet dans la documentation Keras .

  • Notez également que si vous avez 32 bits, le memmap ne permet pas plus de 2 Go.

  • Utilisez-vous _tensorflow-gpu_, par hasard? Peut-être que votre GPU n'est pas suffisant, vous pouvez essayer cela avec le paquetage tensorflow.

Je suggérerais fortement d'essayer quelques profilage de la mémoire pour voir où de plus grandes allocations de mémoire se produisent.


Si ce n'était pas le cas d'une mémoire insuffisante, cela pourrait être une mauvaise gestion des données dans votre modèle, car votre fonction de perte ne s'améliore pas du tout, elle pourrait être mal câblée par exemple.


Enfin, la dernière note ici .. c'est une bonne pratique de charger la memmap des données d'entraînement comme _read-only_, car vous ne voulez pas salir accidentellement les données.

[~ # ~] mise à jour [~ # ~] : je peux voir que vous avez mis à jour le message et fourni le code pour le _train_generator_, mais il n'y a toujours pas d'appel à cette méthode dans votre appel.

Si je suppose que vous avez une faute de frappe dans l'appel - _train_generator_ au lieu de la méthode generator dans votre méthode _d1_model.fit_generator_, il est possible que la méthode _fit_generator_ ne fonctionne pas sur un lot de données, mais en fait sur l'ensemble _training_imgs_ et il copie sur l'ensemble dans l'appel np.copy(x).

En outre, comme déjà mentionné, il y a en effet (vous pouvez en trouver certains, par exemple en voici un ouvert ) quelques problèmes avec la fuite de mémoire Keras lors de l'utilisation des fit et _fit_generator_ méthodes.

5
CermakM

Ceci est courant lors de l'exécution de 32 bits si la précision du flottant est trop élevée. Utilisez-vous 32 bits? Vous pouvez également envisager de lancer ou d'arrondir le tableau.

4
krflol

Keras/Tensorflow est généralement très bon avec l'utilisation des ressources, mais il y a une fuite de mémoire connue qui a causé des problèmes dans le passé. Pour vous assurer que ce n'est pas celui qui cause vos problèmes, essayez d'inclure ces deux lignes de code dans votre script de formation:

# load the backend
from keras import backend as K

# prevent Tensorflow memory leakage
K.clear_session()
4
mikkokotila

J'ai rencontré le même problème récemment. D'une manière ou d'une autre, le code FCN-8 peut s'exécuter avec succès sur mon tensorflow1.2 + keras2.0.9 + 8G RAM +1060 ordinateur, mais une erreur de mémoire s'est produite lors de l'utilisation de modelcheckpoint sur mon tf1.4 + keras2. 1.5 + 16g ram + ordinateur 1080ti.

1
liangjian