Numpy: A veces, supress_warnings pierde uno de sus atributos

Creado en 23 dic. 2016  ·  60Comentarios  ·  Fuente: numpy/numpy

Al intentar compilar skimage, a veces aparece el siguiente error:

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'

Supongo que se trata de un gran problema, pero no estoy seguro.

00 - Bug numpy.testing

Todos 60 comentarios

Hmmm, un poco extraño. ¿Hay algún subproceso (extraño) en las pruebas de skimage? Eso rompería bastante las pruebas de advertencias, ya que el manejo de advertencias no es seguro para subprocesos en Python. Tengo un poco de dificultad para ver de qué otra manera podría suceder esto, pero tal vez debería mirar el código exacto que ejecuta la prueba.

Dado que no hay assert_warns o menos aquí, supongo. Solo debe tener un solo contexto suppress_warnings activo (que sería el alcance más externo y creado por el ejecutor de pruebas de numpy, asumiendo que skimage termina usándolo). Ahora, la razón por la que estoy confundido es que _orig_show no estar definido solo debería ser posible si el contexto ya se ha salido. En ese momento, warnings.showwarning ya debería restablecerse al valor anterior.

Por supuesto, todo el asunto de las advertencias se rompe si tienes hilos. Por ejemplo:

thread1: ingresa al contexto de advertencia -> reemplaza la impresión de advertencia normal
thread2: ingresa al contexto de advertencia -> reemplaza el manejador de advertencia thread1
thread1: sale del contexto de advertencia -> restablece la impresión de advertencia normal
thread2: existe un contexto de advertencia -> se restablece al controlador de advertencia de thread1 -> kaboom.

Por cierto. Veo que tienes un "intento de limpiar después de __warning_registry__ cosas en skimage, la supresión de advertencias es un administrador de contexto que intenta resolver un problema similar (y agrega algunas otras cosas), puede o no ser interesante.

Acabo de tener el problema cuando intenté construir skimage para Debian, y no tengo idea aquí. Sin embargo, abrí scikit-image / scikit-image # 2412 para involucrarlos.

Solo para completar: a veces, incluso obtengo un stacktrace sin ninguna participación 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'

¿Con qué versiones de python, numpy, etc. está compilando?

Numpy 1.12 ~ RC ~ beta 1, Python 2.7 y 3.5
(lo siento, mi error: todavía no comprobé RC)

Hmm, estoy confundido ... No puedo ver por qué habría problemas de subprocesos, pero tampoco puedo comprender que este error se produzca sin una condición de carrera o un anidamiento incorrecto de catch_warning como cosas (incluidas suppress_warning ).

También creo que es una condición de carrera, ya que no siempre ocurre. Ejecutar la compilación dos veces exactamente en el mismo entorno permite que el problema aparezca en diferentes lugares (o incluso que no aparezca en absoluto).

@olebole, ¿cómo estás ejecutando exactamente el traje de prueba?

Copiado de nuestro conjunto de pruebas :

#!/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

El xvfb-run está ahí, ya que la prueba debe ejecutarse en un entorno X11.

Hmmmpf, ¿alguien sabe qué sucede exactamente debajo del capó cuando la nariz comienza a probar un módulo? La nariz me confunde, y no veo por qué terminaría también jugando con las advertencias ... O es un error en la supresión de advertencias después de todo, pero realmente no puedo verlo, je.

En mi página de manual de nosetests, tengo

       --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]

Parece que no hay pruebas paralelas por defecto. Al menos, la condición de carrera no debería estar ahí.

¿Hay alguna posibilidad remota de que la nariz se pase este teardownContext basado en cosas de recolección de basura?

No, probablemente estoy siendo tonto. El contexto de advertencia de supresión restablece warnings.showwarning antes de eliminar el atributo, por lo que duda que incluso el gc que se activa no pueda realmente crear nada sin que suceda algo más. Simplemente no tengo idea de qué más :).

Bueno, veo 33 errores con skimage-0.9.3, la mayoría de PIL o indexación, pero ninguno para suprimir. ¿Cómo maneja todos los demás errores?

@charris El problema se informa para 0.12.3, no 0.9.3. :)

Bien, finalmente lo eliminé del flujo ascendente, ahora 39 errores y un montón de depreciaciones. La mayoría de las advertencias parecen deberse al hecho de que las pruebas piensan que se están ejecutando en QT en lugar de Wayland, podría ser un problema de configuración aquí. También necesito ejecutar las pruebas como

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

