رسم بياني للدالة
يحدد النموذج الأوّلي 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++
بديلاً للرسومات البيانية المعقّدة (مثل مسارات تعلُّم الآلة، معالجة البيانات الوصفية للنماذج، العُقد الاختيارية، وما إلى ذلك). قد يبدو الرسم البياني أعلاه كالتالي:
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
تشبه Calculator Options
تم تحديد النموذج الأولي للآلة الحاسبة MediaPipe. هذه "خيارات الرسم البياني" يمكن أن تكون
المحددة حيث يتم استدعاء الرسم البياني، وتستخدم لتعبئة خيارات الآلة الحاسبة
الخيارات الفرعية ضمن الرسم البياني.
في 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
خيار النموذج الأوّلي لخيار الرسم البياني.
FaceDetectionOptions
يُستخدم FaceDetectionOptions
لتحديد حقل ما
القيم في خيارات الآلة الحاسبة ImageToTensorCalculatorOptions
وبعض الحقول
القيم في خيارات الرسم البياني الفرعي InferenceCalculatorOptions
. قيم الحقول
باستخدام بنية option_value:
.
في النموذج الأولي CalculatorGraphConfig::Node
، يكون الحقلان node_options:
تحدِّد option_value:
معًا قيم الخيارات للآلة الحاسبة، مثل
ImageToTensorCalculator
يحدّد الحقل node_options:
مجموعة من القيم الحرفية
القيم الثابتة باستخدام بناء جملة نموذج النص الأوّلي. كل حقل option_value:
تحدد قيمة حقل واحد من حقول 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 من سلسلة من أسماء حقول النموذج الأولي تحدد
رسائل النموذج الأوّلي والحقول مفصولة بعلامة "/". وهذا يُعرف باسم "ProtoPath"
وبناء الجملة. يجب أن تكون الرسائل المتداخلة المشار إليها في LHS أو RHS
في النموذج الأوّلي المُرفَق من أجل اجتيازه باستخدام
option_value:
فترات زمنية
يتطلب MediaPipe بشكل افتراضي أن تكون الرسوم البيانية للآلة الحاسبة دائرية وتعالج الدورات. في الرسم البياني على أنها أخطاء. إذا كان من المفترض أن يتضمن الرسم البياني دورات، التعليق التوضيحي في تهيئة الرسم البياني. توضّح هذه الصفحة كيفية إجراء ذلك.
ملاحظة: النهج الحالي تجريبي وخاضع للتغيير. نرحّب بالترحيب ملاحظاتك.
يُرجى استخدام اختبار وحدة CalculatorGraphTest.Cycle
في
mediapipe/framework/calculator_graph_test.cc
كنموذج للرمز. الموضح أدناه هو
الرسم البياني الدوري في الاختبار. ناتج sum
للإضافة هو مجموع
الأعداد الصحيحة التي يتم إنشاؤها بواسطة الآلة الحاسبة لمصدر الأعداد الصحيحة.
يوضح هذا الرسم البياني البسيط جميع المشكلات التي قد تظهر في دعم الرسومات البيانية الدورية.
التعليق التوضيحي على الحافة الخلفية
نحن نطلب أن تتم إضافة تعليقات توضيحية إلى حافة في كل دورة باعتبارها حافة خلفية. هذا يسمح يعمل الفرز الطبولوجي في MediaPipe، بعد إزالة جميع الحواف الخلفية.
هناك عادةً العديد من الطرق لتحديد الحواف الخلفية. الحواف المميزة حيث تؤثر الحواف الخلفية في العُقد التي تعتبر لأعلى والعُقد باعتباره مرحلة وصول، وهو ما يؤثر بدوره في الأولويات التي تعينها MediaPipe إلى العقد.
على سبيل المثال، يشير اختبار CalculatorGraphTest.Cycle
إلى حافة old_sum
على أنّها علامة
الحافة الخلفية، وبالتالي تعتبر عقدة التأخير كعقدة أسفل الصفحة للإضافة
في الجزء العلوي وإعطائها أولوية أعلى. بدلاً من ذلك، يمكننا وضع علامة على sum
المدخل إلى عقدة التأخير باعتبارها الحافة الخلفية، وفي هذه الحالة ستكون عقدة التأخير
يعتبر بمثابة عقدة الجزء الرئيسي من عقدة adder ومنحها أولوية أقل.
الحزمة الأولية
لكي تكون الآلة الحاسبة للإضافة قابلة للتشغيل عندما يكون أول عدد صحيح من العدد الصحيح
المصدر، فإننا نحتاج إلى حزمة أولية ذات قيمة 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'
}