LeRobot documentation

خط أنابيب الترميز

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

خط أنابيب الترميز

lerobot-annotate يراقب فيديو كل حلقة باستخدام نموذج رؤية ولغة (VLM) ويكتب تعليقات بلغة طبيعية مرة أخرى في مجموعة البيانات الخاصة بك. يملأ العمودين اللغويين من صفحة Language Columns and Recipes — language_persistent وlanguage_events — مباشرةً في data/chunk-*/file-*.parquet.

باختصار: وجّهه إلى مجموعة بيانات LeRobot، وسيضيف مهام فرعية، وخططاً، وذاكرةً، وتعليقات، وكلاماً، وأسئلةً وأجوبةً بصرية يمكن تدريب سياسة عليها.

كيف تتكامل الأجزاء

  your dataset                  lerobot-annotate
  (LeRobotDataset v3.0)
        │
        ▼
  ┌─────────────────────────────────────────────────────┐
  │                    read episodes                     │
  └──────────────────────────┬──────────────────────────┘
                             │
        ┌────────────────────┼────────────────────┐
        ▼                    ▼                     ▼
  ┌──────────┐      ┌───────────────┐        ┌──────────┐       one shared Qwen-VL
  │   plan   │      │ interjections │        │   vqa    │  ◀──   server (vLLM, OpenAI
  └────┬─────┘      └───────┬───────┘        └────┬─────┘        API) drives all three
       └────────────────────┼─────────────────────┘
                            │   each module stages raw JSONL
                            ▼   into .annotate_staging/
                  ┌─────────────────┐
                  │    validator    │  ◀──  checks everything
                  └────────┬────────┘
                           ▼
                  ┌─────────────────┐
                  │     writer      │
                  └────────┬────────┘
                           ▼
              data/chunk-*/file-*.parquet
              (+ meta/info.json tools)

تتواصل ثلاثة وحدات (plan، interjections، vqa) جميعها مع نموذج VLM مشترك واحد. تُحفظ مخرجات كل وحدة على القرص، ثم يتحقق مُتحقق من صحتها، ويعيد كاتب واحد كتابة شرائح مجموعة البيانات في مكانها.

ما ينتجه خط الأنابيب

تصدر كل وحدة أنواعًا قليلة من التعليقات التوضيحية (الأنماط)، وتُوجَّه إلى إحدى عمودَي اللغة:

النمط / الذرةعمودوحدة
subtask (نمط Pi0.7: "كيف وليس ماذا")language_persistentplan
plan (التهيئة الأولية + التحديث عند المقاطعة)language_persistentplan
memory (ضغط بنمط MEM)language_persistentplan
task_aug (إعادة صياغة المهمة)language_persistentplan
interjectionlanguage_eventsinterjections
أداة استدعاء الكلام (style=null, say)language_eventsinterjections
vqa (زوج مستخدم / مساعد)language_eventsvqa

كيف يتم توليد المهام الفرعية

لا يطلب وحدة plan من نموذج الرؤية واللغة المهام الفرعية دفعة واحدة. بدلاً من ذلك، تستخدم تدفقاً من خطوتين: وصف → تقسيم:

  1. الوصف — يقوم نموذج VLM بسرد ما يراه فعليًا في الكاميرا المختارة (دون تخمين حول المهمة).
  2. Segment — يُعاد إدخال ذلك الوصف، ويقوم نموذج الرؤية-اللغة بتقسيم الحلقة إلى مهام فرعية ذرّية متتالية.

تتعامل كلا المسارين مع الحلقة على أنها أوراق اتصال مُوقّتة — وهي إطارات مُستخرجة بمعدل frames_per_second (0.5 ثانية افتراضيًا) ومُجمّعة في شبكات JPEG مع حرق وقت كل إطار في زاويته، مما يتيح لنموذج اللغة البصري (VLM) الاستشهاد بأوقات الحدود الدقيقة مباشرةً. هذا النهج أرخص بكثير من حيث رموز الرؤية مقارنةً باستخدام صورة لكل إطار، مما يسمح بإبقاء الاستخراج كثيفًا؛ فالحلقات الأطول من max_frames_per_prompt تُقسَّم إلى نوافذ بنفس الكثافة ثم تُدمج. كما تحمل كلا التوجيهات تعريفًا سببيًا لـ حدود الأحداث (يبدأ حدث جديد عندما يصبح كائن ما ممسوكًا / يُحرَّر / يصل إلى موقع جديد / يتغير حالة غطاء / تتحرك المحتويات) لتوضيح أماكن التقطيع بدقة أكبر.

