Numpy: Às vezes, supress_warnings perde um de seus atributos

Criado em 23 dez. 2016  ·  60Comentários  ·  Fonte: numpy/numpy

Ao tentar compilar skimage, às vezes recebo o seguinte erro:

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'

Presumo que seja um problema entorpecido, mas não tenho certeza.

00 - Bug numpy.testing

Todos 60 comentários

Hmmm, um pouco estranho. Existe alguma segmentação (estranha) acontecendo nos testes de imagem de esqui? Isso interromperia o teste de aviso muito mal, uma vez que o tratamento de aviso não é thread-safe em python. Tenho um pouco de dificuldade em ver de que outra forma isso poderia acontecer, mas talvez deva olhar o código exato que o teste executa.

Já que não há assert_warns aqui, eu acho. Você deve ter apenas um único contexto suppress_warnings ativo (que seria o escopo mais externo e criado pelo executor de teste de numpy, assumindo que skimage acabe usando-o). Agora o que estou confuso é que _orig_show não sendo definido só deve ser possível se o contexto já tiver sido encerrado. Nesse momento, warnings.showwarning já deve ter sido redefinido para o valor antigo.

É claro que todo o material de avisos falha se você tiver tópicos. Por exemplo:

thread1: entra no contexto de aviso -> substitui a impressão normal de aviso
thread2: entra no contexto de aviso -> substitui o manipulador de aviso thread1
thread1: sai do contexto de aviso -> redefine para impressão de aviso normal
thread2: existe contexto de aviso -> redefine para o manipulador de aviso do thread1 -> kaboom.

Btw. Vejo que você tem uma "tentativa de limpar após __warning_registry__ coisas em skimage, o suprimir avisos é um gerenciador de contexto que tenta resolver um problema semelhante (e adiciona outras coisas), pode ou não ser interessante.

Acabei de pegar o problema quando tentei construir o skimage para o Debian e não tenho ideia aqui. No entanto, abri scikit-image / scikit-image # 2412 para envolvê-los.

Apenas para completar: às vezes, eu até obtenho um rastreamento de pilha sem qualquer envolvimento de imagem de esqui:

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'

Com quais versões de python, numpy, etc. você está compilando?

Numpy 1.12 ~ RC ~ beta 1, Python 2.7 e 3.5
(desculpe, meu erro: não verifiquei RC ainda)

Hmm, estou confuso .... Não consigo ver por que haveria problemas de threading, mas também não consigo entender esse erro ocorrendo sem uma condição de corrida ou aninhamento incorreto de coisas semelhantes a catch_warning (incluindo suppress_warning ).

Eu também acho que é uma condição de corrida, já que nem sempre acontece. Executar a compilação duas vezes exatamente no mesmo ambiente permite que o problema apareça em lugares diferentes (ou nem mesmo).

@olebole, como exatamente você está executando o traje de teste?

Copiado de nosso pacote de testes :

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

O xvfb-run está lá, pois o teste precisa ser executado em um ambiente X11.

Hmmmpf, alguém sabe o que exatamente acontece sob o capô quando o nariz começa a testar um módulo? O Nose me confunde, e não consigo ver por que ele acabaria também bagunçando avisos ... Ou é um bug em suprimir avisos, mas não consigo ver realmente, heh.

Na minha página de manual nosetests, tenho

       --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 não há teste paralelo por padrão. Pelo menos, a condição de corrida não deveria estar lá.

Existe alguma chance remota de que o nariz execute este teardownContext base no material de coleta de lixo ?!

Não, provavelmente estou sendo bobo. O contexto de aviso de supressão redefine warnings.showwarning antes de excluir o atributo, portanto, duvide que até mesmo o gc inicializando não possa realmente criar nada sem que algo mais aconteça. Só não tenho ideia do que mais :).

Bem, vejo 33 erros com skimage-0.9.3, a maioria de PIL ou indexação, mas nenhum para suprimir. Como você lida com todos os outros erros?

@charris O problema é relatado para 0.12.3, não 0.9.3. :)

OK, finalmente consegui puxar do upstream, agora com 39 erros e uma tonelada de depreciações. A maioria dos avisos parece devido ao fato de que os testes pensam que estão rodando em QT em vez de Wayland, pode ser um problema de configuração aqui. Eu também preciso executar os testes como

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

