Donghwa Kang, Sehee Kweon, Wooyul Jung
CoT in VLA is an Chain-of-Thought (ECoT) reasoning in vision-language-action (VLA) models in uncertain scenarios. CoT is used to improve success rate and reasoning faithfulness when the uncertainty from the action tokens is high. Experiments in LIBERO simulation shows proper Chain-of-Thought is helpful by improving task success rate and reasoning faithfulness.
We train and evaluate our method on the LIBERO-Spatial dataset, which contains 10 manipulation tasks that require spatial reasoning — for example, placing an object relative to another object ("put the bowl on top of the plate," "put the mug to the left of the plate"). These tasks are well-suited for evaluating the effect of reasoning, since the robot must identify spatial relationships before acting.
Why LIBERO-Spatial?
We use two versions of LIBERO in this project:
The original LIBERO dataset is provided in HDF5 format by the official LIBERO repository. It is required for running evaluation rollouts in the LIBERO simulator.
# Clone the LIBERO repo (provides the simulator + download utility)
git clone https://github.com/Lifelong-Robot-Learning/LIBERO.git
cd LIBERO
pip install -e .
# Download the LIBERO-Spatial split
python benchmark_scripts/download_libero_datasets.py --datasets libero_spatial
# Saved under: ./datasets/libero_spatial/
For training, we use the RLDS-formatted version released by OpenVLA, which removes no-op actions for more efficient policy learning. This is the standard training format used by OpenVLA and ECoT.
Source: openvla/modified_libero_rlds
# Install huggingface CLI if not already installed
pip install -U "huggingface_hub[cli]"
# Download the LIBERO-Spatial (no-noops) RLDS split
huggingface-cli download openvla/modified_libero_rlds \
--repo-type dataset \
--include "libero_spatial_no_noops/*" \
--local-dir ./datasets/modified_libero_rlds
Note: The HuggingFace repo contains multiple splits (
libero_spatial_no_noops,libero_object_no_noops,libero_goal_no_noops,libero_10_no_noops). Replace the--includepattern above with the split you want to download. To grab all splits at once, omit the--includeflag.
After downloading, the directory structure should look like:
datasets/
├── libero_spatial/ # original HDF5 (evaluation)
│ └── *.hdf5
└── modified_libero_rlds/ # RLDS (training)
└── libero_spatial_no_noops/
└── 1.0.0/
├── dataset_info.json
├── features.json
└── .tfrecord-
Update the dataset paths in your config file accordingly:
# configs/dataset.yaml
eval_dataset_path: ./datasets/libero_spatial/
train_dataset_path: ./datasets/modified_libero_rlds/libero_spatial_no_noops/1.0.0/
We build on two Vision-Language-Action (VLA) architectures: OpenVLA and ECoT (Embodied Chain-of-Thought).
OpenVLA is a 7B-parameter VLA model built on a vision-language backbone (Prismatic VLM). It takes a single RGB image and a natural language task instruction as input, and directly predicts a 7-DoF robot action (Δx, Δy, Δz, Δroll, Δpitch, Δyaw, gripper).
ECoT extends OpenVLA by injecting a chain-of-thought reasoning step before action prediction. Given the same image and instruction, the model first generates structured reasoning tokens — task description, plan, and subtask decomposition — then predicts the action conditioned on this reasoning trace. This explicit reasoning improves performance on tasks that require spatial understanding and multi-step planning.
| Model | Dataset | Checkpoint |
|---|---|---|
| OpenVLA (fine-tuned) | LIBERO-Spatial | openvla-7b-finetuned-libero-spatial |
| ECoT (LoRA, rank 32) | LIBERO-Spatial | ecot-libero-spatial-r32 |
To download a checkpoint:
# OpenVLA fine-tuned
git clone https://huggingface.co/openvla/openvla-7b-finetuned-libero-spatial
cd openvla-7b-finetuned-libero-spatial && git lfs fetch --all && cd ..
# ECoT LoRA
git clone https://huggingface.co/leepanic/ecot-libero-spatial-r32
cd ecot-libero-spatial-r32 && git lfs fetch --all && cd ..
Both demos are evaluated in the LIBERO environment, where the scene is reset with a new configuration each time (different from the training data).
OpenVLA (without CoT) entropy : 0.73 | success : False |
ECoT (with CoT) entropy : 0.62 | success : True |
conda create -n VLA python=3.10 -y
conda activate VLA
Install the PyTorch build that matches your CUDA version. See the official selector if you need a different version.
# CUDA 12.4
conda install pytorch torchvision torchaudio pytorch-cuda=12.4 -c pytorch -c nvidia -y
git clone https://github.com/seram7/Adaptive-CoT-in-VLA.git
cd Adaptive-CoT-in-VLA
pip install -e .
git clone https://github.com/Lifelong-Robot-Learning/LIBERO.git
cd LIBERO
pip install -e .
cd ..
python -c "import torch; print('PyTorch:', torch.__version__, '| CUDA available:', torch.cuda.is_available())"
python -c "import flash_attn; print('Flash-Attn:', flash_attn.__version__)"
python -c "import libero; print('LIBERO: OK')"
All three commands should print without error.
Make sure you have completed the installation steps before proceeding.
# Install Git LFS
sudo apt update && sudo apt install git-lfs
git lfs install
# Download the base model
git clone https://huggingface.co/openvla/openvla-7b-prismatic
cd openvla-7b-prismatic && git lfs fetch --all && cd ..
# (Optional) Download the ECoT-finetuned base model for LoRA fine-tuning
git clone https://huggingface.co/Embodied-CoT/ecot-openvla-7b-oxe
# Download dataset (written in [Dataset section](#dataset))
git clone https://huggingface.co/datasets/openvla/modified_libero_rlds
If using ECoT reasoning, place the reasoning JSON file in the dataset directory:
cp reasoning.json <DATA_ROOT_DIR>/<DATASET_NAME>/reasoning.json
Note:
<DATA_ROOT_DIR>is the parent directory containing your RLDS datasets (e.g.,./datasets/modified_libero_rlds), and<DATASET_NAME>is the specific split you're training on (e.g.,libero_spatial_no_noops).
Train from scratch on RLDS-formatted datasets:
torchrun --standalone --nnodes 1 --nproc-per-node 8 vla-scripts/train.py \
--vla.type "prism-dinosiglip-224px+mx-bridge" \
--data_root_dir <PATH_TO_DATA> \
--run_root_dir <PATH_TO_CHECKPOINTS> \
--wandb_project <WANDB_PROJECT> \
--wandb_entity <WANDB_ENTITY>
Parameter-efficient fine-tuning with LoRA on specific datasets:
torchrun --standalone --nnodes 1 --nproc-per-node 2 vla-scripts/finetune.py \
--vla_path "Embodied-CoT/ecot-openvla-7b-oxe" \
--data_root_dir <PATH_TO_DATA> \
--dataset_name <DATASET_NAME> \
--run_root_dir <PATH_TO_CHECKPOINTS> \
--adapter_tmp_dir <PATH_TO_ADAPTER_TMP> \
--lora_rank 32 \
--batch_size 1 \
--grad_accumulation_steps 1 \
--learning_rate 5e-4 \
--image_aug True \
--wandb_project <WANDB_PROJECT> \
--wandb_entity <WANDB_ENTITY> \
--save_steps 20000
| Parameter | Description | Default |
|---|---|---|
--vla_path | HuggingFace model path or local checkpoint | openvla/openvla-7b |
--data_root_dir | Root directory containing RLDS datasets | — |
--dataset_name | Name of the dataset to fine-tune on | — |
--lora_rank | Rank of LoRA weight matrices | 32 |
--learning_rate | Learning rate | 2e-5 |
--batch_size | Batch size per GPU | 16 |
--image_aug | Enable image augmentations | True |
--reasoning_dropout_prob | Dropout for reasoning tokens during training | 0.0 |
--action_loss | Add explicit action-only loss term | False |
--save_steps | Checkpoint save interval (gradient steps) | 50000 |
--use_quantization | 4-bit quantization for reduced memory | False |
| Setup | GPU Memory |
|---|---|
| LoRA (rank 32, batch 12) | ~48 GB |
| LoRA (rank 32, batch 24) | ~80 GB |
| Full fine-tune | 8× 80 GB GPUs recommended |
We evaluate both OpenVLA (without CoT) and ECoT (with CoT) on the LIBERO-Spatial benchmark to measure how Chain-of-Thought reasoning affects robot performance under uncertainty.
Each task is evaluated across 10 trials. At every step, we measure the model's uncertainty using action entropy — entropy computed over the 256 action token bins. A higher entropy means the model is more uncertain about which action to take.
Make sure LIBERO is installed and the path is correctly set in the script:
sys.path.insert(0, "/your/path/to/LIBERO")
Single GPU:
python rollout_ECoT.py
Results are saved under ./rollouts/{date}/{task_description}/:
task{id}_trial{id}.pt — logits, entropy, and success per rolloutThis codebase is built on top of the following excellent works:
Overall, our results suggest that ECoT performs better than OpenVLA in uncertain situations, but the story is more nuanced than a simple comparison.
What we found:
Key insight: This suggests an adaptive strategy — we don't need to always use CoT. Instead, we can monitor the model's entropy in real time and only trigger CoT reasoning when uncertainty is above a certain threshold. This way, we can get the benefits of CoT without paying the full cost on every step.
Limitations:
What we learned: Understanding the low-level details of VLA systems — input/output formats, action token structure, and model architecture — was essential to making progress. AI tools helped speed up the process, but only when paired with a solid understanding of the system.
Jupyter Notebook
93.3%
Python
6.6%
Donghwa Kang, Sehee Kweon, Wooyul Jung
CoT in VLA is an Chain-of-Thought (ECoT) reasoning in vision-language-action (VLA) models in uncertain scenarios. CoT is used to improve success rate and reasoning faithfulness when the uncertainty from the action tokens is high. Experiments in LIBERO simulation shows proper Chain-of-Thought is helpful by improving task success rate and reasoning faithfulness.
We train and evaluate our method on the LIBERO-Spatial dataset, which contains 10 manipulation tasks that require spatial reasoning — for example, placing an object relative to another object ("put the bowl on top of the plate," "put the mug to the left of the plate"). These tasks are well-suited for evaluating the effect of reasoning, since the robot must identify spatial relationships before acting.
Why LIBERO-Spatial?
We use two versions of LIBERO in this project:
The original LIBERO dataset is provided in HDF5 format by the official LIBERO repository. It is required for running evaluation rollouts in the LIBERO simulator.
# Clone the LIBERO repo (provides the simulator + download utility)
git clone https://github.com/Lifelong-Robot-Learning/LIBERO.git
cd LIBERO
pip install -e .
# Download the LIBERO-Spatial split
python benchmark_scripts/download_libero_datasets.py --datasets libero_spatial
# Saved under: ./datasets/libero_spatial/
For training, we use the RLDS-formatted version released by OpenVLA, which removes no-op actions for more efficient policy learning. This is the standard training format used by OpenVLA and ECoT.
Source: openvla/modified_libero_rlds
# Install huggingface CLI if not already installed
pip install -U "huggingface_hub[cli]"
# Download the LIBERO-Spatial (no-noops) RLDS split
huggingface-cli download openvla/modified_libero_rlds \
--repo-type dataset \
--include "libero_spatial_no_noops/*" \
--local-dir ./datasets/modified_libero_rlds
Note: The HuggingFace repo contains multiple splits (
libero_spatial_no_noops,libero_object_no_noops,libero_goal_no_noops,libero_10_no_noops). Replace the--includepattern above with the split you want to download. To grab all splits at once, omit the--includeflag.
After downloading, the directory structure should look like:
datasets/
├── libero_spatial/ # original HDF5 (evaluation)
│ └── *.hdf5
└── modified_libero_rlds/ # RLDS (training)
└── libero_spatial_no_noops/
└── 1.0.0/
├── dataset_info.json
├── features.json
└── .tfrecord-
Update the dataset paths in your config file accordingly:
# configs/dataset.yaml
eval_dataset_path: ./datasets/libero_spatial/
train_dataset_path: ./datasets/modified_libero_rlds/libero_spatial_no_noops/1.0.0/
We build on two Vision-Language-Action (VLA) architectures: OpenVLA and ECoT (Embodied Chain-of-Thought).
OpenVLA is a 7B-parameter VLA model built on a vision-language backbone (Prismatic VLM). It takes a single RGB image and a natural language task instruction as input, and directly predicts a 7-DoF robot action (Δx, Δy, Δz, Δroll, Δpitch, Δyaw, gripper).
ECoT extends OpenVLA by injecting a chain-of-thought reasoning step before action prediction. Given the same image and instruction, the model first generates structured reasoning tokens — task description, plan, and subtask decomposition — then predicts the action conditioned on this reasoning trace. This explicit reasoning improves performance on tasks that require spatial understanding and multi-step planning.
| Model | Dataset | Checkpoint |
|---|---|---|
| OpenVLA (fine-tuned) | LIBERO-Spatial | openvla-7b-finetuned-libero-spatial |
| ECoT (LoRA, rank 32) | LIBERO-Spatial | ecot-libero-spatial-r32 |
To download a checkpoint:
# OpenVLA fine-tuned
git clone https://huggingface.co/openvla/openvla-7b-finetuned-libero-spatial
cd openvla-7b-finetuned-libero-spatial && git lfs fetch --all && cd ..
# ECoT LoRA
git clone https://huggingface.co/leepanic/ecot-libero-spatial-r32
cd ecot-libero-spatial-r32 && git lfs fetch --all && cd ..
Both demos are evaluated in the LIBERO environment, where the scene is reset with a new configuration each time (different from the training data).
OpenVLA (without CoT) entropy : 0.73 | success : False |
ECoT (with CoT) entropy : 0.62 | success : True |
conda create -n VLA python=3.10 -y
conda activate VLA
Install the PyTorch build that matches your CUDA version. See the official selector if you need a different version.
# CUDA 12.4
conda install pytorch torchvision torchaudio pytorch-cuda=12.4 -c pytorch -c nvidia -y
git clone https://github.com/seram7/Adaptive-CoT-in-VLA.git
cd Adaptive-CoT-in-VLA
pip install -e .
git clone https://github.com/Lifelong-Robot-Learning/LIBERO.git
cd LIBERO
pip install -e .
cd ..
python -c "import torch; print('PyTorch:', torch.__version__, '| CUDA available:', torch.cuda.is_available())"
python -c "import flash_attn; print('Flash-Attn:', flash_attn.__version__)"
python -c "import libero; print('LIBERO: OK')"
All three commands should print without error.
Make sure you have completed the installation steps before proceeding.
# Install Git LFS
sudo apt update && sudo apt install git-lfs
git lfs install
# Download the base model
git clone https://huggingface.co/openvla/openvla-7b-prismatic
cd openvla-7b-prismatic && git lfs fetch --all && cd ..
# (Optional) Download the ECoT-finetuned base model for LoRA fine-tuning
git clone https://huggingface.co/Embodied-CoT/ecot-openvla-7b-oxe
# Download dataset (written in [Dataset section](#dataset))
git clone https://huggingface.co/datasets/openvla/modified_libero_rlds
If using ECoT reasoning, place the reasoning JSON file in the dataset directory:
cp reasoning.json <DATA_ROOT_DIR>/<DATASET_NAME>/reasoning.json
Note:
<DATA_ROOT_DIR>is the parent directory containing your RLDS datasets (e.g.,./datasets/modified_libero_rlds), and<DATASET_NAME>is the specific split you're training on (e.g.,libero_spatial_no_noops).
Train from scratch on RLDS-formatted datasets:
torchrun --standalone --nnodes 1 --nproc-per-node 8 vla-scripts/train.py \
--vla.type "prism-dinosiglip-224px+mx-bridge" \
--data_root_dir <PATH_TO_DATA> \
--run_root_dir <PATH_TO_CHECKPOINTS> \
--wandb_project <WANDB_PROJECT> \
--wandb_entity <WANDB_ENTITY>
Parameter-efficient fine-tuning with LoRA on specific datasets:
torchrun --standalone --nnodes 1 --nproc-per-node 2 vla-scripts/finetune.py \
--vla_path "Embodied-CoT/ecot-openvla-7b-oxe" \
--data_root_dir <PATH_TO_DATA> \
--dataset_name <DATASET_NAME> \
--run_root_dir <PATH_TO_CHECKPOINTS> \
--adapter_tmp_dir <PATH_TO_ADAPTER_TMP> \
--lora_rank 32 \
--batch_size 1 \
--grad_accumulation_steps 1 \
--learning_rate 5e-4 \
--image_aug True \
--wandb_project <WANDB_PROJECT> \
--wandb_entity <WANDB_ENTITY> \
--save_steps 20000
| Parameter | Description | Default |
|---|---|---|
--vla_path | HuggingFace model path or local checkpoint | openvla/openvla-7b |
--data_root_dir | Root directory containing RLDS datasets | — |
--dataset_name | Name of the dataset to fine-tune on | — |
--lora_rank | Rank of LoRA weight matrices | 32 |
--learning_rate | Learning rate | 2e-5 |
--batch_size | Batch size per GPU | 16 |
--image_aug | Enable image augmentations | True |
--reasoning_dropout_prob | Dropout for reasoning tokens during training | 0.0 |
--action_loss | Add explicit action-only loss term | False |
--save_steps | Checkpoint save interval (gradient steps) | 50000 |
--use_quantization | 4-bit quantization for reduced memory | False |
| Setup | GPU Memory |
|---|---|
| LoRA (rank 32, batch 12) | ~48 GB |
| LoRA (rank 32, batch 24) | ~80 GB |
| Full fine-tune | 8× 80 GB GPUs recommended |
We evaluate both OpenVLA (without CoT) and ECoT (with CoT) on the LIBERO-Spatial benchmark to measure how Chain-of-Thought reasoning affects robot performance under uncertainty.
Each task is evaluated across 10 trials. At every step, we measure the model's uncertainty using action entropy — entropy computed over the 256 action token bins. A higher entropy means the model is more uncertain about which action to take.
Make sure LIBERO is installed and the path is correctly set in the script:
sys.path.insert(0, "/your/path/to/LIBERO")
Single GPU:
python rollout_ECoT.py
Results are saved under ./rollouts/{date}/{task_description}/:
task{id}_trial{id}.pt — logits, entropy, and success per rolloutThis codebase is built on top of the following excellent works:
Overall, our results suggest that ECoT performs better than OpenVLA in uncertain situations, but the story is more nuanced than a simple comparison.
What we found:
Key insight: This suggests an adaptive strategy — we don't need to always use CoT. Instead, we can monitor the model's entropy in real time and only trigger CoT reasoning when uncertainty is above a certain threshold. This way, we can get the benefits of CoT without paying the full cost on every step.
Limitations:
What we learned: Understanding the low-level details of VLA systems — input/output formats, action token structure, and model architecture — was essential to making progress. AI tools helped speed up the process, but only when paired with a solid understanding of the system.
Jupyter Notebook
93.3%
Python
6.6%