Numpy: Parfois, supress_warnings manque l'un de ses attributs

Créé le 23 déc. 2016  ·  60Commentaires  ·  Source: numpy/numpy

Lorsque j'essaye de compiler skimage, j'obtiens parfois l'erreur suivante:

Traceback (most recent call last):
  File "/usr/lib/python2.7/dist-packages/nose/case.py", line 197, in runTest
    self.test(*self.arg)
  File "/build/skimage-0.12.3/debian/tmp/usr/lib/python2.7/dist-packages/skimage/transform/tests/test_integral.py", line 46, in test_vectorized_integrate
    assert_equal(expected, integrate(s, r0, c0, r1, c1))  # test deprecated
  File "/build/skimage-0.12.3/debian/tmp/usr/lib/python2.7/dist-packages/skimage/transform/integral.py", line 86, in integrate
    warn("The syntax 'integrate(ii, r0, c0, r1, c1)' is "
  File "/build/skimage-0.12.3/debian/tmp/usr/lib/python2.7/dist-packages/skimage/_shared/_warnings.py", line 16, in warn
    warnings.warn(message, stacklevel=stacklevel)
  File "/usr/lib/python2.7/dist-packages/numpy/testing/utils.py", line 2199, in _showwarning
    self._orig_show(message, category, filename, lineno,
AttributeError: 'suppress_warnings' object has no attribute '_orig_show'

Je suppose que c'est un problème numpy, mais je ne suis pas sûr.

00 - Bug numpy.testing

Tous les 60 commentaires

Hmmm, un peu bizarre. Y a-t-il des threads (étranges) en cours dans les tests skimage? Cela briserait assez gravement les tests d'avertissement, car la gestion des avertissements n'est pas thread-safe en python. J'ai un peu de mal à voir comment cela pourrait arriver, mais je devrais peut-être regarder le code exact du test.

Puisqu'il n'y a pas de assert_warns ou alors ici je suppose. Vous ne devriez avoir qu'un seul contexte suppress_warnings vivant (qui serait la portée la plus externe et créé par le testeur de numpy, en supposant que skimage finisse par l'utiliser). Maintenant, pourquoi je suis confus, c'est que _orig_show ne pas être défini ne devrait être possible que si le contexte a déjà été quitté. A ce moment, warnings.showwarning devrait déjà être réinitialisé à l'ancienne valeur.

Bien sûr, tout le contenu des avertissements tombe en panne si vous avez des threads. Par exemple:

thread1: entre dans le contexte d'avertissement -> remplace l'impression d'avertissement normale
thread2: entre dans le contexte d'avertissement -> remplace le gestionnaire d'avertissement de thread1
thread1: quitte le contexte d'avertissement -> réinitialise l'impression d'avertissement normale
thread2: existe un contexte d'avertissement -> réinitialise le gestionnaire d'avertissement de thread1 -> kaboom.

Btw. Je vois que vous avez un "essayez de nettoyer après __warning_registry__ trucs dans skimage, les avertissements de suppression est un gestionnaire de contexte qui essaie de résoudre un problème similaire (et ajoute d'autres choses), peut ou non être intéressant.

J'ai juste eu le problème quand j'ai essayé de construire skimage pour Debian, et je n'en ai aucune idée ici. Cependant, j'ai ouvert scikit-image / scikit-image # 2412 pour les impliquer.

Juste pour être complet: parfois, j'obtiens même un stacktrace sans aucune implication de skimage:

ERROR: test suite for <module 'skimage.transform.tests' from '/build/skimage-0.12.3/debian/tmp/usr/lib/python3/dist-packages/skimage/transform/tests/__init__.py'>
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/nose/suite.py", line 229, in run
    self.tearDown()
  File "/usr/lib/python3/dist-packages/nose/suite.py", line 352, in tearDown
    self.teardownContext(ancestor)
  File "/usr/lib/python3/dist-packages/nose/suite.py", line 368, in teardownContext
    try_run(context, names)
  File "/usr/lib/python3/dist-packages/nose/util.py", line 453, in try_run
    inspect.getargspec(func)
  File "/usr/lib/python3.5/inspect.py", line 1040, in getargspec
    stacklevel=2)
  File "/usr/lib/python3/dist-packages/numpy/testing/utils.py", line 2199, in _showwarning
    self._orig_show(message, category, filename, lineno,
AttributeError: 'suppress_warnings' object has no attribute '_orig_show'

Avec quelles versions de python, numpy, etc. compilez-vous?

Numpy 1.12 ~ RC ~ beta 1, Python 2.7 et 3.5
(désolé, mon erreur: je n'ai pas encore vérifié RC)

Hmm, je suis confus ... Je ne vois pas pourquoi il y aurait des problèmes de threading, mais je ne peux pas non plus comprendre cette erreur qui se produit sans une condition de concurrence ou une imbrication incorrecte de catch_warning comme des trucs (y compris suppress_warning ).

Je pense aussi que c'est une condition de course, car cela ne se produit pas toujours. L'exécution de la compilation deux fois dans exactement le même environnement permet au problème d'apparaître à différents endroits (ou même pas du tout).

@olebole comment

Copié de notre suite de tests :

#!/bin/sh
set -efu

pys="$(pyversions -rv 2>/dev/null)"
pkgbuild=${pkgbuild:-no}

srcdir=$PWD

for py in $pys; do
    echo "=== python$py ==="
    if [ "$pkgbuild" = "yes" ]; then
        export PYTHONPATH="$srcdir/debian/tmp/usr/lib/python$py/dist-packages"
        cd "$srcdir/build/"
    else
        cd "$ADTTMP"
    fi

    xvfb-run -a python$py /usr/bin/nosetests -s -v --exclude test_tools.py skimage 2>&1
done

Le xvfb-run est là puisque le test doit être exécuté dans un environnement X11.

Hmmmpf, quelqu'un sait ce qui se passe exactement sous le capot lorsque le nez commence à tester un module? Nose me trouble, et je ne vois pas pourquoi ça finirait aussi par jouer avec les avertissements ... Ou c'est un bug dans la suppression des avertissements après tout, mais je ne peux pas vraiment le voir, heh.

Dans ma page de manuel nosetests, j'ai

       --processes=NUM
              Spread  test run among this many processes. Set a number equal to the number of processors or cores in your machine for best results. Pass a negative
              number to have the number of processes automatically set to the number of cores. Passing 0 means to disable parallel testing.  Default  is  0  unless
              NOSE_PROCESSES is set. [NOSE_PROCESSES]

Il semble qu'il n'y ait pas de test parallèle par défaut. Au moins, la condition de course ne devrait pas être là.

Y a-t-il une chance éloignée que le nez exécute ce teardownContext basé sur des trucs de ramassage des ordures?

Non, je suis probablement stupide. Le contexte d'avertissement de suppression réinitialise warnings.showwarning avant de supprimer l'attribut, donc doute que même le gc qui entre en action ne puisse vraiment rien créer sans autre chose. Je n'ai aucune idée de quoi d'autre :).

Eh bien, je vois 33 erreurs avec skimage-0.9.3, la plupart provenant de PIL ou d'indexation, mais aucune pour la suppression. Comment gérez-vous toutes les autres erreurs?

@charris Le problème est signalé pour la version 0.12.3 et non la 0.9.3. :)