porque nosetests não funciona de todo.

As suspensões são normais. Ainda verificamos nossa API antiga, mesmo que uma suspensão de uso seja esperada. Sobre erros, não é normal. Você se importaria de relatá-los em nosso rastreador de bug (imagem do scikit), por favor?

@sciunto Os documentos podem usar instruções para testar localmente.

OK, vejo no mesmo lugar. O teste é

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

O comentário # test deprecated sugere para mim que talvez o teste precise de alguns consertos, mas ainda suppress_warnings deve falhar mais normalmente.

Um pouco mais de informação, fazendo

$ python skimage/transform/tests/test_integral.py

Que usa NumPy run_module_suite não parece falhar, mas emite o aviso

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

Observe que scikit-image tem seu próprio gerenciador de contexto para avisos em skimage/_shared/_warnings.py . Isso pode estar em conflito com suppress_warnings .

Por curiosidade, eu me pergunto se faz diferença especificar explicitamente DeprecationWarning vez de usar o UserWarning padrão.

Portanto, não vejo erros com

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

Enquanto que

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

Mostra cerca de 25% das vezes. Isso sugere que a origem do erro está em outro lugar e a falha no teste apenas o expõe.

Em particular, skimage/transform/tests/test_geometric.py contém o gerenciador de contexto de avisos expected_warnings e isso me deixa desconfiado.

OK, agora eu suspeito do decorador test_parallel , https://github.com/scikit-image/scikit-image/blob/master/skimage/_shared/testing.py . O padrão é dois threads.

Se eu remover os três arquivos importando test_parallel , não haverá mais um problema.

EDIT: E agora não consigo reproduzir o problema de forma alguma. Hmm ... Talvez também dependa do que mais está sendo executado na máquina.

Hmmm, o test_parallel poderia ser isso eu acho, embora olhando através do código, nenhuma das funções obviamente usa um contexto de aviso, embora não seja impossível, eu acho.

algo em test_hough_transform.py parece ser o iniciador. Com esse arquivo removido, não há erro.

EDITAR: Talvez porque precede o módulo test_integral.py ?

O problema parece ser este teste em 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)

em particuler, qualquer uma das duas linhas

    assert_equal(out1, out2)

# or

    assert_equal(out, out1)

Ativará o erro.

Da mesma forma, remover o decorador @parallel corrige o erro. Portanto, o resultado é que os threads em combinação com assert_equal chamados com vetores levam ao problema.

Faz sentido, a função assert equal usa para filtrar avisos ".*NAT ==" , poderíamos tentar removê-lo dessa função, pois não é realmente óbvio que assert_equal supressa avisos (e, portanto, não totalmente encadeamento de suporte).

Bom rastrear Chuck!

Tentar removê-lo seria uma coisa boa.

Eu me pergunto se existem outras funções numpy que não são thread-safe?

Não tenho certeza, acho que só usamos avisos no traje de teste. E o np.errstate provavelmente é threadsafe?

muito obrigado por esta boa investigação @charris e @seberg

Hmmm, acho um pouco chato. Remover as supressões de onde elas estão pode mudar o comportamento do downstream, o que provavelmente é bom (talvez até mais limpo), mas não tenho certeza se é bom para uma versão de correção de bug. Também poderia bloquear um mutex nos testes de tipo de comparação, o que nem sempre pode funcionar bem, mas não consigo pensar em como isso poderia quebrar.

Eu acho que seria o suficiente apenas para corrigir assert_equal , ele precisará consertar no futuro para a comparação NaT em qualquer caso. Observe que o NaT pode ser convertido em int64 e tem o valor min_int64.

Oh, é verdade, podemos apenas suportar NaT explicitamente, um pouco chato atualmente (uma vez que não há função para fazer a verificação de NaT especificamente), mas não é difícil. Há outra dessas coisas em outras comparações de array, mas acho que não é muito usada (e não tenho certeza para quê).

Adicionar lógica NaT aos assert parece funcionar muito bem para o master, embora eu não tenha certeza de que funcionará para backporting. Eu acho que enquanto suppress_warnings pode ser novo, a condição de corrida em si já estava lá no último lançamento.

Ainda precisamos de uma função isnat ou talvez suporte datetime/timedelta em isnan .

