Solução de problemas

Caminho binário do Python ausente

Mensagem de erro:

ERROR: An error occurred during the fetch of repository 'local_execution_config_python':
  Traceback (most recent call last):
       File "/sandbox_path/external/org_tensorflow/third_party/py/python_configure.bzl", line 208
               get_python_bin(repository_ctx)
    ...
Repository command failed

geralmente indica que o Bazel não encontra o binário local do Python. Para resolver esse problema, primeiro encontre onde o binário do Python está e adicione --action_env PYTHON_BIN_PATH=<path to python binary> ao comando Bazel. Por exemplo, é possível alternar para usar o binário python3 padrão do sistema com o seguinte comando:

bazel build -c opt \
  --define MEDIAPIPE_DISABLE_GPU=1 \
  --action_env PYTHON_BIN_PATH=$(which python3) \
  mediapipe/examples/desktop/hello_world

Faltam pacotes Python necessários

Mensagem de erro:

ImportError: No module named numpy
Is numpy installed?

geralmente indica que alguns pacotes do Python não estão instalados. Execute pip install ou pip3 install, dependendo da versão binária do Python, para instalar esses pacotes.

Falha ao buscar repositórios de dependências remotos

Mensagem de erro:

ERROR: An error occurred during the fetch of repository 'org_tensorflow':
   java.io.IOException: Error downloading [https://mirror.bazel.build/github.com/tensorflow/tensorflow/archive/77e9ffb9b2bfb1a4f7056e62d84039626923e328.tar.gz, https://github.com/tensorflow/tensorflow/archive/77e9ffb9b2bfb1a4f7056e62d84039626923e328.tar.gz] to /sandbox_path/external/org_tensorflow/77e9ffb9b2bfb1a4f7056e62d84039626923e328.tar.gz: Tried to reconnect at offset 9,944,151 but server didn't support it

or

WARNING: Download from https://storage.googleapis.com/mirror.tensorflow.org/github.com/bazelbuild/rules_swift/releases/download/0.12.1/rules_swift.0.12.1.tar.gz failed: class java.net.ConnectException Connection timed out (Connection timed out)

geralmente indica que o Bazel não consegue fazer o download dos repositórios de dependência necessários que a MediaPipe precisa. O MediaPipe tem vários repositórios de dependências hospedados por sites do Google. Em algumas regiões, talvez seja necessário configurar um proxy de rede ou usar uma VPN para acessar esses recursos. Talvez seja necessário anexar --host_jvm_args "-DsocksProxyHost=<ip address> -DsocksProxyPort=<port number>" ao comando do Bazel. Consulte este problema do GitHub para mais detalhes.

Se você acredita que não é um problema de rede, outra possibilidade é que alguns recursos estejam temporariamente indisponíveis. Execute bazel clean --expunge e tente novamente mais tarde. Se ainda não funcionar, registre um problema no GitHub com a mensagem de erro detalhada.

Configuração incorreta do MediaPipe OpenCV

Mensagem de erro:

error: undefined reference to 'cv::String::deallocate()'
error: undefined reference to 'cv::String::allocate(unsigned long)'
error: undefined reference to 'cv::VideoCapture::VideoCapture(cv::String const&)'
...
error: undefined reference to 'cv::putText(cv::InputOutputArray const&, cv::String const&, cv::Point, int, double, cv::Scalar, int, int, bool)'

geralmente indica que o OpenCV não está configurado corretamente para o MediaPipe. Confira as seções "Instalar o OpenCV e o FFmpeg" em Instalação para saber como modificar os arquivos WORKSPACE e linux_opencv/macos_opencv/windows_opencv.BUILD do MediaPipe para suas bibliotecas opencv locais. Este problema do GitHub também pode ajudar.

Falha no pip install do Python

Mensagem de erro:

ERROR: Could not find a version that satisfies the requirement mediapipe
ERROR: No matching distribution found for mediapipe

depois de executar pip install mediapipe, geralmente indica que não há um MediaPipe Python qualificado para seu sistema. O MediaPipe Python PyPI oferece suporte oficial à versão 64 bits do Python 3.7 a 3.10 nos seguintes SO:

  • Linux x86_64
  • x86_64 macOS 10.15 ou mais recente
  • Windows amd64

Se o SO tiver suporte e você ainda receber esse erro, verifique se o binário do Python e do pip são para o Python 3.7 a 3.10. Caso contrário, considere criar o pacote do Python do MediaPipe localmente seguindo as instruções aqui.

Falha no carregamento de DLL do Python no Windows

Mensagem de erro:

ImportError: DLL load failed: The specified module could not be found

geralmente indica que o sistema Windows local está sem pacotes redistribuíveis do Visual C++ e/ou DLLs do ambiente de execução do Visual C++. Isso pode ser resolvido instalando o vc_redist.x64.exe oficial ou o pacote Python "msvc-runtime", executando

$ python -m pip install msvc-runtime

O pacote Python "msvc-runtime" não é lançado nem mantido pela Microsoft.

Método nativo não encontrado

Mensagem de erro:

java.lang.UnsatisfiedLinkError: No implementation found for void com.google.wick.Wick.nativeWick

geralmente indica que uma biblioteca nativa necessária, como /libwickjni.so, não foi carregada ou incluída nas dependências do app ou não pode ser encontrada por algum motivo. O Java exige que todas as bibliotecas nativas sejam carregadas explicitamente usando a função System.loadLibrary.

Nenhuma calculadora registrada encontrada

Mensagem de erro:

No registered object with name: OurNewCalculator; Unable to find Calculator "OurNewCalculator"

geralmente indica que OurNewCalculator é referenciado por nome em um CalculatorGraphConfig, mas que o destino da biblioteca para OurNewCalculator não foi vinculado ao binário do aplicativo. Quando uma nova calculadora é adicionada a um gráfico de calculadora, ela também precisa ser adicionada como uma dependência de build dos aplicativos que usam o gráfico de calculadora.

Esse erro é detectado no momento da execução porque os gráficos de calculadora referenciam as calculadoras por nome no campo CalculatorGraphConfig::Node:calculator. Quando a biblioteca de uma calculadora é vinculada a um binário de aplicativo, a calculadora é registrada automaticamente por nome usando a macro REGISTER_CALCULATOR com a biblioteca registration.h. O REGISTER_CALCULATOR pode registrar uma calculadora com um prefixo de namespace, idêntico ao namespace C++. Nesse caso, o gráfico da calculadora também precisa usar o mesmo prefixo de namespace.

Erro de falta de memória

A memória esgotada pode ser um sintoma de muitos pacotes acumulados em um gráfico do MediaPipe em execução. Isso pode acontecer por vários motivos, como:

  1. Algumas calculadoras no gráfico simplesmente não conseguem acompanhar a chegada de pacotes de um fluxo de entrada em tempo real, como uma câmera de vídeo.
  2. Algumas calculadoras estão esperando pacotes que nunca vão chegar.

Para o problema (1), talvez seja necessário descartar alguns pacotes antigos para processar os mais recentes. Para algumas dicas, consulte: How to process realtime input streams.

No problema (2), pode ser que um fluxo de entrada esteja sem pacotes por algum motivo. Um dispositivo ou uma calculadora pode estar configurado incorretamente ou produzir pacotes apenas esporadicamente. Isso pode fazer com que as calculadoras downstream aguardem muitos pacotes que nunca chegarão, o que, por sua vez, faz com que os pacotes se acumulem em alguns dos streams de entrada. O MediaPipe resolve esse tipo de problema usando "limites de carimbo de data/hora". Para algumas dicas, consulte: How to process realtime input streams.

A configuração do MediaPipe CalculatorGraphConfig::max_queue_size limita o número de pacotes enfileirados em qualquer stream de entrada, restringindo as entradas para o gráfico. Para streams de entrada em tempo real, o número de pacotes enfileirados em um stream de entrada quase sempre precisa ser zero ou um. Caso contrário, você vai receber a seguinte mensagem de aviso:

Resolved a deadlock by increasing max_queue_size of input stream

Além disso, a configuração CalculatorGraphConfig::report_deadlock pode ser definida para causar a falha na execução do gráfico e mostrar o deadlock como um erro, de modo que max_queue_size funcione como um limite de uso de memória.

O gráfico trava

Muitos aplicativos chamam CalculatorGraph::CloseAllPacketSources e CalculatorGraph::WaitUntilDone para finalizar ou suspender a execução de um gráfico MediaPipe. O objetivo aqui é permitir que todas as calculadoras ou pacotes pendentes concluam o processamento e, em seguida, desliguem o gráfico. Se tudo correr bem, cada stream no gráfico vai alcançar Timestamp::Done, e cada calculadora vai chegar a CalculatorBase::Close, e então CalculatorGraph::WaitUntilDone será concluído.

Se algumas calculadoras ou streams não conseguirem alcançar o estado Timestamp::Done ou CalculatorBase::Close, o método CalculatorGraph::Cancel poderá ser chamado para encerrar a execução do gráfico sem esperar que todas as calculadoras e pacotes pendentes sejam concluídos.

O tempo de saída é desigual

Alguns gráficos do MediaPipe em tempo real produzem uma série de frames de vídeo para visualização como um efeito de vídeo ou um diagnóstico de vídeo. Às vezes, um gráfico do MediaPipe produz esses frames em clusters, por exemplo, quando vários frames de saída são extrapolados do mesmo cluster de frames de entrada. Se as saídas forem apresentadas conforme são produzidas, alguns frames de saída serão imediatamente substituídos por frames posteriores no mesmo cluster, o que dificulta a visualização e avaliação visual dos resultados. Em casos como esse, a visualização de saída pode ser melhorada apresentando os frames em intervalos regulares em tempo real.

O MediaPipe resolve esse caso de uso mapeando carimbos de data/hora para pontos em tempo real. Cada carimbo de data/hora indica um tempo em microssegundos, e uma calculadora, como LiveClockSyncCalculator, pode atrasar a saída de pacotes para corresponder aos carimbos de data/hora. Esse tipo de calculadora ajusta o tempo das saídas para que:

  1. O tempo entre as saídas corresponde ao tempo entre os carimbos de data/hora da forma mais precisa possível.
  2. As saídas são produzidas com o menor atraso possível.

O CalculatorGraph fica atrás das entradas

Para muitos gráficos do MediaPipe em tempo real, a baixa latência é um objetivo. O MediaPipe oferece suporte ao processamento paralelo de estilo "pipelined" para iniciar o processamento de cada pacote o mais cedo possível. Normalmente, a menor latência possível é o tempo total necessário para cada calculadora ao longo de um "caminho crítico" de calculadoras sucessivas. A latência de um gráfico do MediaPipe pode ser pior do que o ideal devido a atrasos introduzidos para exibir frames em intervalos uniformes, conforme descrito em O tempo de saída é desigual.

Se algumas das calculadoras no gráfico não conseguirem acompanhar as transmissões de entrada em tempo real, a latência vai continuar aumentando, e será necessário descartar alguns pacotes de entrada. A técnica recomendada é usar os calculadores do MediaPipe projetados especificamente para esse fim, como FlowLimiterCalculator, conforme descrito em How to process realtime input streams.

Monitorar entradas da calculadora e liquidações de carimbos de data/hora

A depuração de calculadoras do MediaPipe geralmente requer um entendimento profundo do fluxo de dados e da sincronização de carimbos de data/hora. Os pacotes de entrada para calculadoras são primeiro armazenados em buffer nas filas de entrada por fluxo para serem sincronizados pelo InputStreamHandler atribuído. O job InputStreamHandler é determinar o pacote de entrada definido para um carimbo de data/hora definido, o que coloca a calculadora em um estado "pronto", seguido pelo acionamento de uma chamada Calculator::Process com o pacote determinado como entrada.

O DebugInputStreamHandler pode ser usado para rastrear pacotes de entrada e assentamentos de carimbos de data/hora em tempo real na saída LOG(INFO) do aplicativo. Ele pode ser atribuído a calculadoras específicas pelo input_stream_handler da calculadora ou globalmente pelo campo input_stream_handler do CalculatorGraphConfig.

Durante a execução do gráfico, os pacotes recebidos geram mensagens de LOG que revelam o carimbo de data/hora e o tipo do pacote, seguidos pelo estado atual de todas as filas de entrada:

[INFO] SomeCalculator: Adding packet (ts:2, type:int) to stream INPUT_B:0:input_b
[INFO] SomeCalculator: INPUT_A:0:input_a num_packets: 0 min_ts: 2
[INFO] SomeCalculator: INPUT_B:0:input_b num_packets: 1 min_ts: 2

Além disso, ele permite o monitoramento de eventos de liquidação de carimbos de data/hora (caso o DefaultInputStreamHandler seja aplicado). Isso pode ajudar a revelar um aumento inesperado de limite de carimbo de data/hora em streams de entrada, resultando em uma chamada Calculator::Process com um conjunto de entrada incompleto, resultando em pacotes vazios em streams de entrada (potencialmente necessários).

Exemplo de cenário:

node {
  calculator: "SomeCalculator"
  input_stream: "INPUT_A:a"
  input_stream: "INPUT_B:b"
  ...
}

Considere uma calculadora com duas entradas, recebendo um pacote de entrada com carimbo de data/hora 1 na stream A, seguido por um pacote de entrada com carimbo de data/hora 2 na stream B. O aumento do limite de carimbo de data/hora para 2 no fluxo B com um pacote de entrada pendente no fluxo A no carimbo de data/hora 1 aciona a chamada Calculator::Process com uma entrada incompleta definida para o carimbo de data/hora 1. Nesse caso, o DefaultInputStreamHandler gera:

[INFO] SomeCalculator: Filled input set at ts: 1 with MISSING packets in input streams: INPUT_B:0:input_b.

VLOG é seu amigo

O MediaPipe usa VLOG em muitos lugares para registrar eventos importantes para fins de depuração, sem afetar o desempenho se a geração de registros não estiver ativada.

Saiba mais sobre VLOG em abseil VLOG

Tenha em mente que a VLOG pode ser considerada spam se for ativada globalmente, por exemplo, usando a flag --v. A flag --vmodule da solução, que permite definir níveis diferentes para diferentes arquivos de origem.

Nos casos em que --v / --vmodule não podem ser usados (por exemplo, ao executar um app Android), o MediaPipe permite definir substituições de flags VLOG --v / --vmodule para fins de depuração, que são aplicadas quando CalculatorGraph é criado.

Modifica:

  • MEDIAPIPE_VLOG_V: define e fornece o valor que você fornece para --v
  • MEDIAPIPE_VLOG_VMODULE: define e fornece o valor que você fornece para --vmodule.

Para definir substituições, adicione: --copt=-DMEDIAPIPE_VLOG_VMODULE=\"*calculator*=5\"

com os padrões de módulo e os níveis de VLOG desejados (confira mais detalhes sobre --vmodule em abseil VLOG) no comando de build.

IMPORTANTE: adicionar o comando acima ao seu comando de build vai acionar a recriação de todo o binário, incluindo as dependências. Portanto, considerando que as substituições de VLOG existem apenas para fins de depuração, é mais rápido simplesmente modificar vlog_overrides.cc adicionando MEDIAPIPE_VLOG_V/VMODULE na parte de cima.

Flags sem suporte durante o build

Se você estiver usando o Clang 18 ou versões anteriores, talvez seja necessário desativar algumas otimizações do compilador no nosso back-end de CPU.

Para desativar o suporte a avxvnniint8, adicione o seguinte ao .bazelrc:

build --define=xnn_enable_avxvnniint8=false