CoolFace
Modelpublic

Dimios45/smolvla_tactile_charger_50ep

sourceHugging Faceapache-2.0updated 26d agoView on Hugging Face
0likes44downloads
Model Card

smolvlatactilecharger_50ep

SmolVLA vision-language-action policy — vision + tactile — fine-tuned from `lerobot/smolvla_base` on 50 episodes.

Task / language instruction: grab and remove the charger from the socket and put it in the black box

Trained with LeFlexiTac. Docs: <https://tna001-ai.github.io/LeFlexiTac/docs.html>

Training data

source dataset`aryankakad/tactile_charger_inserting`
episodes50 (all)
frames27,973 @ 30 fps
camerastop -> camera1, gripper -> camera2 (see rename_map below)
tactileobservation.tactile.primary (12x32)

Task string was retagged. The source dataset is labelled stack cup (carried over from an earlier recording session). SmolVLA is language-conditioned, so it was retrained on a copy retagged to the real instruction above. Use that instruction at inference.

Camera rename is required. smolvla_base expects camera1/2/3; this dataset uses top/gripper. Training passed:

--rename_map='{"observation.images.top": "observation.images.camera1", "observation.images.gripper": "observation.images.camera2"}'

You must pass this again at inference. The mapping is saved in policy_preprocessor.json, but lerobot-record overwrites it with its own --dataset.rename_map (which defaults to empty) at src/lerobot/scripts/lerobot_record.py:522. Without the flag the policy reports camera1/camera2 as missing features:

--dataset.rename_map='{"observation.images.top": "observation.images.camera1", "observation.images.gripper": "observation.images.camera2"}'

Adjust the left-hand keys if your cameras are named differently.

Configuration

baselerobot/smolvla_base
steps50,000
batch size64
epochs114.4
trainable params~101M of ~451M (VLM backbone frozen)
mixed precisionbf16
chunk_size50
n_action_steps50
vlm_model_nameHuggingFaceTB/SmolVLM2-500M-Video-Instruct
optimizer_lr0.0001
freeze_vision_encoderTrue
n_tactile_tokens4
tactile_feature_dim256

Epoch-matched at ~114.4 epochs with every other model in this series.

Training command actually used

bash
python -u -m lerobot.scripts.lerobot_train \
  --dataset.repo_id=Dimios45/tactile_charger_retagged --dataset.root=/mnt/data/mritunjoyh/data/datasets/tactile_charger_retagged  \
  --policy.path=lerobot/smolvla_base --policy.use_tactile=true --policy.tactile_features='["observation.tactile.primary"]' --policy.n_tactile_tokens=4 \
  --policy.repo_id=Dimios45/smolvla_tactile_charger_50ep \
  --rename_map='{"observation.images.top": "observation.images.camera1", "observation.images.gripper": "observation.images.camera2"}' \
  --policy.private=true --policy.device=cuda \
  --output_dir=outputs/train/F_smolvla_tactile_50 --job_name=F_smolvla_tactile_50 \
  --batch_size=64 --num_workers=8 --steps=50000 --save_freq=10000 --wandb.enable=true

Evaluation / rollout

Not run here (no robot on the training machine). Load with --policy.path=Dimios45/smolvla_tactile_charger_50ep and prompt with the instruction above.

Reference: the lerobot-record eval invocations in `tactile_cmd.txt` and the project docs.

Notes

  • Trained on AMD MI300X (ROCm 6.2.4). cudnn.benchmark must stay off on ROCm or MIOpen runs an exhaustive search before step 1; persistent_workers=True avoids ~410 s stalls at epoch boundaries.
  • Training loss is not a proxy for task success - compare by rollout success rate.