OK, finalement obtenu que cela descende de l'amont, maintenant 39 erreurs et une tonne de dépréciations. La plupart des avertissements semblent dus au fait que les tests pensent qu'ils s'exécutent dans QT au lieu de Wayland, pourraient être un problème de configuration ici. J'ai également besoin d'exécuter les tests comme

python -c'import skimage; skimage.test()'

car nosetests ne fonctionne pas du tout.

Les dépréciations sont normales. Nous vérifions toujours notre ancienne API, même si une dépréciation est attendue. Concernant les erreurs, ce n'est pas normal. Pourriez-vous les signaler sur notre (scikit-image) bug tracker s'il vous plaît?

@sciunto La documentation pourrait utiliser des instructions pour tester localement.

OK, je le vois au même endroit. Le test est

def test_vectorized_integrate():
    r0 = np.array([12, 0, 0, 10, 0, 10, 30])
    c0 = np.array([10, 0, 10, 0, 0, 10, 31])
    r1 = np.array([23, 19, 19, 19, 0, 10, 49])
    c1 = np.array([19, 19, 19, 19, 0, 10, 49])

    expected = np.array([x[12:24, 10:20].sum(),
                         x[:20, :20].sum(),
                         x[:20, 10:20].sum(),
                         x[10:20, :20].sum(),
                         x[0,0],
                         x[10, 10],
                         x[30:, 31:].sum()])
    start_pts = [(r0[i], c0[i]) for i in range(len(r0))]
    end_pts = [(r1[i], c1[i]) for i in range(len(r0))]
    assert_equal(expected, integrate(s, r0, c0, r1, c1))  # test deprecated
    assert_equal(expected, integrate(s, start_pts, end_pts))

