グラフ
CalculatorGraphConfig
プロトコルは、デバイスのトポロジと機能を指定します。
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++
表現(ML パイプライン、モデル メタデータの処理、オプションのノードなど)を提供します。上記のグラフは次のようになります。
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
プロトコル バッファで、フィールド node_options:
と
option_value:
は一緒に、次のような計算ツールのオプション値を定義します。
ImageToTensorCalculator
。node_options:
フィールドは、一連のリテラルを定義します。
テキスト protobuf 構文を使用して定数値を生成します。各 option_value:
フィールド
含まれる 1 つの情報を使用して、1 つの protobuf フィールドの値を定義
特に包含のグラフ オプションのフィールドの値から
表示されます。上記の例では、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 はグラフ オプション フィールドを示します。具体的には LHS は
RHS は、ネストされたフィールドを識別する、一連の protobuf フィールド名から構成される
「/」で区切られた protobuf メッセージとフィールド。これは「ProtoPath」と呼ばれ
説明します。LHS または RHS で参照されるネストされたメッセージは、
含まれる protobuf に定義されている文字列を
option_value:
。
季節と時間
デフォルトでは、MediaPipe は計算機グラフが非巡回であることを求め、サイクルを扱います。 エラーとして表示されます。グラフにサイクルがある場合、サイクルは アノテーションが付けられます。このページでは、その方法について説明します。
注: 現在のアプローチは試験運用版であり、変更される可能性があります。歓迎 フィードバックをお寄せください。
CalculatorGraphTest.Cycle
単体テストを使用してください
mediapipe/framework/calculator_graph_test.cc
をサンプルコードとして使用。以下は、
循環グラフが作成されます加算器の sum
出力は、
整数ソース計算ツールで生成された整数。
このシンプルなグラフは、巡回グラフのサポートにおけるすべての問題を示しています。
バックエッジのアノテーション
各サイクルのエッジには、バックエッジとしてアノテーションを付ける必要があります。これにより、 MediaPipe のトポロジソートが機能するように、後端をすべて削除しました。
通常、後端を選択するには複数の方法があります。どのエッジがマークされますか バックエンド エッジがどのノードをアップストリームとみなすか、どのノードをアップストリーム これは下流とみなされるため、MediaPipe が割り当てる優先度に影響します。 ノードにルーティングされます。
たとえば、CalculatorGraphTest.Cycle
テストでは、old_sum
のエッジが
遅延ノードは加算器のダウンストリーム ノードと
より優先度が高くなります。または、sum
を
バックエッジとして遅延ノードに入力され、
アップストリーム ノードと見なされ、より低い優先度が与えられます。
最初のパケット
整数の最初の整数が入力された時点で加算器計算ツールを実行可能にするには、
到着したときに、値が 0、かつ同じ値を持つ最初のパケットが必要です。
加算器への old_sum
入力ストリームのタイムスタンプ。この最初のパケットは、
Open()
メソッドの遅延計算ツールで出力する必要があります。
ループ再生の遅延
各ループで、前の sum
出力を次の出力に合わせて調整するために遅延が発生します。
使用します。これは遅延ノードによっても行われます。そのため遅延ノードは
整数ソース計算ツールのタイムスタンプについて、以下を把握してください。
最初の出力のタイムスタンプ。
連続する出力間のタイムスタンプのデルタ。
パケットのみを考慮した代替スケジューリング ポリシーを追加する予定です。 パケットのタイムスタンプが無視されるため、この不便さがなくなります。
1 つの入力ストリームが終了したときの電卓の早期終了
デフォルトでは、MediaPipe は、次の場合にソース以外の計算ツールの Close()
メソッドを呼び出します。
すべての入力ストリームが完了しましたサンプルのグラフでは、2 つ目の Pod に
加算器ノードを返すことができます。これを実現するのが
代替入力ストリーム ハンドラで加算器ノードを構成する
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'
}