ya que nosetests no funciona en absoluto.

Las bajas son normales. Seguimos comprobando nuestra antigua API, incluso si se espera una desactivación. Acerca de los errores, no es normal. ¿Le importaría informarlos en nuestro rastreador de errores (scikit-image), por favor?

@sciunto Los docs podrían utilizar instrucciones para realizar pruebas localmente.

OK, lo veo en el mismo lugar. La prueba es

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))

El comentario # test deprecated me sugiere que tal vez la prueba necesite algunas correcciones, pero aún así suppress_warnings debería fallar con más gracia.

Un poco más de información, haciendo

$ python skimage/transform/tests/test_integral.py

Que usa NumPy run_module_suite no parece fallar, pero emite la advertencia

======================================================================
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))'.

Tenga en cuenta que scikit-image tiene su propio administrador de contexto para advertencias en skimage/_shared/_warnings.py . Eso puede estar en conflicto con suppress_warnings .

Por curiosidad, me pregunto si hay alguna diferencia en especificar explícitamente DeprecationWarning lugar de usar el valor predeterminado UserWarning .

Entonces no veo errores con

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

Mientras

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

Lo muestra aproximadamente el 25% del tiempo. Eso sugiere que la fuente del error se encuentra en otra parte y la prueba fallida simplemente lo expone.

En particular, skimage/transform/tests/test_geometric.py contiene el administrador de contexto de advertencias expected_warnings y eso me hace sospechar.

Bien, ahora sospecho que el decorador test_parallel , https://github.com/scikit-image/scikit-image/blob/master/skimage/_shared/testing.py . Ese valor predeterminado es dos subprocesos.

Si elimino los tres archivos que importan test_parallel , ya no hay problema.

EDITAR: Y ahora no puedo reproducir el problema en absoluto. Hmm ... Quizás también depende de qué más se esté ejecutando en la máquina.

Hmmm, el test_parallel podría ser, supongo, aunque mirando el código, ninguna de las funciones obviamente usa un contexto de advertencia, aunque no es imposible, supongo.

algo en test_hough_transform.py parece ser el iniciador. Con ese archivo eliminado no hay error.

EDITAR: ¿Quizás porque precede al módulo test_integral.py ?

El problema parece ser esta prueba en 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 particular, cualquiera de las dos líneas

    assert_equal(out1, out2)

# or

    assert_equal(out, out1)

Habilitará el error.

Del mismo modo, eliminar el decorador @parallel soluciona el error. Entonces, el resultado es que los hilos en combinación con assert_equal llamados con vectores conducen al problema.

Tiene sentido, la función de aserción igual la usa para filtrar advertencias de ".*NAT ==" , posiblemente podríamos intentar eliminarlo de esa función ya que no es realmente obvio que assert_equal haga una supresión de advertencia (y por lo tanto no soporte de roscado).

¡Qué bueno rastrear a Chuck!

Intentar eliminarlo sería algo bueno.

Me pregunto si hay otras funciones numpy que no son seguras para subprocesos.

No estoy seguro, creo que solo usamos material de advertencia en el traje de prueba. ¿Y el np.errstate probablemente sea seguro para subprocesos?

muchas gracias por esta linda investigación @charris y @seberg

Hmmm, lo encuentro un poco molesto. Eliminar las supresiones de donde se encuentran podría cambiar el comportamiento de las versiones posteriores, que probablemente esté bien (tal vez incluso más limpio), pero no estoy seguro de que sea bueno para una versión de corrección de errores. También podría bloquear un mutex en las pruebas de tipo de comparación, lo que puede no siempre estar bien en principio, pero realmente no puedo pensar en cómo podría romperse.

Creo que sería suficiente arreglar assert_equal , en cualquier caso, será necesario corregirlo en el futuro para la comparación de NaT. Tenga en cuenta que el NaT se puede convertir a int64 y tiene el valor min_int64.

Oh, es cierto, en realidad podemos admitir NaT explícitamente, un poco molesto actualmente (ya que no hay una función para verificar específicamente NaT), pero no es difícil. Hay otra de estas cosas en otras comparaciones de matrices, pero supongo que no se usa mucho (y no estoy seguro de qué).

Agregar lógica NaT a las afirmaciones parece funcionar bastante bien para master, aunque no estoy seguro de que funcione para backporting. Creo que si bien el suppress_warnings puede ser nuevo, la condición de carrera en sí ya estaba allí en la última versión.

Todavía necesitamos una función isnat o quizás admitamos datetime/timedelta en isnan .

