# LingBot-VLA 2.0

LingBot-VLA 2.0 هو نموذج الرؤية واللغة والإجراء من Robbyant، وهو النسخة التالية من LingBot-VLA 1.0. يجمع بين العمود الفقري Qwen3-VL-4B وخبير إجراء Qwen2 يعتمد على مزيج من الخبراء المتناثرين (32 خبيرًا، مع توجيه top-4)، ويولّد مجموعات الإجراءات باستخدام مطابقة التدفق عبر مساحة حالة/إجراء قياسية من 55 بُعدًا مشتركة بين جميع التجسيدات.

نسخة LeRobot هي سياسة `lingbot_vla_v2`. تستخدم مجموعات بيانات LeRobot القياسية، والمعالجات، و`lerobot-train`، و`lerobot-eval`، و`lerobot-rollout`، بما في ذلك تقطير العمق والفيديو للاستعلام المزدوج من المصدر الأصلي.

لمزيد من التفاصيل حول النموذج، راجع [المستودع الأصلي](https://github.com/Robbyant/lingbot-vla-v2) و[التقرير التقني](https://arxiv.org/abs/2607.06403).

## التثبيت

```bash
pip install -e ".[training,lingbot_vla_v2]"
```

يتم تحميل مُجزِّئ ومعالج الصور الخاصين بـ Qwen3-VL من `Qwen/Qwen3-VL-4B-Instruct` (`--policy.tokenizer_path`) عند بناء المعالج. لا حاجة إلى `flash-attn`؛ إذ يستخدم الانتباه PyTorch SDPA.

## نقاط التفتيش

| نقطة التفتيش                        | المصدر                                               | استخدام                                                                                                                                       |
| --------------------------------- | ---------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `lerobot/lingbot_vla_v2_base`     | `robbyant/lingbot-vla-v2-6b`، تحويل بصيغة فقط | نقطة الانطلاق للضبط الدقيق. الميزات هي التخطيط القياسي الكامل ذو 55 بُعدًا؛ قم بتمرير خرائط الفتحات الخاصة بروبوتك.                           |
| `lerobot/lingbot_vla_v2_robotwin` | `robbyant/lingbot-vla-v2-6b-robotwin`، الخطوة 50000    | تقييم RoboTwin 2.0. حالة/إجراء بعدد 14 بُعدًا، كاميرات `cam_high`، `cam_left_wrist`، `cam_right_wrist`، تطبيع `QUANTILES` (q01/q99). |

حمّل أيّاً منهما باستخدام `--policy.path`؛ حيث يتم قراءة نوع السياسة من ملف `config.json` الخاص بالنقطة المحفوظة.

## تعيين الروبوت على التخطيط القياسي

يرى النموذج حالة بأبعاد 55 ويتنبأ بإجراءات بأبعاد 55. يتم تحديد الترتيب بواسطة `canonical_joints` في الإعدادات:

| فتحة                | الأبعاد | المحتوى               |
| ------------------- | ---- | --------------------- |
| `arm.position`      | 14   | مواضع مفاصل الذراع   |
| `end.position`      | 14   | أوضاع الأطراف النهائية    |
| `effector.position` | 2    | مواضع الماسك     |
| `hand.position`     | 12   | مفاصل اليد الماهرة |
| `waist.position`    | 4    | مفاصل الخصر          |
| `head.position`     | 2    | مفاصل الرأس           |
| `base.velocity`     | 3    | سرعة القاعدة المتنقلة  |
| `reserved.slots`    | 4    | محجوز              |

`--policy.state_slots` و`--policy.action_slots` تُخضع مقاطع `observation.state` و`action` في مجموعة بياناتك إلى هذه الفتحات، بصيغة JSON:

```json
{
  "observation.state.arm.position": {
    "origin_keys": [{ "observation.state": { "start": 0, "end": 5 } }]
  }
}
```

- أسماء الفتحات هي الأسماء الرسمية المذكورة أعلاه، مع إمكانية إضافة بادئة اختيارية `observation.state.` أو `action.`. تثير الأسماء غير المعروفة خطأً.
- تقرأ كل خانة نطاقًا واحدًا أو أكثر من `{start, end}` من `observation.state` (خانات الحالة) أو `action` (خانات الإجراء). يتم دمج النطاقات وتعبئتها من بداية الخانة؛ أما الجزء المتبقي من الخانة فيُملأ بالأصفار ويُستبعد من حساب الخسارة.
- في غياب تعيين الفتحات، تُؤخذ الميزات الخام على أنها التخطيط القياسي ذي الأبعاد الخمسين وخمسة، كما في نقطة الفحص الأساسية.
- الإجراءات النسبية معطّلة افتراضيًا. يطرح `--policy.use_relative_actions=true` الحالة الحالية من الإجراء، باستثناء الأبعاد التي تحتوي أسماؤها على عنصر من `--policy.relative_exclude_joints` (الافتراضي `["gripper"]`).

يعكس المعالج اللاحق (postprocessor) عملية الإسناد، لذا تُرجع `select_action` الإجراءات في فضاء الإجراءات الخام لروبوتك. تحفظ نقاط الفحص المُحسَّنة (fine-tuned checkpoints) إسنادات الفتحات وإحصاءات مجموعة البيانات مع معالجاتها.

### الكاميرات

تقرأ خطوة الصورة الكاميرات المدرجة في `input_features` الخاص بالنقطة المرجعية، وذلك بالترتيب المذكور. بالنسبة للنقطة المرجعية الأساسية، فهي `camera_top` و`camera_wrist_left` و`camera_wrist_right`. قم بربط كاميرات مجموعة بياناتك بها باستخدام `--rename_map`؛ حيث تُستبعد الزوايا التي لا تتوفر في روبوتك.

## الضبط الدقيق

مثال على [`maximellerbach/omx_multicubes`](https://huggingface.co/datasets/maximellerbach/omx_multicubes)، وهو ذراع واحدة بمفاصل خمسة ومقبض وكاميرتين (`top`، `wrist`):

```bash
lerobot-train \
  --dataset.repo_id=maximellerbach/omx_multicubes \
  --policy.path=lerobot/lingbot_vla_v2_base \
  --policy.state_slots='{"observation.state.arm.position": {"origin_keys": [{"observation.state": {"start": 0, "end": 5}}]}, "observation.state.effector.position": {"origin_keys": [{"observation.state": {"start": 5, "end": 6}}]}}' \
  --policy.action_slots='{"action.arm.position": {"origin_keys": [{"action": {"start": 0, "end": 5}}]}, "action.effector.position": {"origin_keys": [{"action": {"start": 5, "end": 6}}]}}' \
  --rename_map='{"observation.images.top": "observation.images.camera_top", "observation.images.wrist": "observation.images.camera_wrist_left"}' \
  --policy.dtype=float32 \
  --accelerator.mixed_precision=bf16 \
  --policy.repo_id=your_repo_id \
  --batch_size=1 \
  --steps=30000 \
  --save_freq=5000 \
  --output_dir=outputs/train/lingbot_vla_v2_omx
```

حافظ على الأوزان في fp32 وحسب في bf16 (`--policy.dtype=float32 --accelerator.mixed_precision=bf16`)، كما يفعل الإصدار الأصلي. عند استخدام `--policy.dtype=bfloat16`، يقوم المُحسِّن بتحديث أوزان bf16 مباشرةً، ومعظم التحديثات صغيرة جدًا بحيث لا تُحدث تغييرًا فيها: في هذا مجموعة البيانات، بقي 66% من الأوزان مطابقةً بتًّا لنقطة التفتيش الأساسية، وكان سياسة التدريب الدقيق أكثر اهتزازًا بكثير. نفّذ الاستدلال في fp32 أيضًا (وهو الافتراضي لنقطة تفتيش تم تدريبها بهذه الطريقة)؛ فاستدلال bf16 يجعل مقاطع الإجراءات أقل سلاسة بشكل ملحوظ.

تأتي إحصاءات التطبيع من مجموعة البيانات. يستخدم التدريب متعدد وحدات معالجة الرسوميات أداة الإقلاع القياسية `torchrun` مع الأعلام `--parallelism.*` و`--accelerator.*`. تستهلك الأوزان والتدرجات وحالة المُحسِّن بدقة fp32 حوالي 96 جيجابايت، لذا قسّمها باستخدام `--parallelism.dp_shard=<num_gpus>` عندما تكون وحدة معالجة الرسوميات الواحدة صغيرة الحجم.

### التقطير بالاستعلام المزدوج

تضيف تطبيق LingBot-VLA 2.0 رموز استعلام مُتعلَّمة (عمق/فيديو حالي ومستقبلي) بعد رموز اللغة، ويُولي خبير الإجراءات اهتمامًا بها. تحمل كلا نقطتي التفتيش وصفة المصدر في `align_params`، لذا تُستخدم رموز الاستعلام دائمًا عند الاستدلال. أثناء التدريب، تقرأ رؤوس صغيرة تلك الرموز وتُستخلص من مدرّسين مجمّدين (LingBot-Depth مع MoGe-2، وDINO-Video) بأوزان الخسارة من المصدر؛ وتُسجَّل الخسائر الإضافية على أنها `depth_loss`، `future_depth_loss`، `current_video_loss` و`future_video_loss`.

تُحمَّل نماذج المعلم في خطوة التدريب الأولى (حوالي 3 غيغابايت من `robbyant/lingbot-vla-v2-6b` و`Ruicheng/moge-2-vitb-normal`)، وتستحوذ على نحو 2 غيغابايت من ذاكرة وحدة معالجة الرسوميات، وتضيف ما يقارب 130 مللي ثانية لكل عينة في كل خطوة. كما تُحمَّل كل عينة الإطار `chunk_size - 1` خطوات إلى الأمام، وهو ما تتطلبه الأهداف المستقبلية. لا يُنفَّذ أي شيء إضافي أثناء الاستدلال.

### معلمات التدريب الرئيسية

| معامل                               | افتراضي                     | الوصف                                                                |
| --------------------------------------- | --------------------------- | -------------------------------------------------------------------------- |
| `state_slots` / `action_slots`          | `null`                      | المقاطع الخام إلى الفتحات القياسية (انظر أعلاه).                                  |
| `use_relative_actions`                  | `false`                     | تدرّب على الإجراءات النسبية للحالة الحالية.                            |
| `loss_type`                             | `L1_fm`                     | خسارة مطابقة التدفق على السرعة.                                        |
| `normalization_mapping`                 | حالة `MEAN_STD` والإجراء | يستخدم نقطة التفتيش RoboTwin `QUANTILES`.                                  |
| `train_expert_only`                     | `false`                     | Freeze العمود الفقري لنموذج Qwen3-VL وتدرّب على خبير الإجراءات فقط.             |
| `freeze_vision_encoder`                 | `false`                     | تجميد برج الرؤية.                                                   |
| `gradient_checkpointing`                | `false`                     | إعادة حساب التفعيلات في التدرج العكسي لتوفير الذاكرة على حساب زمن الخطوة. |
| `use_moe_expert_lr`                     | `true`                      | تُدرَّب الخبراء الموجَّهون بمعدل تعلّم `lr * sqrt(num_experts / top_k)`، كما هو الحال في المصدر الأصلي.     |
| `optimizer_lr` / `scheduler_decay_lr`   | `1e-5` / `1e-5`             | معدل التعلم الأقصى والنهائي لـ AdamW.                                        |
| `resize_imgs_with_padding`              | `[256, 256]`                | حجم الإطار قبل معالج صور Qwen3-VL، كما هو في المصدر.               |
| `image_max_pixels` / `image_min_pixels` | `65536` / `65536`           | ميزانية بكسلات Qwen3-VL: 64 رمزًا لكل كاميرا، كما في المصدر الأصلي.                  |
| `chunk_size` / `n_action_steps`         | `50` / `50`                 | الأفق المتوقع وعدد الإجراءات المنفذة لكل شريحة.                |
| `num_steps`                             | `10`                        | خطوات إزالة الضوضاء عند الاستدلال.                                              |
| `tokenizer_path`                        | `Qwen/Qwen3-VL-4B-Instruct` | مُجزِّئ ومعالج الصور لنموذج Qwen3-VL. استخدم مسارًا محليًا دون اتصال.          |

لتحقيق توافق مع بطاقة GPU أصغر، اجمع بين `--policy.train_expert_only=true` و`--policy.gradient_checkpointing=true` مع قيمة صغيرة لـ`--batch_size`.

## التقييم

قيّم نقطة التفتيش RoboTwin في بيئة RoboTwin الخاصة بـ LeRobot (انظر [RoboTwin](./robotwin) للإعداد). تُحاذا خريطة إعادة التسمية أسماء كاميرات البيئة مع أسماء نقطة التفتيش:

```bash
lerobot-eval \
  --policy.path=lerobot/lingbot_vla_v2_robotwin \
  --env.type=robotwin \
  --env.task=beat_block_hammer \
  --eval.batch_size=1 \
  --eval.n_episodes=100 \
  --rename_map='{"observation.images.head_camera": "observation.images.cam_high", "observation.images.left_camera": "observation.images.cam_left_wrist", "observation.images.right_camera": "observation.images.cam_right_wrist"}'
```

متوسط النجاح عبر مهام RoboTwin 2.0 الخمسين (100 حلقة لكل مهمة)، كما ورد في [ملف README الأصلي](https://github.com/Robbyant/lingbot-vla-v2) الخاص بنقطة الفحص (checkpoint) المُطلَقة من RoboTwin (تدريب لاحق باستخدام Muon على بيانات نظيفة ومُشَوَّشة، واستدلال بدقة FP32 باستخدام مُشغِّل RoboTwin الأصلي). هذه أرقام من المصدر الأصلي، ولم تُقَس عبر هذا الإصدار المُحوَّل.

| الإعداد    | π0.5   | LingBot-VLA 1.0 | LingBot-VLA 2.0 |
| ---------- | ------ | --------------- | --------------- |
| نظيف      | 82.74% | 88.56%          | **93.52%**      |
| عشوائي | 76.76% | 86.68%          | **92.80%**      |

## تسريع الاستدلال

أربعة أعلام، جميعها معطّل افتراضيًا، تُسرّع `select_action`. تتطلب CUDA وأشكال إدخال ثابتة، ولا تحتاج إلى تبعيات إضافية:

- `--policy.use_cudagraph_denoise=true`: التقاط حلقة إزالة الضوضاء كرسمة CUDA واحدة.
- `--policy.use_cudagraph_prefix=true`: التقاط تعبئة KV للبداية المشتركة بين الرؤية واللغة.
- `--policy.use_cudagraph_prefix_full=true`: التقاط برج الرؤية أيضًا في رسم البادئة.
- `--policy.compile_predict_velocity=true`: `torch.compile` للتنبؤ بالسرعة في كل خطوة. يستغرق الاستدعاء الأول حوالي دقيقة للترجمة.

حان الوقت لقطعة إجراء واحدة من 50 خطوة مع 10 خطوات إزالة الضوضاء، نقطة تحقق RoboTwin، وبطاقة RTX PRO 6000 واحدة:

| أعلام                                | bf16    | fp32    |
| ------------------------------------ | ------- | ------- |
| none                                 | ~756 مللي ثانية | ~614 مللي ثانية |
| أعلام CUDA graph الثلاثة           | ~180 مللي ثانية | ~203 مللي ثانية |
| جميع أعلام CUDA graph الثلاثة + compile | ~120 مللي ثانية | ~156 مللي ثانية |

في bf16 تعطي رسوميات CUDA نفس المخرجات كما في الوضع العاجل؛ `torch.compile` يغيّر الأرقام قليلاً.

## النشر

شغّل نقطة تحقق مُعدّلة على روبوت باستخدام `lerobot-rollout`، مع تمرير `--rename_map` نفسه كما في التدريب:

```bash
lerobot-rollout \
  --strategy.type=base \
  --policy.path=outputs/train/lingbot_vla_v2_omx/checkpoints/last/pretrained_model \
  --robot.type=<your_robot_type> \
  --robot.port=<port> \
  --task="pick up the cube" \
  --fps=30 \
  --device=cuda
```

يتوفر التقطيع في الوقت الفعلي مع `--inference.type=rtc`، تمامًا كما هو الحال مع سياسات مطابقة التدفق الأخرى.

## الاستشهاد

```bibtex
@article{lingbotvla2,
      title={From Foundation to Application: Improving VLA Models in Practice},
      author={Wei Wu and Fangjing Wang and Fan Lu and He Sun and Shi Liu and Yunnan Wang and Yibin Yan and Yong Wang and Shuailei Ma and Xinyang Wang and Yibin Liu and Shuai Yang and Tianxiang Zhou and Kejia Zhang and Lei Zhou and Cheng Su and Nan Xue and Bin Tan and Han Zhang and Youchao Zhang and Fei Liao and Xing Zhu and Yujun Shen and Kecheng Zheng},
      journal={arXiv preprint arXiv:2607.06403},
      year={2026}
}
```

## رخصة

الكود ونقاط التفتيش المحوّلة مرخّصة بموجب Apache-2.0، تمامًا كما هي إصدارات LingBot-VLA 2.0 وQwen3-VL الأصلية.

تنزيل تدريب التقطير ثلاثة معلمين مجمّدين تحت رخصهم الخاصة (لا يتم تحميلهم أبداً أثناء الاستدلال):

| المعلم       | الأوزان                                      | رخصة                                                                           |
| ------------- | -------------------------------------------- | --------------------------------------------------------------------------------- |
| MoGe-2        | `Ruicheng/moge-2-vitb-normal`                | MIT                                                                               |
| LingBot-Depth | `robbyant/lingbot-vla-v2-6b` (`depth/`)      | Apache-2.0                                                                        |
| DINO-Video    | `robbyant/lingbot-vla-v2-6b` (`dino_video/`) | [رخصة DINOv3](https://github.com/facebookresearch/dinov3/blob/main/LICENSE.md) |

تُشتق أوزان DINO-Video من DINOv3 الخاص بـ Meta، لذا فإن التدريب باستخدام التقطير يعني استخدامها بموجب ترخيص DINOv3، والذي، إلى جانب شروط أخرى، يطلب منك ذكر DINOv3 في المنشورات ويقيّد بعض الاستخدامات النهائية.

