疑難排解

缺少 Python 二進位檔路徑

錯誤訊息:

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

通常表示 Bazel 無法找到本機 Python 二進位檔。如要解決這個問題,請先找出 Python 二進位檔的位置,然後將 --action_env PYTHON_BIN_PATH=<path to python binary> 新增至 Bazel 指令。舉例來說,您可以使用下列指令切換至使用系統預設的 python3 二進位檔:

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

缺少必要的 Python 套件

錯誤訊息:

ImportError: No module named numpy
Is numpy installed?

通常表示未安裝特定 Python 套件。請根據 Python 二進位檔版本執行 pip installpip3 install,以便安裝這些套件。

無法擷取遠端依附元件存放區

錯誤訊息:

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)

通常表示 Bazel 無法下載 MediaPipe 所需的必要依附元件存放區。MediaPipe 有幾個由 Google 網站代管的依附元件存放區。在某些地區,您可能需要設定網路 Proxy 或使用 VPN 才能存取這些資源。您可能還需要將 --host_jvm_args "-DsocksProxyHost=<ip address> -DsocksProxyPort=<port number>" 附加到 Bazel 指令。詳情請參閱這個 GitHub 問題

如果您認為這不是網路問題,另一個可能原因是部分資源暫時無法使用,請執行 bazel clean --expunge,稍後再試一次。如果還是無法解決問題,請在 GitHub 回報問題,並附上詳細的錯誤訊息。

MediaPipe OpenCV 設定不正確

錯誤訊息:

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

通常表示 OpenCV 未正確設定 MediaPipe。請參閱「安裝」中的「安裝 OpenCV 和 FFmpeg」部分,瞭解如何針對本機 opencv 程式庫修改 MediaPipe 的 WORKSPACE 和 linux_opencv/macos_opencv/windows_opencv.BUILD 檔案。這個 GitHub 問題也許也有幫助。

Python pip 安裝失敗

錯誤訊息:

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

執行 pip install mediapipe 後,通常表示系統中沒有合格的 MediaPipe Python。請注意,MediaPipe Python PyPI 正式支援以下作業系統的 64 位元 Python 3.7 至 3.10 版本:

  • x86_64 Linux
  • x86_64 macOS 10.15 以上版本
  • amd64 Windows

如果目前支援的作業系統仍出現這個錯誤,請確認 Python 和 pip 二進位檔都是適用於 Python 3.7 到 3.10 的版本。否則,請考慮按照這裡的操作說明,在本機環境中建構 MediaPipe Python 套件。

Python DLL 在 Windows 上載入失敗

錯誤訊息:

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

通常表示本機 Windows 系統缺少 Visual C++ 可重新發布的套件和/或 Visual C++ 執行階段 DLL。如要解決這個問題,請安裝官方的 vc_redist.x64.exe,或執行以下命令來安裝「msvc-runtime」Python 套件:

$ python -m pip install msvc-runtime

請注意,「msvc-runtime」Python 套件並非由 Microsoft 發布或維護。

找不到原生方法

錯誤訊息:

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

通常表示所需的原生資料庫 (例如 /libwickjni.so) 未載入或未納入應用程式的依附元件,或是因某些原因而無法找到。請注意,Java 要求每個原生資料庫都必須使用 System.loadLibrary 函式明確載入。

找不到已註冊的計算機

錯誤訊息:

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

通常表示 OurNewCalculatorCalculatorGraphConfig 中以名稱參照,但 OurNewCalculator 的程式庫目標尚未連結至應用程式二進位檔。將新計算機新增至計算機圖表時,該計算機也必須新增為使用計算機圖表的應用程式的建構依附元件。

這個錯誤會在執行階段偵測到,因為計算機圖表會透過 CalculatorGraphConfig::Node:calculator 欄位以名稱參照計算機。當計算機的程式庫連結至應用程式二進位檔時,系統會使用 registration.h 程式庫,透過 REGISTER_CALCULATOR 巨集自動以名稱註冊計算機。請注意,REGISTER_CALCULATOR 可以使用命名空間前置字串註冊計算機,這與其 C++ 命名空間相同。在這種情況下,計算機圖表也必須使用相同的命名空間前置字元。

記憶體不足錯誤

耗盡記憶體的症狀可能是在執行中的 MediaPipe 圖表中累積太多封包。這可能由許多因素造成,例如:

  1. 圖表中的一些計算機根本無法跟上來自攝影機等即時輸入串流的封包。
  2. 部分計算機正在等待永遠不會送達的封包。

針對問題 (1),您可能需要捨棄舊封包中的部分舊封包,以便處理較新的封包。如需一些提示,請參閱:How to process realtime input streams

針對問題 (2),可能是某個輸入串流因某些原因而缺少封包。裝置或計算機可能設定錯誤,或只偶爾產生封包。這可能會導致下游計算機等待許多永遠不會抵達的封包,進而導致封包在部分輸入串流中累積。MediaPipe 會使用「時間戳記邊界」解決這類問題。如需一些提示,請參閱:How to process realtime input streams

MediaPipe 設定 CalculatorGraphConfig::max_queue_size 會限制任何輸入串流上排入佇列的封包數量,方法是限制圖表的輸入量。對於即時輸入串流,在輸入串流中排隊的封包數量幾乎總是零或一。如果不是這種情況,您可能會看到下列警告訊息:

Resolved a deadlock by increasing max_queue_size of input stream

此外,您也可以設定 CalculatorGraphConfig::report_deadlock,讓圖表執行作業失敗,並將死結顯示為錯誤,讓 max_queue_size 做為記憶體用量限制。

圖表停滯