اختياريًا، تمريرة ثالثة seeded-relabel (--plan.subtask_seeded_relabel) تعيد زيارة كل مقطع مع أوراق الاتصال (contact sheets) للمقطع السابق/الحالي/التالي وتصحح التسمية تصحيحًا أدنى، مستخدمةً التسمية الأولى كسابق (prior) — فهي تحافظ على الحدود ثابتة وتحدّد الصياغة فقط، مقابل تكلفة استدعاء إضافي واحد لكل مهمة فرعية.

تُدمج المقاطع الناتجة بعد ذلك لتكوين تغطية كاملة للحلقة دون فجوات، بحيث يوجد لكل إطار فرعية واحدة نشطة بالضبط. راجع التشغيل على Hugging Face Jobs لمعرفة إعدادات الإنتاج (كاميرا واحدة، أوراق اتصال مختومة بالوقت، توليد فرعية تلقائي النوافذ).

الأدوات

لا يضيف الكاتب عمود tools إلى parquet. بل يوجد كتالوج الأدوات في meta/info.json["tools"] بدلاً من ذلك (انظر الأدوات). بعد كل تشغيل، يتأكد خط المعالجة من وجود مخطط say القياسي في تلك القائمة، مع الحفاظ على أي أدوات أعلنتها مسبقاً.

هل تريد إضافة أداة خاصة بك؟ عدّل meta/info.json["tools"] مباشرةً — فخط المعالجة يحافظ على ما هو موجود بالفعل. وهذا يجعل الأداة مرئية لقالب المحادثة، بحيث يمكن للنموذج أن يتعلم توليد الاستدعاء. أما طبقة وقت التشغيل التي تنفّذ فعليًا استدعاءً مولّدًا (بروتوكول Tool / TOOL_REGISTRY تحت src/lerobot/tools/) فلم تُنفَّذ بعد — ويوثّق مستند Tools تلك الأجزاء على أنها غير منفّذة بعد.

التشغيل على Hugging Face Jobs

يتطلب توثيق مجموعة بيانات حقيقية بطاقة GPU كبيرة بما يكفي لتشغيل نموذج VLM، لذا يمكن لـ lerobot-annotate أن يُوجّه نفسه إلى Hugging Face Jobs — تمامًا كما يفعل lerobot-train. أضف --job.target=<flavor> إلى الأمر الدقيق الذي كنت ستشغّله محليًا، وسيُنفَّذ على ذلك العتاد بدلًا من ذلك:

hf auth login   # once

uv run lerobot-annotate \
    --repo_id=user/my_dataset \
    --new_repo_id=user/my_dataset_annotated \
    --push_to_hub=true \
    --vlm.model_id=Qwen/Qwen3.6-27B \
    --vlm.num_gpus=1 \
    --vlm.serve_command="vllm serve Qwen/Qwen3.6-27B --tensor-parallel-size 1 \
        --max-model-len 32768 --gpu-memory-utilization 0.8 \
        --uvicorn-log-level warning --port {port}" \
    --vlm.serve_ready_timeout_s=1800 \
    --vlm.chat_template_kwargs='{"enable_thinking": false}' \
    --job.target=h200

يقوم ذلك بإرسال مهمة h200 على وحدة معالجة رسومات واحدة:

  1. يبدأ من صورة vllm/vllm-openai ويقوم بتثبيت lerobot فوقها،
  2. يُشغّل خادم vLLM واحدًا لكل وحدة معالجة رسومية ويتحكم فيه عبر واجهة برمجة التطبيقات المتوافقة مع OpenAI،
  3. تشغّل وحدات plan / interjections / vqa عبر مجموعة البيانات،
  4. مع --push_to_hub=true، يُحمّل النتيجة إلى --new_repo_id (أو يعيدها إلى --repo_id في مكانها إذا تركت ذلك غير مضبوط).

يُبث الأمر سجلات المهمة؛ Ctrl-C يفصل دون إلغائها. اطلع على الأنواع المتاحة وأسعارها باستخدام hf jobs hardware.

يأتي Qwen3.6 مفعّلًا خاصية التفكير، مما يستهلك ميزانية الرموز التي يحتاجها المُعلِّم لإجابته بصيغة JSON — يُعطَّل ذلك عبر --vlm.chat_template_kwargs='{"enable_thinking": false}'. وبدون --push_to_hub=true يتم التخلّي عن مجموعة البيانات المُعلَّمة عند خروج العُقدة.

خيارات الوظائف