Sim, concordo com a função isnat . Existem também dois tipos onde estão as contas: timedelta64 e datetime64 . Observe que o valor NaT também não está exposto em nenhum lugar, provavelmente poderíamos usar um np.nat também. A definição real está em ndarraytypes.h .

@charris , Chuck, qual é a sua opinião sobre isso, em vez de criar np.isnat ou permitir datetime e timedelta em isnan ?

Hmm, colocar tudo em isnan é um pensamento interessante, mas eu suspeito que pode causar problemas neste momento, talvez mais tarde? @njsmith @juliantaylor Thoughts?

@shoyer também pode ter uma opinião.

Acabei de implementar isnat , mas não tenho certeza sobre todas as coisas de tempo com relação ao lançamento. Se tivermos que tentar consertar isso em uma versão mínima, a melhor opção é provavelmente conectar uma versão python isnat no traje de teste, embora consertá-lo possa ser um pouco complicado em qualquer caso ( no mínimo, outros receberão mais avisos do que antes, embora talvez poucos 1. use nosso material de teste e 2. teste os avisos com cuidado).

Não considero a falha muito grave, mas seria bom consertá-la. Uma versão python (privada?) De isnat estaria bem para mim para 1.12.

O docstring suppress_warnings também deve mencionar que não é seguro para threads.

Sim :)

muito obrigado, pessoal, por abordar o problema durante as férias e pela depuração completa

há algo que eu possa fazer para implementar / testar uma solução para isso? debian está ansioso para obter uma solução para isso :)

@sandrotosi , infelizmente é um pouco complicado, talvez, a correção mais simples pode ser simplesmente não usar o material de teste paralelo no skimage, mas isso de alguma forma anula o propósito. Podemos simplesmente fazer algo como nas minhas coisas isnat (usando uma versão python privada do isnat). No entanto, não estou certo de que não possa criar regressões de teste em outro lugar: /.

Adicionar um mutex para esses dois casos pode na verdade ser um hack plausível que deve remover o problema e parece improvável que dê errado (já que você não chamaria assert_equal ou similar de dentro de assert_equal ). Eu realmente não usaria isso no numpy master, mas como uma correção de bug mínima para 1.12, pode ser uma opção real. E não iria interferir nos próprios testes de imagem de esqui.

@olebole desabilitaria o teste paralelo em imagem de esqui seria uma solução temporária aceitável?

@seberg sim, eu acho que o objetivo pode ser ter uma correção mínima para 1.12 e, eventualmente, resolvê-lo de uma forma mais completa / abrangente no master - que pelo menos deixaria o próximo lançamento debian ter um numpy sem esse problema

@sandrotosi Tentei a abordagem de bloqueio no gh-8427. Eu não sou se o pensamento é maluco ou não, mas se alguém quiser experimentar ....

Existe alguma maneira de simplesmente modificar suppress_warnings para ter um comportamento indefinido, mas não travar quando usado em uma forma multi-threaded?

(Tenho algumas ideias, mas ainda estou pensando em como exatamente isso poderia funcionar.)

Claro, não podemos simplesmente excluir o atributo, mas isso pode criar bugs nos testes posteriormente ... Embora eu ache que a maioria dos conjuntos de teste não são tão detalhistas quanto entediantes sobre avisos de teste, então ....

Eu carreguei 1.12.0rc2 (que contém https://github.com/numpy/numpy/pull/8427) para debian e reconstruí 3 vezes o skimage (uma versão ligeiramente antiga do pacote debian, sem o conjunto de testes completamente desativado) e todas as vezes em que foi construído com sucesso.

muito obrigado pessoal por trabalhar nisso durante as férias!

Agora, algum plano para o lançamento final 1.12.0? :)

Pretendo fazer o lançamento final em 15 de janeiro.

Posso confirmar que funciona com rc2. Muito obrigado pelos seus esforços!

Estou deixando isso aberto até que seja corrigido no mestre.

Hmm, não fixado no mestre. @seberg É correto que # 8421 fechará isso?

Corrigido por # 8421.

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

navytux picture navytux  ·  4Comentários

marcocaccin picture marcocaccin  ·  4Comentários

dcsaba89 picture dcsaba89  ·  3Comentários

perezpaya picture perezpaya  ·  4Comentários

inducer picture inducer  ·  3Comentários