# X Vla Embodiment

> Use soft-prompted transformer architecture for multi-robot learning. Add learnable embodiment-specific prompt embeddings to handle different robot types while maintaining single shared backbone. Scale to 0.9B parameters across 6 simulators and 3 real robots.

- Skill: `adu2021/x-vla-embodiment` (Agent Skill)
- Install (CLI): `npx skillmds@latest add adu2021/x-vla-embodiment`
- Raw SKILL.md: https://api.skillmd.com/api/skills/adu2021/x-vla-embodiment/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- License: MIT
- Author: adu2021 (https://skillmd.com/u/adu2021)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/adu2021/x-vla-embodiment

---


# X-VLA: Efficient Cross-Embodiment Vision-Language-Action Learning

Different robot embodiments have different action spaces, dynamics, and sensor configurations. X-VLA handles this diversity through soft prompting: each embodiment gets learnable prompt embeddings that condition the shared transformer, enabling one model to work across diverse robotic systems without separate parameters per embodiment.

Core insight: embodiment diversity is largely a prompt-engineering problem. By treating embodiment as learnable conditioning information rather than fundamentally different models, you maintain parameter efficiency while achieving state-of-the-art multi-robot performance.

## Core Concept

**Soft Prompting for Embodiments**: Each data source/embodiment gets learnable embedding that conditions model behavior without parameter multiplication.

**Shared Backbone Architecture**: Single transformer with minimal added parameters handles all embodiments through prompt variation.

## Architecture Overview

- **Shared Vision Transformer**: Encodes images consistently
- **Embodiment Prompts**: Learnable per-embodiment conditioning vectors
- **Prompt Fusion**: Integrate embodiment prompts with visual/language features
- **Action Decoder**: Generates robot-specific actions

## Implementation Steps

**Stage 1: Embodiment-Specific Soft Prompts**

Create learnable embodiment embeddings:

```python
import torch
import torch.nn as nn
from transformers import AutoModel, AutoTokenizer

class EmbodimentPromptedVLA(nn.Module):
    def __init__(
        self,
        backbone_model='google/vit-base-patch16-224',
        num_embodiments=3,
        prompt_dim=768,
        vocab_size=1024
    ):
        """
        Multi-embodiment VLA with soft prompts.
        """

        super().__init__()

        # Shared vision backbone
        self.vision_encoder = AutoModel.from_pretrained(
            backbone_model
        )

        # Embodiment-specific soft prompts
        self.num_embodiments = num_embodiments
        self.embodiment_prompts = nn.ParameterList([
            nn.Parameter(torch.randn(1, 1, prompt_dim))
            for _ in range(num_embodiments)
        ])

        # Normalize prompts
        for param in self.embodiment_prompts:
            nn.init.normal_(param, std=0.02)

        # Transformer for combining vision + prompt + language
        self.fusion_transformer = nn.TransformerEncoder(
            encoder_layer=nn.TransformerEncoderLayer(
                d_model=prompt_dim,
                nhead=12,
                dim_feedforward=3072,
                dropout=0.1,
                batch_first=True
            ),
            num_layers=4
        )

        # Action decoder (generates robot-specific actions)
        self.action_decoder = nn.Sequential(
            nn.Linear(prompt_dim, 512),
            nn.ReLU(),
            nn.Linear(512, vocab_size)
        )

    def forward(
        self,
        images,
        language_embeddings,
        embodiment_idx
    ):
        """
        Forward pass with embodiment conditioning.

        Args:
            images: [batch, 3, 224, 224]
            language_embeddings: [batch, seq_len, 768]
            embodiment_idx: which embodiment (0, 1, 2, ...)
        """

        # Encode images
        image_features = self.vision_encoder.forward_features(
            images
        )  # [batch, seq_len, 768]

        batch_size = image_features.shape[0]

        # Get embodiment prompt
        embodiment_prompt = self.embodiment_prompts[embodiment_idx]
        embodiment_prompt = embodiment_prompt.expand(
            batch_size,
            -1,
            -1
        )

        # Concatenate: [image_features | embodiment_prompt | language]
        fused_input = torch.cat(
            [image_features, embodiment_prompt, language_embeddings],
            dim=1
        )

        # Fusion transformer
        fused_features = self.fusion_transformer(fused_input)

        # Extract embodiment-conditioned representation
        embodiment_conditioned = fused_features[:, image_features.shape[1], :]

        # Decode actions
        action_logits = self.action_decoder(
            embodiment_conditioned
        )

        return action_logits
```

**Stage 2: Training with Multiple Embodiments**

Train on data from different robots:

```python
def train_multi_embodiment_vla(
    model,
    embodiment_datasets,
    num_epochs=10,
    learning_rate=5e-4
):
    """
    Train VLA on multiple embodiment datasets simultaneously.

    Args:
        embodiment_datasets: list of dataloader, one per embodiment
        embodiment_datasets[i] yields (image, language, action)
    """

    optimizer = torch.optim.AdamW(
        model.parameters(),
        lr=learning_rate
    )

    for epoch in range(num_epochs):
        for embodiment_idx, dataloader in enumerate(embodiment_datasets):
            for batch_idx, batch in enumerate(dataloader):
                images = batch['images'].cuda()
                language = batch['language_embeddings'].cuda()
                actions = batch['actions'].cuda()

                # Forward pass with specific embodiment
                action_logits = model(
                    images,
                    language,
                    embodiment_idx=embodiment_idx
                )

                # Compute loss
                loss = torch.nn.functional.cross_entropy(
                    action_logits.view(-1, action_logits.shape[-1]),
                    actions.view(-1)
                )

                # Backward pass
                optimizer.zero_grad()
                loss.backward()
                optimizer.step()

                if batch_idx % 50 == 0:
                    print(
                        f"Epoch {epoch}, Embodiment {embodiment_idx}, "
                        f"Batch {batch_idx}, Loss: {loss:.4f}"
                    )
```

**Stage 3: Inference on Different Embodiments**

Deploy on any embodiment:

```python
class CrossEmbodimentDeployer:
    def __init__(self, model, embodiment_names):
        """
        Deploy model on different embodiments.

        Args:
            embodiment_names: list like ['robot-arm', 'mobile-base', 'gripper']
        """

        self.model = model
        self.embodiment_mapping = {
            name: idx for idx, name in enumerate(embodiment_names)
        }

    def execute_task(
        self,
        task_description,
        initial_image,
        embodiment_name,
        max_steps=10
    ):
        """
        Execute task on specific embodiment.
        """

        embodiment_idx = self.embodiment_mapping[embodiment_name]

        # Encode task language
        language_embedding = encode_language(task_description)

        current_image = initial_image
        executed_actions = []

        for step in range(max_steps):
            with torch.no_grad():
                # Get action for this embodiment
                action_logits = self.model(
                    current_image.unsqueeze(0),
                    language_embedding.unsqueeze(0),
                    embodiment_idx=embodiment_idx
                )

                action = action_logits.argmax(dim=-1)[0].item()

            # Execute action on robot
            executed_actions.append(action)

            # Get observation
            current_image = execute_action_on_robot(
                action,
                embodiment_name
            )

            # Check if task complete
            if check_task_complete(current_image, task_description):
                break

        return executed_actions

    def transfer_to_new_embodiment(
        self,
        new_embodiment_name,
        adaptation_examples=None
    ):
        """
        Quickly adapt to new embodiment.
        """

        embodiment_idx = len(self.embodiment_mapping)

        # Add new embodiment prompt
        new_prompt = nn.Parameter(torch.randn(1, 1, 768))
        nn.init.normal_(new_prompt, std=0.02)

        self.model.embodiment_prompts.append(new_prompt)

        # Optional: fine-tune with few adaptation examples
        if adaptation_examples:
            optimizer = torch.optim.AdamW(
                [new_prompt],
                lr=1e-3
            )

            for image, language, action in adaptation_examples:
                action_logits = self.model(
                    image,
                    language,
                    embodiment_idx=embodiment_idx
                )

                loss = torch.nn.functional.cross_entropy(
                    action_logits,
                    action
                )

                optimizer.zero_grad()
                loss.backward()
                optimizer.step()

        self.embodiment_mapping[new_embodiment_name] = embodiment_idx

        return True
```

## Practical Guidance

**When to Use X-VLA:**
- Multi-robot learning with shared infrastructure
- Need to transfer between embodiments
- Parameter efficiency important
- Diverse but related robotic platforms

**When NOT to Use:**
- Single-embodiment systems (soft prompting overhead)
- Radically different embodiments (different capability classes)
- Real-time constraints (fusion transformer adds latency)

**Embodiment Prompt Design:**

| Strategy | Parameters Added | Best For |
|----------|-----------------|----------|
| Minimal (1 vector) | 768 per embodiment | Very similar robots |
| Standard (token sequence) | 10,000 per embodiment | Different morphologies |
| Full prompt (multi-token) | 100,000 per embodiment | Radically different robots |

**Cross-Embodiment Performance:**

| Setup | Single-Embodiment | X-VLA | Improvement |
|-------|------------------|-------|-------------|
| LIBERO | 42.3% | 43.1% | +1.8% |
| RoboTwin | 45.8% | 47.6% | +1.8% |
| Real Robots | 28.4% | 34.5% | +21.5% |

**Common Pitfalls:**
- Prompt dimension too small (insufficient conditioning)
- Prompt not trainable (frozen embeddings don't adapt)
- Fusion architecture too simple (doesn't integrate embodiment info)
- Not validating transfer to new embodiments

## Reference

Based on the research at: https://arxiv.org/abs/2510.10274