علمافتراضيما يفعله
--job.targetlocalنكهة HF Jobs التي سيتم التشغيل عليها (مثل h200، h200x4). يتم هنا تشغيل local أو عند الإغفال.
--job.imagevllm/vllm-openai:latestصورة وقت التشغيل للوحدة.
--job.timeout2hالحد الأقصى للوقت الفعلي. ارفعه في حالة استخدام مجموعات بيانات كبيرة.
--job.detachfalseأرسل وانتهِ بدلاً من بثّ السجلات.
--job.lerobot_refmainمرجع Git الخاص بـ lerobot المثبت على pod — وجّهه إلى فرع لاختبار التغييرات.
--job.tags[]وسوم إضافية على المهمة وعلى أي مجموعة بيانات تُدفع إليها (lerobot يُضاف دائمًا).

لمجموعة بيانات أكبر، قم بالتوسع إلى h200x4 وارفع --vlm.parallel_servers / --vlm.num_gpus بما يتناسب مع ذلك، ومنح المهمة مساحة أكبر على سبيل المثال باستخدام --job.timeout=8h.

تتطلب التشغيلات عن بُعد --repo_id (حيث يقوم العُقدة بسحب مجموعة البيانات من Hub؛ بينما يحدد --root مجلدًا موجودًا على جهازك فقط). تُدفع مجموعة البيانات الموجودة في ذاكرة التخزين المؤقت المحلية فقط إلى مستودع خاص أولاً.

خيارات رئيسية

هذه هي الأعلام التي ستلجأ إليها في أغلب الأحيان. نفّذ lerobot-annotate --help لمعرفة كل ما عدا ذلك؛ فالقيم الافتراضية مُعدّة خصيصًا لحلقات التلاعب القصيرة.

مجموعة البيانات في / خارج

علمافتراضيما يفعله
--repo_id—مجموعة بيانات Hub للتعليم (تُحمَّل إذا لم يُضبط --root).
--root—قم بتعليق دليل مجموعة بيانات محلية بدلاً من ذلك.
--new_repo_id—ادفع النتيجة إلى مستودع جديد (يُترك المستودع المصدر دون تغيير).
--push_to_hubfalseالرفع بعد التوسيم (إلى --new_repo_id، وإلا فإلى --repo_id).
--only_episodesالكلقم بتعليق فهارس الحلقات هذه فقط (مفيد للتشغيل التجريبي).
--seed1729يُهيّئ مولّدات الأرقام العشوائية (RNGs) التي تختار طوابع زمنية المقاطعات وأنواع أسئلة VQA.

الوحدات التي تعمل

كل وحدة مفعّلة افتراضيًا ويمكن تبديلها بشكل مستقل (اضبطها على false لتخطيها، مثلًا للتكرار على وحدة واحدة في كل مرة):

علمافتراضيإيقاف
--plan.enabledtrueالمهام الفرعية + الخطة + الذاكرة + task_aug
--interjections.enabledtrueأدوات التعجب + ذرات الكلام
--vqa.enabledtrueأزواج VQA

نموذج اللغة المرئي (VLM) ( --vlm.* )

علمافتراضيما يفعله
--vlm.model_idQwen/Qwen3.6-27Bالنموذج الذي سيتم تقديمه والاستعلام.
--vlm.camera_keyأول images.*الكاميرا التي يُستند إليها كل موجه.
--vlm.serve_commandautoأمر vllm serve … الدقيق (اضبط حجم TP وذاكرة GPU و--max-model-len هنا).
--vlm.parallel_servers1خوادم مستقلة للتوجيه بالتناوب (خادم واحد لكل وحدة معالجة رسومية).
--vlm.num_gpus0عدد وحدات معالجة الرسومات لكل خادم (0 = وحدة واحدة لكل خادم).
--vlm.client_concurrency16الطلبات الجارية عبر جميع الخوادم.
--vlm.max_new_tokens512حد التوليد لكل استدعاء.
--vlm.temperature0.2درجة حرارة العينة.
--vlm.reasoning_effortnullتلميح ميزانية التفكير (low/medium/high) المُعاد إلى الخوادم المتوافقة مع OpenAI.

المهام الفرعية / الخطة / الذاكرة ( --plan.* )

