圖表
CalculatorGraphConfig
proto 會指定模型的拓撲和功能
MediaPipe 圖表。圖表中的每個 node
都代表特定計算機或
以及指定必要的設定,例如
計算機/子圖表類型、輸入內容、輸出內容和選填欄位,例如
節點專屬選項、輸入政策和執行程式
同步處理。
CalculatorGraphConfig
還有其他幾個欄位可用於設定全域圖表層級
設定 (例如圖形執行器設定、執行緒數量和佇列大小上限
輸入串流的個別項目您可以運用幾種圖表層級設定來調整
圖表在不同平台上 (例如桌機和行動裝置) 的成效。適用對象
以行動裝置為例
將重型模型推論計算機
執行器可以提升即時應用程式的效能
會啟用執行緒位置。
下方是簡單的 CalculatorGraphConfig
範例,其中包含一系列的
直通式計算機:
# This graph named main_pass_throughcals_nosubgraph.pbtxt contains 4
# passthrough calculators.
input_stream: "in"
output_stream: "out"
node {
calculator: "PassThroughCalculator"
input_stream: "in"
output_stream: "out1"
}
node {
calculator: "PassThroughCalculator"
input_stream: "out1"
output_stream: "out2"
}
node {
calculator: "PassThroughCalculator"
input_stream: "out2"
output_stream: "out3"
}
node {
calculator: "PassThroughCalculator"
input_stream: "out3"
output_stream: "out"
}
MediaPipe 可為複雜圖表提供替代的 C++
表示法,例如機器學習管道、處理模型中繼資料和選用節點等。上圖看起來可能像這樣:
CalculatorGraphConfig BuildGraphConfig() {
Graph graph;
// Graph inputs
Stream<AnyType> in = graph.In(0).SetName("in");
auto pass_through_fn = [](Stream<AnyType> in,
Graph& graph) -> Stream<AnyType> {
auto& node = graph.AddNode("PassThroughCalculator");
in.ConnectTo(node.In(0));
return node.Out(0);
};
Stream<AnyType> out1 = pass_through_fn(in, graph);
Stream<AnyType> out2 = pass_through_fn(out1, graph);
Stream<AnyType> out3 = pass_through_fn(out2, graph);
Stream<AnyType> out4 = pass_through_fn(out3, graph);
// Graph outputs
out4.SetName("out").ConnectTo(graph.Out(0));
return graph.GetConfig();
}
詳情請參閱在 C++ 中建構圖表。
子圖表
將 CalculatorGraphConfig
模組化為子模組,協助重複使用
的觀感解決方案,MediaPipe 圖表可定義為 Subgraph
。
子圖表的公開介面由一組輸入和輸出串流組成
類似於計算機的公用介面接著,您可以將子圖表加入
CalculatorGraphConfig
,就像計算機一樣。當 MediaPipe 圖表顯示
從 CalculatorGraphConfig
載入,每個子圖表節點都會替換為
以及相應的計算機圖形因此,語意和效能
就會對應至相應的計算機圖形。
以下範例說明如何建立名為 TwoPassThroughSubgraph
的子圖表。
定義子圖表。
# This subgraph is defined in two_pass_through_subgraph.pbtxt # and is registered as "TwoPassThroughSubgraph" type: "TwoPassThroughSubgraph" input_stream: "out1" output_stream: "out3" node { calculator: "PassThroughCalculator" input_stream: "out1" output_stream: "out2" } node { calculator: "PassThroughCalculator" input_stream: "out2" output_stream: "out3" }
子圖表的公用介麵包含:
- 繪製輸入串流的圖形
- 繪製輸出串流的圖形
- 繪製輸入端封包的圖形
- 繪製側邊封包的圖表
使用 BUILD 規則
mediapipe_simple_subgraph
註冊子圖表。register_as
參數會定義新子圖表的元件名稱。# Small section of BUILD file for registering the "TwoPassThroughSubgraph" # subgraph for use by main graph main_pass_throughcals.pbtxt mediapipe_simple_subgraph( name = "twopassthrough_subgraph", graph = "twopassthrough_subgraph.pbtxt", register_as = "TwoPassThroughSubgraph", deps = [ "//mediapipe/calculators/core:pass_through_calculator", "//mediapipe/framework:calculator_graph", ], )
使用主圖中的子圖表。
# This main graph is defined in main_pass_throughcals.pbtxt # using subgraph called "TwoPassThroughSubgraph" input_stream: "in" node { calculator: "PassThroughCalculator" input_stream: "in" output_stream: "out1" } node { calculator: "TwoPassThroughSubgraph" input_stream: "out1" output_stream: "out3" } node { calculator: "PassThroughCalculator" input_stream: "out3" output_stream: "out4" }
圖表選項
您可以指定「圖表選項」MediaPipe 圖表的 protobuf
與 Calculator Options
類似
為 MediaPipe 計算機指定的 protobuf。這些「圖表選項」可以是
就會指定叫用圖表的位置,用來填入計算機選項及
子圖表選項
在 CalculatorGraphConfig
中,您可以指定子圖表的圖表選項
與計算機選項完全相同,如下所示:
node {
calculator: "FlowLimiterCalculator"
input_stream: "image"
output_stream: "throttled_image"
node_options: {
[type.googleapis.com/mediapipe.FlowLimiterCalculatorOptions] {
max_in_flight: 1
}
}
}
node {
calculator: "FaceDetectionSubgraph"
input_stream: "IMAGE:throttled_image"
node_options: {
[type.googleapis.com/mediapipe.FaceDetectionOptions] {
tensor_width: 192
tensor_height: 192
}
}
}
在 CalculatorGraphConfig
中,您可以使用圖表選項來填入資料
計算機選項,如下所示:
graph_options: {
[type.googleapis.com/mediapipe.FaceDetectionOptions] {}
}
node: {
calculator: "ImageToTensorCalculator"
input_stream: "IMAGE:image"
node_options: {
[type.googleapis.com/mediapipe.ImageToTensorCalculatorOptions] {
keep_aspect_ratio: true
border_mode: BORDER_ZERO
}
}
option_value: "output_tensor_width:options/tensor_width"
option_value: "output_tensor_height:options/tensor_height"
}
node {
calculator: "InferenceCalculator"
node_options: {
[type.googleapis.com/mediapipe.InferenceCalculatorOptions] {}
}
option_value: "delegate:options/delegate"
option_value: "model_path:options/model_path"
}
在本範例中,FaceDetectionSubgraph
接受圖表選項 protobuf
FaceDetectionOptions
。FaceDetectionOptions
是用來定義部分欄位
計算機選項 ImageToTensorCalculatorOptions
和部分欄位中的值
子圖表選項 InferenceCalculatorOptions
中的值。欄位值
是使用 option_value:
語法來定義
CalculatorGraphConfig::Node
protobuf 中的欄位 node_options:
和
option_value:
一起定義計算機的選項值,例如
ImageToTensorCalculator
。node_options:
欄位會定義一組常值
常數值。每個 option_value:
欄位
會定義一個通訊協定緩衝區欄位的值
圖表,特別是來自資料集內圖表選項的欄位值
圖表。在上述範例中,option_value:
"output_tensor_width:options/tensor_width"
定義欄位
使用 ImageToTensorCalculatorOptions.output_tensor_width
的值做為
FaceDetectionOptions.tensor_width
。
option_value:
的語法與 input_stream:
的語法類似。
語法為 option_value: "LHS:RHS"
LHS 會找出計算機選項
欄位,RHS 則識別圖表選項欄位。具體來說
而 RHS 則包含一系列的 protobuf 欄位名稱
protobuf 訊息和欄位,以「/」分隔。這就是所謂的「ProtoPath」
語法。LHS 或 RHS 參照的巢狀訊息必須已
才能完全依照
option_value:
。
時序更迭
依據預設,MediaPipe 要求計算機圖形必須為循環圖形和治療週期 顯示為錯誤如果圖表涉及月經週期,那麼循環機制必須 加註。本頁說明如何完成這項作業。
注意:目前做法仍在實驗階段,因此可能會有變動。不客氣 提供意見回饋。
請在以下位置使用 CalculatorGraphTest.Cycle
單元測試:
以 mediapipe/framework/calculator_graph_test.cc
做為範例程式碼。如下所示
測試中的循環圖加法器的 sum
輸出內容是
整數來源計算工具產生的整數。
這個簡單的圖表呈現了支援循環圖的所有問題。
返回邊緣註解
每個週期的邊緣都必須加註為後邊緣。這樣一來, 移除所有返回邊緣後,MediaPipe 的拓撲排序。
一般來說,選取後邊緣的方法有很多種。哪些邊緣所標示的邊緣 因為返回邊緣會影響哪些節點被視為上游,以及哪些節點 這會影響 MediaPipe 指派的優先順序 節點。
舉例來說,CalculatorGraphTest.Cycle
測試會將 old_sum
邊緣標示為
因此 Delay 節點會被視為其下游節點
且優先順序較高或者,您也可以將 sum
若是後邊緣,延遲時間節點就會是
視為附加器節點的上游節點,優先順序較低
初始封包
為了讓新增器計算器在整數中的第一個整數為執行時
收到來源時,我們需要使用值為 0 且具有相同值的初始封包
old_sum
輸入串流上的時間戳記,這個初始封包
應使用 Open()
方法的延遲計算工具輸出。
迴圈延遲
每個迴圈都應該產生延遲,以便對齊先前的 sum
輸出內容
整數值。這也適用於延遲節點。所以延遲節點
瞭解有關整數來源計算機的時間戳記:
第一項輸出內容的時間戳記。
連續輸出內容之間的時間戳記差異。
我們打算新增僅適用於封包的其他排程政策 排序並忽略封包時間戳記,即可排除造成的不便。
在單一輸入串流完成時提前終止計算機
根據預設,在下列情況下,MediaPipe 會呼叫非來源計算機的 Close()
方法
所有輸入串流都已完成在範例中,我們想停止
加上器節點。方法是透過
使用替代輸入串流處理常式設定 adder 節點
EarlyCloseInputStreamHandler
。
相關原始碼
延遲計算機
請注意 Open()
中輸出初始封包的程式碼,以及
Process()
,這會增加輸入封包的 (單位) 延遲時間。如前所述
延遲節點會假設其輸出串流與含有
封包時間戳記 0、1、2、3...
class UnitDelayCalculator : public Calculator {
public:
static absl::Status FillExpectations(
const CalculatorOptions& extendable_options, PacketTypeSet* inputs,
PacketTypeSet* outputs, PacketTypeSet* input_side_packets) {
inputs->Index(0)->Set<int>("An integer.");
outputs->Index(0)->Set<int>("The input delayed by one time unit.");
return absl::OkStatus();
}
absl::Status Open() final {
Output()->Add(new int(0), Timestamp(0));
return absl::OkStatus();
}
absl::Status Process() final {
const Packet& packet = Input()->Value();
Output()->AddPacket(packet.At(packet.Timestamp().NextAllowedInStream()));
return absl::OkStatus();
}
};
圖譜設定
請留意 back_edge
註解和替代 input_stream_handler
。
node {
calculator: 'GlobalCountSourceCalculator'
input_side_packet: 'global_counter'
output_stream: 'integers'
}
node {
calculator: 'IntAdderCalculator'
input_stream: 'integers'
input_stream: 'old_sum'
input_stream_info: {
tag_index: ':1' # 'old_sum'
back_edge: true
}
output_stream: 'sum'
input_stream_handler {
input_stream_handler: 'EarlyCloseInputStreamHandler'
}
}
node {
calculator: 'UnitDelayCalculator'
input_stream: 'sum'
output_stream: 'old_sum'
}