許多應用程式會呼叫 CalculatorGraph::CloseAllPacketSourcesCalculatorGraph::WaitUntilDone,以便完成或暫停執行 MediaPipe 圖表。這裡的目標是讓所有待處理的計算器或封包完成處理,然後關閉圖表。如果一切順利,圖表中的每個串流都會到達 Timestamp::Done,每個計算機都會到達 CalculatorBase::Close,然後 CalculatorGraph::WaitUntilDone 就會順利完成。

如果某些計算機或串流無法達到狀態 Timestamp::DoneCalculatorBase::Close,則可以呼叫 CalculatorGraph::Cancel 方法來終止圖表執行作業,而不需要等待所有待處理的計算機和封包完成。

輸出時間不均勻

部分即時 MediaPipe 圖表會產生一系列的影片影格,可做為影片效果或影片診斷工具。有時,MediaPipe 圖表會在叢集中產生這些影格,例如從相同的輸入影格叢集推算出多個輸出影格。如果輸出內容會在產生時顯示,某些輸出影格會立即遭到同一個叢集中的後續影格取代,導致結果難以以視覺方式查看和評估。在這種情況下,您可以即時以均勻間隔呈現影格,改善輸出影像可視化效果。

MediaPipe 會將時間戳記對應至即時點,以解決這個用途。每個時間戳記都會以微秒表示時間,而 LiveClockSyncCalculator 等計算機可延遲資料包的輸出,以便與時間戳記相符。這類計算機會調整輸出時間,以便:

  1. 輸出內容之間的時間會盡可能與時間戳記之間的時間相符。
  2. 輸出內容會以最短的延遲時間產生。

CalculatorGraph 落後於輸入

對於許多即時 MediaPipe 圖表來說,低延遲是目標。MediaPipe 支援「管道」式平行處理,以便盡早開始處理每個封包。通常,最短的延遲時間就是沿著「關鍵路徑」的連續計算機,由每個計算機所需的總時間。由於顯示影格會在等間隔時間內出現延遲,因此 MediaPipe 圖表的延遲時間可能會比理想情況更糟,如「輸出時間不均勻」一節所述。

如果圖表中的部分計算機無法與即時輸入串流保持同步,延遲時間就會持續增加,因此必須捨棄部分輸入封包。建議使用專為此用途而設計的 MediaPipe 計算器,例如 FlowLimiterCalculator,如 How to process realtime input streams 所述。

監控計算機輸入內容和時間戳記結算

偵錯 MediaPipe 計算機通常需要深入瞭解資料流程和時間戳記同步處理。計算機收到的傳入封包會先在每個串流的輸入佇列中緩衝,以便由指派的 InputStreamHandler 同步處理。InputStreamHandler 的工作是判斷已定時刻的輸入封包集,這會將計算機置於「就緒」狀態,接著以已判斷的封包集做為輸入內容,觸發 Calculator::Process 呼叫。

DebugInputStreamHandler 可用於在應用程式的 LOG(INFO) 輸出內容中,即時追蹤傳入的封包和時間戳記。您可以透過 Calculator 的 input_stream_handler 或全域圖表,將其指派給特定計算機或 CalculatorGraphConfig 的 input_stream_handler 欄位。

在圖表執行期間,傳入的封包會產生 LOG 訊息,其中會顯示封包的時間戳記和類型,以及所有輸入佇列的目前狀態:

[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

此外,這項功能還可監控時間戳記結算事件 (如果已套用 DefaultInputStreamHandler)。這有助於揭露輸入串流的時間戳記邊界意外增加,導致 Calculator::Process 呼叫含有不完整的輸入集,進而導致 (可能必要的) 輸入串流出現空白封包。

情境範例:

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

假設有一個有兩個輸入值的計算機,在串流 A 上接收時間戳記為 1 的傳入封包,接著在串流 B 上接收時間戳記為 2 的輸入封包。在時間戳記 1 時,串流 A 上有待處理的輸入封包,因此串流 B 的時間戳記上限增加為 2,這會觸發 Calculator::Process 呼叫,並提供時間戳記 1 的輸入集合。在這種情況下,DefaultInputStreamHandler 會輸出以下內容:

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

VLOG 是你的好幫手

MediaPipe 會在許多地方使用 VLOG 記錄重要事件,以利偵錯,但如果未啟用記錄功能,則不會影響效能。

如要進一步瞭解 VLOG,請前往 abseil VLOG

請注意,如果您在全球啟用 VLOG (例如使用 --v 旗標),可能會造成垃圾訊息。解決方案 --vmodule 標記,可讓您為不同的來源檔案設定不同的層級。

如果無法使用 --v / --vmodule (例如執行 Android 應用程式),MediaPipe 可設定 VLOG --v / --vmodule 旗標覆寫值,用於偵錯,並在建立 CalculatorGraph 時套用。

覆寫值:

  • MEDIAPIPE_VLOG_V:定義並提供您為 --v 提供的值
  • MEDIAPIPE_VLOG_VMODULE:定義並提供您為 --vmodule 提供的值

您可以透過新增下列項目來設定覆寫值: --copt=-DMEDIAPIPE_VLOG_VMODULE=\"*calculator*=5\"

並將所需的模組模式和 VLOG 層級 (請參閱 abseil VLOG 中的 --vmodule 詳細資訊) 加入建構指令。

重要事項:請注意,將上述內容加入建構指令會觸發整個二進位檔 (包括依附元件) 的重建作業。因此,考量 VLOG 覆寫值只用於偵錯,因此直接修改 vlog_overrides.cc 並在最上方新增 MEDIAPIPE_VLOG_V/VMODULE 會更快速。

建構期間不支援的旗標

如果您使用的是 Clang 18 或更舊版本,可能需要在 CPU 後端停用某些編譯器最佳化功能。

如要停用 avxvnniint8 支援功能,請在 .bazelrc 中新增以下內容:

build --define=xnn_enable_avxvnniint8=false