Sí, estoy de acuerdo con la función isnat . También hay dos tipos donde ocurre: timedelta64 y datetime64 . Tenga en cuenta que el valor de NaT tampoco está expuesto en ninguna parte, probablemente también podríamos usar np.nat . La definición real está en ndarraytypes.h .

@charris , Chuck, ¿cuál es tu opinión al respecto? ¿Prefieres crear np.isnat o más bien permitir datetime y timedelta en isnan ?

Hmm, ponerlo todo en isnan es una idea interesante, pero sospecho que podría causar problemas en este momento, ¿tal vez más tarde? @njsmith @juliantaylor ¿Pensamientos?

@shoyer también puede tener una opinión.

Acabo de implementar isnat , pero no estoy seguro de todo lo relacionado con el tiempo con respecto al lanzamiento. Si tenemos que intentar arreglar esto en una versión mínima, la mejor opción es probablemente conectar una versión isnat python en el traje de prueba, aunque arreglarlo puede resultar un poco complicado en cualquier caso ( como mínimo, otros recibirán más advertencias que antes, aunque tal vez pocas 1. utilicen nuestro traje de prueba y 2. prueben las advertencias con cuidado).

No considero que la falla sea terriblemente grave, pero sería bueno arreglarla. Una versión de Python (¿privada?) De isnat estaría bien para mí por 1.12.

La cadena de documentación suppress_warnings también debe mencionar que no es segura para subprocesos.

Lo hace :)

muchas gracias chicos por abordar el tema durante las vacaciones y por la depuración completa

¿Hay algo que pueda hacer para implementar / probar una solución para esto? debian está ansioso por solucionar este problema :)

@sandrotosi , lamentablemente es un poco complicado, tal vez, la solución más simple puede ser simplemente no usar las pruebas paralelas en skimage, pero eso frustra un poco el propósito. Podemos simplemente hacer algo como en mis cosas de isnat (usando una versión privada de Python de isnat). Sin embargo, no estoy muy seguro de que no cree regresiones de prueba en otros lugares: /.

Agregar un mutex para esos dos casos puede ser un truco plausible que debería eliminar el problema y parece poco probable que salga mal (ya que no llamaría a assert_equal o similar desde dentro de assert_equal ). En realidad, no usaría eso en numpy master, pero como una corrección de error mínima para 1.12 puede ser una opción real. Y no interferiría con las pruebas de skimage en sí.

¿@olebole deshabilitaría las pruebas paralelas en skimage como una solución temporal aceptable?

@seberg, sí, creo que el objetivo podría ser tener una solución mínima para 1.12 y eventualmente abordarlo de una manera más completa / comprensiva en el maestro, eso al menos permitiría que la próxima versión de Debian tenga muchos problemas sin este problema

@sandrotosi Probé el enfoque de bloqueo en gh-8427. No estoy si el pensamiento es una locura o no, pero si alguien quiere probarlo ...

¿Hay alguna forma en la que podamos modificar suppress_warnings para tener un comportamiento indefinido pero que no se bloquee cuando se usa de manera multiproceso?

(Tengo algunas ideas, pero todavía estoy pensando en cómo podría funcionar exactamente).

Claro, simplemente no podemos eliminar el atributo, pero podría crear errores en las pruebas más adelante ... Aunque supongo que la mayoría de los trajes de prueba no son tan quisquillosos como numpy sobre las advertencias de prueba, así que ...

He subido 1.12.0rc2 (que contiene https://github.com/numpy/numpy/pull/8427) a Debian y reconstruí 3 veces el skimage (una versión un poco antigua del paquete debian, sin la suite de prueba completamente deshabilitada) y todas las veces que se construyó con éxito.

¡Muchas gracias a todos por trabajar en esto durante las vacaciones!

Ahora, ¿algún plan para la versión final 1.12.0? :)

Planeo hacer el lanzamiento final el 15 de enero.

Puedo confirmar que funciona con rc2. ¡Muchas gracias por tus esfuerzos!

Dejo esto abierto hasta que se arregle en el maestro.

Hmm, no fijo en maestro. @seberg ¿Es correcto que # 8421 cerrará esto?

Corregido por # 8421.

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

qualiaa picture qualiaa  ·  3Comentarios

keithbriggs picture keithbriggs  ·  3Comentarios

astrofrog picture astrofrog  ·  4Comentarios

thouis picture thouis  ·  4Comentarios

marcocaccin picture marcocaccin  ·  4Comentarios