Pyradiomics: Erreur de mémoire lors de l'extraction de caractéristiques (pour de nombreuses images ou un grand masque)

Créé le 27 sept. 2017  ·  16Commentaires  ·  Source: AIM-Harvard/pyradiomics

Lorsque j'ai essayé d'extraire des fonctionnalités sur de nombreuses images en boucle à l'aide de PyRadiomics, j'ai rencontré une erreur de mémoire. J'ai pu reproduire deux types d'erreurs de mémoire avec un script simple et une seule image et un seul masque, en appelant à plusieurs reprises l'extraction de caractéristiques sur la même image.

J'ai mis le code pour reproduire l'erreur ici sur l'essentiel
Vous pouvez trouver les données d'image de test pour exécuter le script (ainsi que le fichier de script lui-même à nouveau) ici

Il existe deux cas d'erreur différents :

  1. Essayer d'extraire des caractéristiques d'un masque assez grand (-> "MemoryError" dans numpy)
  2. Essayer d'extraire des fonctionnalités de petits masques pour de nombreuses images dans une boucle (-> "Impossible d'allouer de la mémoire pour l'image" dans SimpleITK)

Vous pouvez les reproduire en (dé)commentant l'une des lignes définissant le masque à utiliser (voir aussi le commentaire explicatif en haut du script).

Détails de l'erreur du cas 1 :

Traceback (most recent call last):
  File "d:/Test/PyRadiomicsMemoryExceptionTest.py", line 26, in <module>
    featureVector = extractor.execute(testImage, testMask, label = 1)
  File "C:\Python36\lib\site-packages\pyradiomics-1.2.0.post25.dev0+g13274ff-py3.6-win32.egg\radiomics\featureextractor.py", line 354, in execute
    shapeClass = self.featureClasses['shape'](croppedImage, croppedMask, **self.settings)
  File "C:\Python36\lib\site-packages\pyradiomics-1.2.0.post25.dev0+g13274ff-py3.6-win32.egg\radiomics\shape.py", line 62, in __init__
    physicalCoordinates -= numpy.mean(physicalCoordinates, axis=0)  # Centered at 0
  File "C:\Python36\lib\site-packages\numpy\core\fromnumeric.py", line 2909, in mean
    out=out, **kwargs)
  File "C:\Python36\lib\site-packages\numpy\core\_methods.py", line 54, in _mean
    arr = asanyarray(a)
  File "C:\Python36\lib\site-packages\numpy\core\numeric.py", line 583, in asanyarray
    return array(a, dtype, copy=False, order=order, subok=True)
MemoryError

Détails de l'erreur du cas 2 :

Traceback (most recent call last):
  File "d:/Test/PyRadiomicsMemoryExceptionTest.py", line 27, in <module>
    featureVector = extractor.execute(testImage, testMask, label = 1)
  File "C:\Python36\lib\site-packages\pyradiomics-1.2.0.post25.dev0+g13274ff-py3.6-win32.egg\radiomics\featureextractor.py", line 346, in execute
    featureVector.update(self.getProvenance(imageFilepath, maskFilepath, mask))
  File "C:\Python36\lib\site-packages\pyradiomics-1.2.0.post25.dev0+g13274ff-py3.6-win32.egg\radiomics\featureextractor.py", line 440, in getProvenance
    for k, v in six.iteritems(generalinfoClass.execute()):
  File "C:\Python36\lib\site-packages\pyradiomics-1.2.0.post25.dev0+g13274ff-py3.6-win32.egg\radiomics\generalinfo.py", line 56, in execute
    generalInfo[el] = getattr(self, 'get%sValue' % el)()
  File "C:\Python36\lib\site-packages\pyradiomics-1.2.0.post25.dev0+g13274ff-py3.6-win32.egg\radiomics\generalinfo.py", line 139, in getVolumeNumValue
    ccif.Execute(labelMap)
  File "C:\Python36\lib\site-packages\SimpleITK\SimpleITK.py", line 20584, in Execute
    return _SimpleITK.ConnectedComponentImageFilter_Execute(self, *args)
RuntimeError: Exception thrown in SimpleITK ConnectedComponentImageFilter_Execute: c:\d\vs14-win32-pkg\simpleitk-build\itk-prefix\include\itk-4.11\itkImportImageContainer.hxx:199:
Failed to allocate memory for image.
bug installation

Tous les 16 commentaires

@JoostJM, faites-nous savoir si vous avez une idée de ce qui se passe ou si nous devons approfondir nos recherches.