Le commentaire # test deprecated me suggère que le test a peut-être besoin d'être corrigé, mais que suppress_warnings devrait quand même échouer plus gracieusement.

Un peu plus d'informations, faire

$ python skimage/transform/tests/test_integral.py

Qui utilise NumPy run_module_suite ne semble pas échouer, mais émet un avertissement

======================================================================
ERROR: skimage.transform.tests.test_integral.test_vectorized_integrate
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
    self.test(*self.arg)
  File "/home/charris/Workspace/scikit-image/skimage/transform/tests/test_integral.py", line 46, in test_vectorized_integrate
    assert_equal(expected, integrate(s, r0, c0, r1, c1))  # test deprecated
  File "/home/charris/Workspace/scikit-image/skimage/transform/integral.py", line 86, in integrate
    warn("The syntax 'integrate(ii, r0, c0, r1, c1)' is "
  File "/home/charris/Workspace/scikit-image/skimage/_shared/_warnings.py", line 16, in warn
    warnings.warn(message, stacklevel=stacklevel)
UserWarning: The syntax 'integrate(ii, r0, c0, r1, c1)' is deprecated, and will be phased out in release 0.14. The new syntax is 'integrate(ii, (r0, c0), (r1, c1))'.

Notez que scikit-image a son propre gestionnaire de contexte pour les avertissements dans skimage/_shared/_warnings.py . Cela peut être en conflit avec suppress_warnings .

Par curiosité, je me demande si cela fait une différence de spécifier explicitement DeprecationWarning au lieu d'utiliser la valeur par défaut UserWarning .

Donc je ne vois pas d'erreurs avec

$ nosetests-2.7 skimage/transform/tests/test_integral.py |& grep orig_show

Tandis que

$ nosetests-2.7 skimage/transform/tests/ |& grep orig_show

L'affiche environ 25% du temps. Cela suggère que la source de l'erreur se trouve ailleurs et que l'échec du test ne fait que l'exposer.

En particulier, skimage/transform/tests/test_geometric.py contient le gestionnaire de contexte d'avertissements expected_warnings et cela me rend suspect.

OK, maintenant je soupçonne le décorateur test_parallel , https://github.com/scikit-image/scikit-image/blob/master/skimage/_shared/testing.py . Par défaut, deux threads.

Si je supprime les trois fichiers en important test_parallel , il n'y a plus de problème.

EDIT: Et maintenant, je ne peux pas reproduire du tout le problème. Hmm ... Cela dépend peut-être aussi de ce qui fonctionne sur la machine.

Hmmm, le test_parallel pourrait l'être, je suppose, bien qu'en regardant le code, aucune des fonctions n'utilise évidemment un contexte d'avertissement, bien que ce ne soit pas impossible je suppose.

quelque chose dans test_hough_transform.py semble être l'initiateur. Avec ce fichier supprimé, il n'y a pas d'erreur.

EDIT: Peut-être parce qu'il précède le module test_integral.py ?

Le problème semble être ce test dans test_hough_transform.py

@test_parallel()
def test_hough_circle():
    # Prepare picture
    img = np.zeros((120, 100), dtype=int)
    radius = 20
    x_0, y_0 = (99, 50)
    y, x = circle_perimeter(y_0, x_0, radius)
    img[x, y] = 1

    out1 = tf.hough_circle(img, radius)
    out2 = tf.hough_circle(img, [radius])
    assert_equal(out1, out2)
    out = tf.hough_circle(img, np.array([radius], dtype=np.intp))
    assert_equal(out, out1)
    x, y = np.where(out[0] == out[0].max())
    assert_equal(x[0], x_0)
    assert_equal(y[0], y_0)

en particulier, l'une des deux lignes

    assert_equal(out1, out2)

# or

    assert_equal(out, out1)

Activera l'erreur.

De même, la suppression du décorateur @parallel corrige l'erreur. Donc, le résultat est que les threads en combinaison avec le assert_equal appelé avec des vecteurs conduit au problème.

Cela a du sens, la fonction assert equal l'utilise pour filtrer les avertissements ".*NAT ==" , nous pourrions peut-être essayer de le supprimer de cette fonction car il n'est pas vraiment évident que assert_equal supprime les avertissements (et donc ne filetage de soutien).

Belle traque de Chuck!

Essayer de le supprimer serait une bonne chose.

Je me demande s'il existe d'autres fonctions numpy qui ne sont pas thread-safe?

Pas sûr, je pense que nous n'utilisons que des avertissements dans la combinaison de test. Et le np.errstate est probablement threadsafe?

merci beaucoup pour cette belle enquête @charris et @seberg

Hmmm, je trouve ça un peu ennuyeux. Supprimer les suppressions là où elles se trouvent peut changer le comportement en aval, ce qui est probablement très bien (peut-être même plus propre), mais pas sûr que ce soit bon pour une version de correction de bogue. Pourrait également verrouiller un mutex sur les tests de type comparaison, ce qui peut ne pas toujours convenir en principe, mais je ne peux pas vraiment penser à comment cela pourrait se casser.

Je pense qu'il suffirait de corriger assert_equal , il faudra dans tous les cas le corriger à l'avenir pour la comparaison NaT. Notez que le NaT peut être converti en int64 et a la valeur min_int64.

Oh, c'est vrai, nous pouvons en fait simplement supporter NaT explicitement, un peu ennuyeux actuellement (car il n'y a pas de fonction pour vérifier spécifiquement NaT), mais pas difficile. Il y a une autre de ces choses autour d'autres comparaisons de tableaux, mais je suppose que ce n'est pas beaucoup utilisé (et je ne sais pas pour quoi).

