단순히 문서 해석과 궁금한 점을 덧붙여 작성하였습니다.
시리즈는 아래와 같습니다.
Framework Concepts
Framework Concepts - Graphs
GraphConfig
GraphConfig은 Mediapipe graph의 topology와 기능성에 대해 설명하는 명세서입니다. 명세서에서, 그래프의 노드는 특정한 calculator의 인스턴스로 나타납니다. 모든 필요한 노드의 설정들은, 타입같은 경우, inputs과 outpus은 명세서에서 설명되어야만 합니다. 노드의 설명은 또한 몇몇의 options fields를 포함합니다, node-specific options, input policy와 executor와 같은 것입니다. Synchronization에서 논의됩니다.
GraphConfig는 예를 들어 graph executor configs, 스레드의 개수, 그리고 input stream의 최대 큐 사이즈와 같은 global graph-level settings를 설정하기 위한 몇몇의 다른 필드를 가지고 있습니다. 몇몇의 global-level 세팅들은 다른 플랫폼(예를들어 데스크탑과 모바일)에서 그래프의 성능을 조정하는데에 유용합니다. 일례로, 모바일에서, 각각의 executor에 무거운 model-inference calculator를 붙이는 것은 thread locality를 가능하게 하기 때문에 실시간 애플리케이션의 성능을 향상시킬 수 있습니다.
아래는 우리가 calculators에서 거쳐왔던 간단한 GraphConfig 예제입니다.
# This graph named main_pass_throughcals_nosubgraph.pbtxt contains 4
# passthrough calculators.
input_stream: "in"
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: "out4"
}
Subgraph
CalculatorGraphConfig를 sub-modules 안으로 모듈화하기 위해 그리고 perception solutions의 재사용을 지원하기 위해, Mediapipe graph는 Subgraph 로써 정의될 수 있습니다. subgraph의 public interface는 calculator의 public interface와 유사하게 input과 output의 집합으로 구성되어있습니다. subgraph는 그래서 calculator 로써 calculatorGraphConfig 안에 포함될 수 있습니다. MediaPipe graph가 CalculatorGraphConfig로부터 로드되어질 때, 각 subgraph node는 calculators의 그래프에 상응함으로써 대체됩니다. 결과적으로, subgraph의 의미와 성능은 calculators의 그래프와 해당함으로 같습니다.
아래는 TwoPassThroughSubgraph라고 불리는 subgraph를 생성하는 방법의 예제입니다.
1. Subgraph를 정의하기
# 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"
}
subgraph의 public interface 구성:
- Graph input streams
- Grph output streams
- Graph input side packets
- Graph output side packets
2. BUILD 규칙 mediapipe_simple_subgraph 를 사용함으로 subgraph를 등록합니다. register_as 파라미터는 새로운 subgraph를 위한 컴포넌트 이름을 정의합니다.
# 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",
],
)
3. 메인 그래프 안에서 subgraph를 사용하세요.
# 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"
}
Cycles
기본적으로, Mediapipe는 비순환적이게 하기 위해 그리고 에러로써 그래프 안의 사이클을 다루기 위해 calculator graphs를 요청합니다. 만약 그래프가 사이클이 있게 된다면, 그 사이클은 graph config에 표시되어있어야 합니다. 이 페이지는 어떻게 그것을 하는지에 대해 설명합니다.
NOTE: 현재 접근은 실험적이고 바뀔 수 있는 주제입니다. 우리는 당신의 피드백을 환영합니다.
샘플 코드로써 mediapipe/framework/calculator_graph_test.cc 안의 CalculatorGraphTest.Cycle 유닛 테스트를 사용해주세요. 아래 보여지는 것은 테스트에서 순환적인 그래프입니다. adder의 sum output 는 integer source calculator 에 의해 생성된 integers의 합입니다.
이 간단한 그래프는 순환 그래프를 지원하는 것 안에서 모든 이슈를 표현합니다.
Back Edge Annotation
우리는 back edge로써 알려진 각 사이클 안에서의 edge를 요청합니다. 이것은 모든 back edges를 삭제한 이후에 Mediapipe의 topological sort가 동작할 수 있도록 합니다.
대체적으로 back edges 를 선택하는 많은 방법이 있습니다. 어떤 edges 가 back edges 로써 선택되었는지가 어떤 노드가 upstream으로써 여겨지고 어떤 노드가 downstream으로써 여겨지는지 대해 영향을 끼칩니다. 이것은 Medipipe가 노드에 할당하는 우선 순위에 영향을 미칩니다.
예를 들어, CalculatorGraphTest,Cycle 테스트는 back edge로써 old_sum edge 를 나타내고, 그래서 Delay node 는 adder node의 downstream node 으로써 여겨지고 높은 우선순위를 얻게 됩니다. 대신에, 우리는 back edge로써 delay node를 위한 sum input을 표시할 수 있습니다, 이 상황에서 delay node는 adder node의 upstream node 로써 여겨지고, 낮은 우선순위를 얻게 됩니다.
Initial Packet
integer source의 도착으로부터 첫번째 integer가 실행할 수 있는 adder calculator를 위해, 우리는 값이 0 이고 같은 timestamp를 가지고, adder를 위해 old_sum input stream에서의 initial packet이 필요합니다. 이 initial packet은 Open() 메소드 안에서 delay calculator 에 의해 output이 됩니다.
Delay in a Loop
각 루프는 다음 정수형 input과 이전의 sum output이 맞춰지는 것의 연기를 초래할 수 있다. 이것은 또한 delay node에 의해 끝난다. 그래서 delay node는 integer source calculator의 timestamp에 대해 알 필요가 있다:
- 첫번째 output의 timestamp
- 연속되는 outputs 사이의 timestamp delta
우리는 오직 불편함을 줄이도록 packet의 순서와 packet의 timestamps를 무시하는 것에만 신경쓰는 대체할 수 있는 스케줄링 정책을 추가하는 것을 계획한다.
Early Termination of a Calculator When One Input Stream is Done
기본적으로, Mediapipe는 그것의 모든 input streas가 끝날 때 non-source calculator의 Close() 메소드를 호출합니다. 이 예제 그래프에서, 우리는 adder node가 가능한 빨리 integer source가 끝났을 때 멈추기를 원합니다. 이것은 EarlyCloseInputStreamHandler, 대체가능한 input stream handler와 adder node를 설정함으로써 성취할 수 있습니다.
Relevant Source Code
DELAY CALCULATOR
initial packet의 outputs 인 Open() 안의 코드와 input packets 에 (단위) 지연을 추가하는 Process() 안의 코드를 확인하세요. 위에 확인하였듯이, 이 delay node는 그것의 output stream이 packet timestamps 0, 1, 2, 3, ... 과 input stream의 옆에서 사용됩니다.
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();
}
};
GRAPH CONFIG
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'
}
References
https://google.github.io/mediapipe/framework_concepts/graphs.html
'개발 > mediapipe' 카테고리의 다른 글
python - face mesh (0) | 2022.03.05 |
---|---|
mediapipe hello world error on m1 (0) | 2022.03.03 |
Framework Concepts - Calculators (0) | 2022.03.03 |
mediapipe install on iOS (2) | 2022.03.03 |
Windows 에서 media pipe 설치하기 (0) | 2022.03.01 |