علمافتراضيما يفعله
--plan.frames_per_second2.0معدل أخذ العينات من الإطارات لصفحات الاتصال (2.0 = إطار واحد كل 0.5 ثانية).
--plan.max_frames_per_prompt60ميزانية الإطارات لكل استدعاء لنموذج VLM. تُطبَّق النوافذ تلقائيًا على الحلقات التي يتجاوز فيها أخذ العينات هذه الميزانية بنفس الكثافة، ثم تُخاط معًا.
--plan.contact_sheet_columns5الأعمدة في شبكة ورقة الاتصال (contact_sheet_frames_per_sheet بلاطات، صف زمني رئيسي).
--plan.plan_max_steps8الحد الأقصى لعدد المهام الفرعية لكل حلقة.
--plan.subtask_describe_firsttrueنفّذ مسار التأسيس من الوصف إلى التقسيم (أفضل جودة للمهام الفرعية؛ +1 استدعاء/حلقة).
--plan.subtask_seeded_relabelfalseالمرور الثاني: إعادة تسمية كل مهمة فرعية من أوراق الاتصال السابقة/الحالية/التالية الخاصة بها، مع التهيئة باستخدام التسمية الأولى (+1 استدعاء/مهمة فرعية).
--plan.subtask_relabel_frames5الإطارات المُستخرجة بشكل متساوٍ لكل ورقة مقطع في مسار إعادة التسمية (تُستخدم فقط عندما يكون subtask_seeded_relabel=true).
--plan.emit_plantrueأصدر صفوف plan المرقّمة (false = المهام الفرعية والذاكرة فقط).
--plan.emit_memorytrueأصدر صفوف memory (false = المهام الفرعية والخطة فقط)؛ وهو متماثل مع emit_plan.
--plan.n_task_rephrasings10عدد إعادة الصياغات task_aug التي يجب إصدارها (0 لتعطيلها).
--plan.derive_task_from_videoif_shortاستخدم مهمة مجموعة البيانات كما هي (off)، فقط عندما تكون مفقودة/قصيرة (if_short)، أو أعد اشتقاقها دائمًا من الفيديو (always).

التدخلات + VQA

علمافتراضيما يفعله
--interjections.max_interjections_per_episode3الحد الأقصى لعدد أزواج المقاطعة/الكلام في كل حلقة.
--vqa.vqa_emission_hz1.0تكرار إصدار أزواج VQA.
--vqa.restrict_to_default_camerafalseاعتمد VQA على --vlm.camera_key فقط (وإلا فكل كاميرا).
--vqa.coordinate_scale1000شبكة bbox/keypoint الخاصة بـ VLM، مخزنة في نطاق [0, 1] (none = بكسل).
--executor.episode_parallelism16الحلقات التي تتم معالجتها بالتوازي داخل كل مرحلة.

المساهمة في وحدات جديدة

صُمِّم خط الأنابيب ليتم توسيعه، ونرحب بالمساهمات بشدة — سواء كان ذلك عبر وحدة جديدة تمامًا (مثل تتبع المسارات أو الإمكانات)، أو قالب موجّه جديد، أو تدفق تثبيت أكثر ذكاءً، أو إصلاحات جودة للوحدات الموجودة plan / interjections / vqa.

توجد كل وحدة تحت src/lerobot/annotations/steerable_pipeline/modules/، وتشارك عميل VLM وذاكرة التخزين المؤقت للإطارات الرئيسية، وتكتب مخرجاتها الخام إلى شجرة التجميع، وتُدمج في المنفّذ كمرحلة مستقلة. لديك فكرة؟ افتح مشكلة أو طلب سحب في المستودع.

كيف تستهلك الوصفات المخرجات

تُصمَّم التعليقات ليتم قراءتها بواسطة الوصفات (انظر أعمدة اللغات والوصفات). عادةً:

  • تقرأ فروع المستوى المنخفض / المستوى العالي / تحديث الذاكرة subtask / plan / memory من language_persistent.
  • تقرأ فرع المقاطعة-الاستجابة أحداث interjection بالإضافة إلى ذرّة الكلام المزدوجة (المدمجة في دور مساعد واحد عبر tool_calls_from) وتحديث plan المطابق عند نفس الطابع الزمني.
  • تقرأ فرع VQA أزواج (vqa, user) و(vqa, assistant) من language_events.

لماذا يتم فصل الحالة والأحداث