L'ajout de la logique NaT aux assertions semble fonctionner assez bien pour master, même si je ne suis pas sûr que cela fonctionnera pour le backporting. Je pense que si le suppress_warnings peut être nouveau, la condition de concurrence elle-même était déjà présente dans la dernière version.

Nous avons encore besoin d'une fonction isnat ou peut-être de prendre en charge datetime/timedelta dans isnan .

Oui, d'accord sur la fonction isnat . Il existe également deux types de malédictions: timedelta64 et datetime64 . Notez que la valeur NaT n'est exposée nulle part non plus, nous pourrions probablement utiliser un np.nat également. La définition réelle est en ndarraytypes.h .

@charris , Chuck, quelle est votre np.isnat ou plutôt autorisez datetime et timedelta dans isnan ?

Hmm, mettre tout cela dans isnan est une pensée intéressante mais je soupçonne que cela pourrait causer des problèmes à ce moment, peut-être plus tard? @njsmith @juliantaylor Pensées?

@shoyer peut également avoir une opinion.

Je viens d'implémenter isnat , mais je ne suis pas sûr de tout le timing de la sortie. Si nous devons essayer de résoudre ce problème dans une version minimale, la meilleure option est probablement de brancher une version python isnat dans la combinaison de test, bien que la corriger puisse s'avérer un peu délicate dans tous les cas ( à tout le moins, les autres recevront plus d'avertissements qu'avant, mais peut-être que peu 1. utilisent notre combinaison de test et 2. testent réellement les avertissements avec soin).