@michaelschwier , quel type de matériel utilisez-vous ? Plus précisément, de combien de RAM disposiez-vous lors de l'exécution du script ?
J'ai testé votre script sur mon ordinateur (Intel Xeon E3-1241, 16 Go de RAM) et je n'ai eu aucun problème avec votre grand masque (il a exécuté 11 itérations, la mémoire fluctue, besoin maximum d'environ 2 Go). J'exécute également le petit script de masque (environ 600 itérations maintenant, ne nécessite toujours qu'environ 200 Mo de RAM), mais cela semble également fonctionner correctement.

Il est possible qu'il n'y ait pas assez de RAM disponible pour exécuter la pyradiomics. Nous intégrons déjà des améliorations pour réduire l'empreinte mémoire lors de l'extraction de caractéristiques, telles que le recadrage du cadre de délimitation de la segmentation avant l'extraction de caractéristiques. Cependant, générer des matrices de texture, en particulier lors de l'utilisation de grands masques, nécessite simplement beaucoup de mémoire. Pour vérifier davantage, je vais exécuter un profilage de la mémoire au fil du temps de votre script.

Votre petit masque pose cependant un cas intéressant. Il est possible que cela se bloque car plus tard, car la RAM est suffisante pour les premières itérations, mais s'épuise lorsque le vecteur de résultats devient trop grand (même si ce vecteur est relativement petit par rapport à l'utilisation globale de la mémoire de la pyrradiomic.

Quant aux solutions. S'il échoue déjà sur le premier filtre d'image composant connecté (comme c'est le cas dans votre grand boîtier de masque), je ne sais pas quoi faire. Vous pouvez supprimer cette partie du code en désactivant les informations supplémentaires (paramètre additionalInfo défini sur False ), mais je pense que cela échouera dans une autre partie du code (la partie la plus gourmande en mémoire les fonctions sont la génération de matrices de texture).
Pour votre petit étui de masque, consultez le script batch contenu dans les exemples. Ce script écrit les résultats de chaque cas (en les ajoutant à un fichier), empêchant ainsi une accumulation d'utilisation de la mémoire lors de l'extraction d'un gros lot. En théorie, le script batch ne devrait échouer en raison d'un manque de mémoire que si l'un des cas est trop volumineux pour être extrait (quel que soit le nombre de cas extraits auparavant).

Voici les graphiques de l'utilisation de la mémoire au fil du temps pour les grandes (~20 itérations) et les petites (~200 itérations). Je n'ai eu aucune erreur de mémoire et j'ai arrêté le processus.

Grand masque
large mask memory usage

Petit Masque
small mask memory usage

Si vous obtenez toujours vos erreurs de mémoire, pourriez-vous faire un graphique similaire ?
J'ai utilisé un simple package python appelé mprof ( pip install memory_profiler ), puis j'ai exécuté votre script en utilisant python C:\Python27\scripts\mprof run PyRadiomicsMemoryExceptionTest.py . Une fois cette opération terminée, vous pouvez voir le graphique en exécutant python C:\Python27\scripts\mprof plot

@JoostJM Merci pour votre réponse et votre vérification sur votre machine.
Mon système est Win 10 avec 16 Go de RAM. Pendant tous mes tests, il y avait toujours au moins 7 Go de RAM disponibles. Malheureusement, l'outil mprof ne fonctionne pas pour moi (Windows), il lève une exception indiquant qu'il ne peut pas accéder au code source !?

J'ai donc fait une observation "manuelle" de la mémoire en regardant la consommation de mémoire du processus dans le gestionnaire de tâches. Pour le cas avec le grand masque, le processus se bloque lors de l'utilisation d'environ 1,4 Go de mémoire. Pour le cas avec le petit masque le processus ne consomme jamais plus de 350 Mo de mémoire.

Cependant: j'utilisais un Python 32 bits. Donc, dans le cas des grands masques, je peux comprendre qu'il exécute notre mémoire (bien qu'il devrait toujours avoir une certaine marge à 1,4). Pour le cas des petits masques, cela ne devrait pas être un problème, cependant :/

J'ai maintenant également installé un Python 64 bits en parallèle et je n'arrive pas à reproduire les erreurs jusqu'à présent (> 1200 itérations sur le petit masque). Donc pour moi ça pourrait être la solution. Néanmoins le plantage du petit masque sur 32 bit me laisse encore perplexe...

Nous devrions penser à ne pas prendre en charge explicitement le python 32 bits. Nous ne prenons explicitement pas en charge les plates-formes 32 bits dans Slicer car nous avons eu tellement d'erreurs liées à la mémoire.

Je suggérerais de ne pas passer de temps sur ce problème à le déboguer en 32 bits et d'ajouter une note au guide de l'utilisateur indiquant que python 64 bits doit être utilisé.

Pourrait peut-être même ajouter un avertissement lors de l'installation de pyradiomics lors de la détection de python 32 bits !?

Pourrait peut-être même ajouter un avertissement lors de l'installation de pyradiomics lors de la détection de python 32 bits !?

Certainement, voire un échec.

Salut,

J'ai essayé d'exécuter un test.py pour vérifier que les radiomics fonctionnent, mais il n'arrête pas de dire qu'il ne peut pas importer de featureextracteur à partir de radiomics. Y a-t-il quelqu'un qui a le même problème ?

Merci d'avance

J'ai un problème similaire.
Je suis confronté à une erreur de mémoire lorsque j'essaie d'exécuter mon modèle. J'envoie 6500 images pour m'entraîner avec 7 légendes chacune.
J'utilise Ubuntu.

@Yukti-09, quelle version spécifique de PyRadiomics utilisez-vous ? quels paramètres ? De combien de RAM votre système dispose-t-il ?

Ne pas utiliser la pyromic

Salut! J'utilise la pyrradiomique pour l'image échographique 2D pour l'extraction de caractéristiques. J'utilise une base de données en libre accès d'images échographiques de la thyroïde (Disponible : thyroid http://cimalab.intec.co/applications/thyroid/ ). Lorsque j'utilise la pyrradiomic pour l'extraction de caractéristiques à partir d'un masque, cela nécessite plus de 16 Go de RAM. Y a-t-il des paramètres requis pour traiter les pyrradiomics afin de limiter l'utilisation de la mémoire ? Le masque est petit par rapport à l'image entière. Si l'extraction des caractéristiques du masque prend autant de mémoire, que se passera-t-il si je fais la même chose pour l'image entière ? Veuillez guider.

@ReemaParekh quel type de paramètres utilisez-vous lors de l'extraction ?

J'ai une image USG de taille 360x560 et j'utilise l'extraction de caractéristiques basée sur les voxels qui est appliquée sur l'ensemble de l'image et toutes les classes d'entités sont activées. Dans ce cas, l'utilisation de la mémoire a atteint 20 Go dans certains cas. J'utilise les paramètres ci-dessous pour la même chose.
featureVector = extractor.execute(image3D, mask,label=1,voxelBased=True)
paramètres = {}
paramètres['binWidth'] = 25

paramètres['force2D'] = vrai

paramètres['force2Ddimension'] = 0
settings['maskedKernel']=True
paramètres['initvalue']=5
paramètres['kernelRadius']=10
settings['resampledPixelSpacing'] = None # [3,3,3] est un exemple pour définir le rééchantillonnage (voxels de taille 3x3x3mm)
paramètres['interpolateur'] = sitk.sitkBSpline
settings['verbose'] = True

De plus, si j'écris force2D = true, mon code ne fonctionne pas. Sinon, cela fonctionne mais nécessite une mémoire énorme. J'ai une image 2D, mais je ne peux pas utiliser directement l'image 2D dans le programme de pyradiomics, j'ai donc converti l'image 2D en 1x360x560 à traiter. image3D=sitk.JoinSeries(image)

La mémoire requise semble valide. Sachez que les radiomics à base de voxels peuvent être très gourmands en mémoire, en particulier lors de l'extraction de l'image entière et de l'activation de toutes les fonctionnalités. La sortie est des cartes float64 pour chaque fonctionnalité, ce qui dans votre cas signifie 360x560x8 octets par carte de fonctionnalité. De plus, il y a une exigence de mémoire supplémentaire pour les cartes de caractéristiques intermédiaires, le masque, etc.

Quant au force2D, qu'entendez-vous par "ne fonctionne pas" ? PyRadiomics devrait être capable de gérer les deux entrées véritablement 2D, comme lorsque vous activez force2D. La seule chose que je peux imaginer qui va mal dans votre code est que si votre image a une taille de sitk 1x360x560, cela signifie que x est votre dimension force2D, et vous devez définir force2Ddimension sur 2 (raison de la matrice, qui est ordonnée comme z, y , X).

Cette page vous a été utile?
0 / 5 - 0 notes