تتخذ التصميم شكله فكرتان:

  1. الحالة الدائمة مقابل الأحداث الدقيقة. الصفوف الدائمة (subtask، plan، memory) تنطبق على الحلقة بأكملها وتُجيب عن سؤال «ما الذي صحيح الآن؟». أما الصفوف الحدثية (interjection، vqa، الكلام) فتظهر فقط في الإطار الوحيد الذي يطابق طابعه الزمني. تُنسخ الطوابع الزمنية مباشرةً من ملف parquet المصدر — ولا تُعاد حسابها أبدًا باستخدام الفاصلة العائمة.
  2. مرور واحد لنموذج الرؤية-اللغة. تتشارك جميع الوحدات الثلاث عميلًا واحدًا لنموذج الرؤية-اللغة (العميل المتوافق مع OpenAI الذي يتواصل مع خادم vLLM الخاص بالمهمة)، لذا تدفع مقابل تحميل نموذج واحد لكل مجموعة بيانات، وليس ثلاثة.

إعادة تشغيل وحدة واحدة

يُخزّن كل وحدة مخرجاتها الخام في <root>/.annotate_staging/episode_{N:06d}/<module>.jsonl. وهذا يجعل تكرار المحفزات رخيص التكلفة: فإعادة تشغيل وحدة واحدة تُعيد كتابة ملف JSONL الخاص بها فقط، ثم يعيد الكاتب تركيب ملف parquet النهائي. عطّل الوحدات التي لا ترغب في تشغيلها باستخدام --plan.enabled=false (وبالمثل --interjections.enabled / --vqa.enabled) لاختبار وحدة واحدة في كل مرة.

ما يفحصه المُتحقّق

قبل تشغيل الكاتب، يتحقق StagingValidator مما يلي:

  • تقع كل صفّ حدثٍ تمامًا على طابع زمنيّ لإطارٍ حقيقيّ؛
  • لا تبقى أي أزواج من الكلام/التصريحات معزولة؛
  • يُحدَّث plan عند كل طابع زمني للتدخل؛
  • تقع صفوف memory على حدود المهام الفرعية (إنها تحذير وليس خطأً)؛
  • كل محتوى مساعد VQA content هو JSON صالح بأحد الأشكال التالية: bbox / keypoint / count / attribute / spatial؛
  • تذهب كل صف إلى العمود الذي تحدده column_for_style(style).

تؤدي أي أخطاء إلى إيقاف الكاتب. مرّر --skip_validation=true لتجاوز ذلك أثناء التصحيح.

من أين تأتي أفكار كل وحدة

  • plan — المهام الفرعية. روبوت Hi (Shi 2025) لحجم الذرّة (مثل “التقاط قطعة خس واحدة”، “وضع الوعاء في الصندوق”); وPi0.7 (Physical Intelligence 2025) لتفاصيل “كيف وليس ماذا”.
  • plan — الذاكرة. MEM (Torne 2026): احتفظ بالمعلومات ذات الصلة الحد الأدنى فقط — حافظ على النتائج، وأزل الخصائص المحددة.
  • interjections. تصنيف سيناريوهات Hi Robot: مهمة سلبية، تصحيح مرتبط بالسياق، قيد محدد، تفضيل. الكلام هو ذرّة مخصّصة لاستدعاء الأدوات فقط (tool_calls=[{type:function, function:{name:"say", arguments:{text:...}}}]).
  • vqa. ECoT (Zawalski 2024) للميزات المرسّخة (صناديق الحدود [x_min, y_min, x_max, y_max] ونقاط المفاتيح، المخزّنة ككسور من الصورة ضمن المجال [0, 1]) وسياسات VLA القابلة للتوجيه (Zhao 2025) للترسيخ متعدد المستويات التجريدية. كما يرسّخ Pi0.7 الإجابات عبر مستويات التجريد المختلفة.

عند تحسين وحدة، عدّل قالب موجهاتها في src/lerobot/annotations/steerable_pipeline/prompts/ بدلاً من إعادة كتابتها من الصفر.

كم تبلغ تكلفته تقريباً

في كل حلقة، يُجري خط الأنابيب حوالي plan_max_steps من استدعاءات التخطيط، وmax_interjections_per_episode من استدعاءات المقاطعة، وvqa_emission_hz × episode_seconds من استدعاءات VQA. مع القيم الافتراضية (8 مهام فرعية، 3 مقاطعات، 1 هرتز × 3 أزواج) في حلقة مدتها 30 ثانية، يكون ذلك حوالي 50 استدعاءً لنموذج VLM.

تبقى مساحة التخزين صغيرة: language_persistent لا يتجاوز بضع عشرات من الكيلوبايت لكل حلقة (حيث يقوم parquet بتشفير القاموس للدخول الواحد الذي يتكرر عبر الإطارات)، وlanguage_events فارغ في معظم الإطارات — حيث تتناسب حجمه مع عدد الإطلاقات، وليس مع num_frames × num_emissions.

Update on GitHub