Je ne considère pas l'échec comme terriblement grave, mais ce serait bien de le réparer. Une version python (privée?) D'isnat me conviendrait pour la version 1.12.

La docstring suppress_warnings doit également mentionner qu'elle n'est pas thread-safe.

Cela fait :)

merci beaucoup les gars pour avoir abordé le problème pendant les vacances et pour le débogage approfondi

puis-je faire quelque chose pour mettre en œuvre / tester une solution pour cela? debian a hâte de trouver une solution à ce problème :)

@sandrotosi , malheureusement c'est peut-être un peu délicat, la solution la plus simple peut être de ne pas utiliser les tests parallèles dans skimage, mais cela va quelque peu à l'encontre de l'objectif. Nous pouvons tout simplement faire quelque chose comme dans mes trucs isnat (en utilisant une version python privée d'isnat). Cependant, je ne suis pas certain que cela ne crée pas de régressions de test ailleurs: /.

L'ajout d'un mutex pour ces deux cas peut en fait être un hack plausible qui devrait éliminer le problème et semble peu susceptible de se détériorer (puisque vous n'appeleriez pas assert_equal ou similaire de l'intérieur de assert_equal ). Je n'utiliserais pas réellement cela dans numpy master, mais en tant que correction de bogue minimale pour 1.12, cela peut être une vraie option. Et cela n'interférerait pas avec les tests de skimage lui-même.

@olebole désactiverait les tests parallèles dans skimage serait une solution temporaire acceptable?

@seberg ouais, je pense que la cible pourrait être d'avoir un correctif minimal pour 1.12 et éventuellement de le résoudre de manière plus complète / plus complète dans master - cela au moins laisserait la prochaine version de Debian avoir numpy sans ce problème

@sandrotosi J'ai essayé l'approche de verrouillage dans gh-8427. Je ne sais pas si la pensée est folle ou non, mais si quelqu'un veut l'essayer ....

Existe-t-il un moyen de modifier simplement suppress_warnings pour avoir un comportement indéfini mais ne pas planter lorsqu'il est utilisé de manière multi-thread?

(J'ai quelques idées, mais je réfléchis toujours à la manière dont cela pourrait fonctionner.)

Bien sûr, nous ne pouvons tout simplement pas supprimer l'attribut, mais cela pourrait créer des bogues dans les tests plus tard ... Bien que je suppose que la plupart des combinaisons de test ne sont pas aussi pointilleuses que les tests d'avertissement, alors ....

J'ai téléchargé 1.12.0rc2 (qui contient https://github.com/numpy/numpy/pull/8427) sur debian et reconstruit 3 fois skimage (une version légèrement ancienne du paquet debian, sans la suite de tests complètement désactivée) et toutes les fois où il a été construit avec succès.

merci beaucoup les gars pour avoir travaillé là-dessus pendant les vacances!

Maintenant, des plans pour la version finale 1.12.0? :)

Je prévois de faire la version finale le 15 janvier.

Je peux confirmer que cela fonctionne avec rc2. Merci beaucoup pour vos efforts!

Je laisse cela ouvert jusqu'à ce qu'il soit corrigé dans master.

Hmm, pas fixé dans le master. @seberg Est-il correct que # 8421 fermera ça?

Corrigé par # 8421.

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

Questions connexes

marcocaccin picture marcocaccin  ·  4Commentaires

ghost picture ghost  ·  4Commentaires

Kreol64 picture Kreol64  ·  3Commentaires

inducer picture inducer  ·  3Commentaires

keithbriggs picture keithbriggs  ·  3Commentaires