Instructions to use Bigenlight/diffusion_banana_in_pot_ee with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- LeRobot
How to use Bigenlight/diffusion_banana_in_pot_ee with LeRobot:
- Notebooks
- Google Colab
- Kaggle
EE (10-D) diffusion policy 100k + model card
Browse files- README.md +434 -0
- assets/diffusion_ee_openloop_eval.csv +11 -0
- assets/diffusion_ee_overfit_diag.png +0 -0
- config.json +96 -0
- model.safetensors +3 -0
- policy_postprocessor.json +32 -0
- policy_postprocessor_step_0_unnormalizer_processor.safetensors +3 -0
- policy_preprocessor.json +64 -0
- policy_preprocessor_step_3_normalizer_processor.safetensors +3 -0
- train_config.json +193 -0
README.md
ADDED
|
@@ -0,0 +1,434 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: apache-2.0
|
| 3 |
+
library_name: lerobot
|
| 4 |
+
tags:
|
| 5 |
+
- robotics
|
| 6 |
+
- diffusion-policy
|
| 7 |
+
- lerobot
|
| 8 |
+
- manipulation
|
| 9 |
+
- ur7e
|
| 10 |
+
pipeline_tag: robotics
|
| 11 |
+
datasets:
|
| 12 |
+
- Bigenlight/banana_in_pot_lerobot_v3
|
| 13 |
+
---
|
| 14 |
+
|
| 15 |
+
# Diffusion Policy — Put the right banana in the pot (UR7e, END-EFFECTOR action space)
|
| 16 |
+
|
| 17 |
+
A **Diffusion Policy** (visuomotor DDPM, 1D-conv UNet denoiser) trained by imitation
|
| 18 |
+
learning to perform the manipulation task *"put the right banana in the pot"* on a
|
| 19 |
+
**Universal Robots UR7e** arm with two RGB cameras. Actions are **10-D absolute
|
| 20 |
+
end-effector (EE) targets**: `action = [x, y, z (meters), r1..r6 (6-D rotation), grip]`.
|
| 21 |
+
The observation state is likewise **10-D** in the same EE parameterization.
|
| 22 |
+
|
| 23 |
+
- **Policy:** LeRobot `DiffusionPolicy` — per-camera **ResNet18** visual encoder
|
| 24 |
+
(ImageNet-pretrained) + **SpatialSoftmax** keypoints, conditioning a **1D convolutional
|
| 25 |
+
UNet** denoiser. Receding-horizon action generation: `horizon = 64`, `n_obs_steps = 2`,
|
| 26 |
+
`n_action_steps = 32`.
|
| 27 |
+
- **Noise model:** **DDPM**, `num_train_timesteps = 100`, `beta_schedule =
|
| 28 |
+
squaredcos_cap_v2`, `prediction_type = epsilon` (ε-prediction), `clip_sample = true`.
|
| 29 |
+
- **Trained on:** [`Bigenlight/banana_in_pot_lerobot_v3`](https://huggingface.co/datasets/Bigenlight/banana_in_pot_lerobot_v3)
|
| 30 |
+
— 51 teleoperated episodes / 21,524 frames, UR7e follower + GELLO leader, 2 RGB cameras
|
| 31 |
+
(EE-pose action/state variant of the task).
|
| 32 |
+
- **This checkpoint:** step **100,000** — the best of the 80k–100k plateau: 100k has the
|
| 33 |
+
**best gripper accuracy (0.966)** and the **best overall L1**, and its `poseMAE` is tied
|
| 34 |
+
within noise with the 80k minimum (see [Results](#results--the-headline-finding)).
|
| 35 |
+
- **Framework:** [LeRobot](https://github.com/huggingface/lerobot) v0.6.1.
|
| 36 |
+
|
| 37 |
+
> **Headline finding (read this first):** on a held-out split the diffusion **denoising
|
| 38 |
+
> `eval_loss` ROSE ~4.5× (0.0250 @8k → 0.112 @100k)**, and LeRobot's auto-report flags this
|
| 39 |
+
> as "overfit from ~8k". That verdict is **misleading**. The deployment-relevant **open-loop
|
| 40 |
+
> rollout MAE kept IMPROVING then plateaued** (poseMAE 0.0665 → ~0.0368; gripAcc → 0.966) —
|
| 41 |
+
> **no destructive overfit through 100k.** **For a Diffusion Policy the held-out denoising
|
| 42 |
+
> loss is a misleading overfit/early-stop signal — select checkpoints by open-loop MAE, not
|
| 43 |
+
> by `eval_loss`.** (Exactly the lesson from the [JOINT sibling](https://huggingface.co/Bigenlight/diffusion_banana_in_pot_joint).)
|
| 44 |
+
|
| 45 |
+
---
|
| 46 |
+
|
| 47 |
+
## Task & data
|
| 48 |
+
|
| 49 |
+
**"put the right banana in the pot."** The tabletop holds several distractor objects —
|
| 50 |
+
**two bananas, an apple, carrots/peppers, and a slice of watermelon** — plus a **silver
|
| 51 |
+
pot**. The operator must grasp the **RIGHT banana** (the target) and place it inside the
|
| 52 |
+
pot. Success = the right banana ends up inside the pot. Every demonstration is a success.
|
| 53 |
+
|
| 54 |
+
- **Dataset:** [`Bigenlight/banana_in_pot_lerobot_v3`](https://huggingface.co/datasets/Bigenlight/banana_in_pot_lerobot_v3)
|
| 55 |
+
(LeRobot v3.0 format).
|
| 56 |
+
- **Scale:** **51 episodes / 21,524 frames / 30 fps / ~12 min.**
|
| 57 |
+
- **Action / state space:** 10-D absolute end-effector pose,
|
| 58 |
+
`[x, y, z (meters), r1..r6 (6-D rotation, unitless), grip]`. The gripper channel is
|
| 59 |
+
effectively binary (open/close). This is the **EE** variant; the sibling model uses a
|
| 60 |
+
7-D joint action instead.
|
| 61 |
+
- **Cameras:** two RGB viewpoints (Intel RealSense D435 + D435if), captured at 1280×720
|
| 62 |
+
(720p) @ 30 fps, **RGB only** (no depth / IR). `cam1 ↔ cam2` order is fixed and must be
|
| 63 |
+
preserved at deploy time.
|
| 64 |
+
|
| 65 |
+
### Train / held-out split
|
| 66 |
+
|
| 67 |
+
Training holds out the **LAST 6 episodes (indices 45–50)** as a true validation split and
|
| 68 |
+
trains on the other **45** episodes (0–44). The held-out episodes 45–50 are used both for
|
| 69 |
+
the in-training denoising `eval_loss` probe and for all offline open-loop evaluation below.
|
| 70 |
+
|
| 71 |
+
---
|
| 72 |
+
|
| 73 |
+
## Model architecture
|
| 74 |
+
|
| 75 |
+
LeRobot `DiffusionPolicy`. All values below are quoted directly from the checkpoint's
|
| 76 |
+
`config.json`. The architecture is **identical to the JOINT sibling** except that the first
|
| 77 |
+
(state) and last (action) layers are 10-D instead of 7-D.
|
| 78 |
+
|
| 79 |
+
**Observation encoder (vision):**
|
| 80 |
+
|
| 81 |
+
| Item | Value |
|
| 82 |
+
|---|---|
|
| 83 |
+
| Vision backbone | `resnet18` |
|
| 84 |
+
| Pretrained weights | `ResNet18_Weights.IMAGENET1K_V1` (ImageNet) |
|
| 85 |
+
| Per-camera encoder | `use_separate_rgb_encoder_per_camera = true` (separate ResNet18 per view) |
|
| 86 |
+
| Pooling | **SpatialSoftmax**, `spatial_softmax_num_keypoints = 32` |
|
| 87 |
+
| Group norm in encoder | `use_group_norm = false` (keeps BatchNorm from the pretrained backbone) |
|
| 88 |
+
| Cameras | 2 × RGB (`observation.images.cam1`, `observation.images.cam2`) |
|
| 89 |
+
| Network input resolution | **360 × 640** (`resize_shape = [360, 640]`; see [why](#why-the-two-non-default-flags-are-required)) |
|
| 90 |
+
| Crop | **OFF** — `crop_shape = null`, `crop_ratio = 1.0` (`crop_is_random` is moot with no crop) |
|
| 91 |
+
| State input | `observation.state`, shape `(10,)` |
|
| 92 |
+
|
| 93 |
+
> Note: `config.json` records the raw dataset image feature shape as `[3, 720, 1280]`, but
|
| 94 |
+
> the on-the-fly `Resize` to `[360, 640]` (`resize_shape`) means the network actually sees
|
| 95 |
+
> **360 × 640** frames. See the training section for why this must match at inference.
|
| 96 |
+
|
| 97 |
+
**Denoiser (conditional 1D-conv UNet):**
|
| 98 |
+
|
| 99 |
+
| Item | Value |
|
| 100 |
+
|---|---|
|
| 101 |
+
| Denoiser | 1D convolutional UNet (Diffusion Policy / Janner-style) |
|
| 102 |
+
| `down_dims` | `[512, 1024, 2048]` |
|
| 103 |
+
| `kernel_size` | `5` |
|
| 104 |
+
| `n_groups` (GroupNorm) | `8` |
|
| 105 |
+
| `diffusion_step_embed_dim` | `128` |
|
| 106 |
+
| FiLM conditioning | `use_film_scale_modulation = true` |
|
| 107 |
+
| `horizon` | `64` (prediction horizon, in frames) |
|
| 108 |
+
| `n_obs_steps` | `2` (observation context length) |
|
| 109 |
+
| `n_action_steps` | `32` (actions executed before replanning) |
|
| 110 |
+
|
| 111 |
+
> **Conditioning dimension (EE-specific):** each observation contributes
|
| 112 |
+
> `state 10 + vision 128 = 138-D` (per-camera ResNet18 → 64-D, two cameras → 128-D); with
|
| 113 |
+
> `n_obs_steps = 2` the UNet `global_cond` is **276-D** (the JOINT model's is 270-D). This
|
| 114 |
+
> 6-D difference is the only structural change from the JOINT config.
|
| 115 |
+
|
| 116 |
+
**Diffusion process (noise scheduler):**
|
| 117 |
+
|
| 118 |
+
| Item | Value |
|
| 119 |
+
|---|---|
|
| 120 |
+
| `noise_scheduler_type` | `DDPM` |
|
| 121 |
+
| `num_train_timesteps` | `100` |
|
| 122 |
+
| `beta_schedule` | `squaredcos_cap_v2` (cosine) |
|
| 123 |
+
| `beta_start` / `beta_end` | `0.0001` / `0.02` |
|
| 124 |
+
| `prediction_type` | `epsilon` (predict noise) |
|
| 125 |
+
| `clip_sample` | `true`, `clip_sample_range = 1.0` |
|
| 126 |
+
| `num_inference_steps` | `null` in config → defaults to the full DDPM schedule at inference unless overridden (evals here used **DDIM, 10 steps** for speed — see [Usage](#usage--inference)) |
|
| 127 |
+
|
| 128 |
+
**Normalization (`normalization_mapping`):**
|
| 129 |
+
|
| 130 |
+
| Feature group | Mode |
|
| 131 |
+
|---|---|
|
| 132 |
+
| `VISUAL` (images) | `MEAN_STD` (ImageNet stats, `use_imagenet_stats = true`) |
|
| 133 |
+
| `STATE` (observation.state) | `MIN_MAX` |
|
| 134 |
+
| `ACTION` (action) | `MIN_MAX` |
|
| 135 |
+
|
| 136 |
+
Normalizer statistics are baked into the pre/post-processor pipelines saved alongside the
|
| 137 |
+
checkpoint (`policy_preprocessor.json` / `policy_postprocessor.json`), not into
|
| 138 |
+
`forward()`.
|
| 139 |
+
|
| 140 |
+
**I/O summary:**
|
| 141 |
+
|
| 142 |
+
| I/O | Spec |
|
| 143 |
+
|---|---|
|
| 144 |
+
| `observation.state` | `(10,)` — `[x, y, z (m), r1..r6 (6-D rotation), grip]` |
|
| 145 |
+
| `observation.images.cam1` / `cam2` | RGB, network input **360 × 640** |
|
| 146 |
+
| `action` | `(10,)` — `[x, y, z (m), r1..r6 (6-D rotation), grip]`, **absolute** EE pose + ~binary gripper |
|
| 147 |
+
|
| 148 |
+
**Size:** ~**277.9M** parameters, fp32 ~**1.11 GB** — effectively identical to the JOINT
|
| 149 |
+
model (they differ only by the 3-D width of the first and last layers).
|
| 150 |
+
|
| 151 |
+
---
|
| 152 |
+
|
| 153 |
+
## Training setup
|
| 154 |
+
|
| 155 |
+
Trained with `lerobot-train` (LeRobot 0.6.1). Values below are from the saved training
|
| 156 |
+
config; hyperparameters match the JOINT run.
|
| 157 |
+
|
| 158 |
+
| Item | Value |
|
| 159 |
+
|---|---|
|
| 160 |
+
| Policy | `diffusion` (`--policy.type=diffusion`) |
|
| 161 |
+
| Dataset | `banana_in_pot_lerobot_v3` (EE action/state), holds out eps 45–50 |
|
| 162 |
+
| Batch size | **8** |
|
| 163 |
+
| Steps | **100,000**; checkpoints saved every 10,000 |
|
| 164 |
+
| Optimizer | **Adam**, `lr = 1e-4`, `betas = [0.95, 0.999]`, `eps = 1e-8`, `weight_decay = 1e-6` |
|
| 165 |
+
| LR scheduler | **cosine** (`scheduler_name = cosine`), `num_warmup_steps = 500` |
|
| 166 |
+
| Precision | **fp32** (`use_amp = false`) |
|
| 167 |
+
| EMA | **none** (no EMA weights in this config) |
|
| 168 |
+
| Image transform | on-the-fly `Resize` to `[360, 640]`, deterministic |
|
| 169 |
+
| `drop_n_last_frames` | **31** (non-default; see below) |
|
| 170 |
+
| `resize_shape` | `[360, 640]` (non-default; see below) |
|
| 171 |
+
| Control rate | dataset 30 fps, consecutive frames (step = 1) — no downsampling. obs 2 frames (~0.067 s) / horizon 64 (2.13 s) / exec 32 (1.07 s) @ 30 Hz |
|
| 172 |
+
| Eval probe | held-out denoising `eval_loss`; open-loop rollouts run offline per checkpoint |
|
| 173 |
+
|
| 174 |
+
### Why the two non-default flags are required
|
| 175 |
+
|
| 176 |
+
Both `resize_shape=[360,640]` and `drop_n_last_frames=31` are **not** the LeRobot defaults;
|
| 177 |
+
they are mandatory for this dataset/config and encode real operational knowledge:
|
| 178 |
+
|
| 179 |
+
1. **`resize_shape=[360,640]` — SpatialSoftmax is shape-rigid.** The Diffusion Policy RGB
|
| 180 |
+
encoder ends in a `SpatialSoftmax` layer whose keypoint geometry is fixed to the spatial
|
| 181 |
+
dimensions of the feature map at build time. The network must therefore be *constructed*
|
| 182 |
+
for the exact input resolution it will ever see. Setting `resize_shape=[360,640]` builds
|
| 183 |
+
the encoder for 360×640 and — combined with crop being **off** (`crop_shape=null`) —
|
| 184 |
+
guarantees the training image path, the offline-eval image path, and any deploy image
|
| 185 |
+
path all feed the encoder identically. A mismatched resolution (or leaving crop on)
|
| 186 |
+
changes the SpatialSoftmax grid and breaks the model.
|
| 187 |
+
|
| 188 |
+
2. **`drop_n_last_frames=31` — horizon / n_action off-by-one at episode ends.** The
|
| 189 |
+
trajectory sampler must not draw a window that runs past the end of an episode. With
|
| 190 |
+
`horizon=64`, `n_obs_steps=2`, and `n_action_steps=32`, the correct number of trailing
|
| 191 |
+
frames to drop is `horizon - n_action_steps - (n_obs_steps - 1) = 64 - 32 - 1 = 31`.
|
| 192 |
+
Using the default (7, tuned for the reference `horizon=16` config) would let the sampler
|
| 193 |
+
pull frames off the end of an episode and corrupt the action targets. **If you change
|
| 194 |
+
`horizon`/`n_obs_steps`/`n_action_steps`, recompute `drop_n_last_frames`.**
|
| 195 |
+
|
| 196 |
+
---
|
| 197 |
+
|
| 198 |
+
## Results & the headline finding
|
| 199 |
+
|
| 200 |
+

|
| 201 |
+
|
| 202 |
+
Offline **open-loop** evaluation on the held-out episodes **45–50** with `eval_offline.py`
|
| 203 |
+
(each logged observation is fed to `select_action`; the predicted action is compared to the
|
| 204 |
+
dataset ground truth). Sampling used **DDIM with 10 inference steps**
|
| 205 |
+
(`--scheduler DDIM --num-inference-steps 10`) for ~10× faster rollouts; DDIM is a valid
|
| 206 |
+
sampler for a DDPM-trained ε model (same beta schedule). `poseMAE` is the mean absolute
|
| 207 |
+
error over the first 9 pose dims; `gripAcc` is the binary gripper-open/close accuracy
|
| 208 |
+
(threshold 0.5); `overall L1` averages all 10 dims. Numbers persisted at
|
| 209 |
+
[`assets/diffusion_ee_openloop_eval.csv`](assets/diffusion_ee_openloop_eval.csv).
|
| 210 |
+
|
| 211 |
+
| checkpoint | poseMAE (own scale ↓) | gripAcc ↑ | overall L1 ↓ |
|
| 212 |
+
|---|---|---|---|
|
| 213 |
+
| 10k | 0.06648 | 0.886 | 0.07517 |
|
| 214 |
+
| 20k | 0.04499 | 0.923 | 0.05031 |
|
| 215 |
+
| 30k | 0.04345 | 0.930 | 0.04839 |
|
| 216 |
+
| 40k | 0.03999 | 0.926 | 0.04440 |
|
| 217 |
+
| 50k | 0.03786 | 0.942 | 0.04126 |
|
| 218 |
+
| 60k | 0.03900 | 0.950 | 0.04131 |
|
| 219 |
+
| 70k | 0.03687 | 0.956 | 0.03846 |
|
| 220 |
+
| 80k | **0.03674** ⟵ poseMAE min | 0.961 | 0.03773 |
|
| 221 |
+
| 90k | 0.03718 | 0.955 | 0.03856 |
|
| 222 |
+
| **100k** ⭐ | 0.03717 | **0.966** ⟵ max | **0.03754** ⟵ min |
|
| 223 |
+
|
| 224 |
+
> **Units caveat — do NOT compare `poseMAE` across the two models.** The EE `poseMAE`
|
| 225 |
+
> mixes **meters** (x, y, z) with **6-D rotation** (unitless) channels, so it is on a
|
| 226 |
+
> completely different scale from the JOINT model's **radian** `poseMAE` (0.0845). The two
|
| 227 |
+
> numbers are not comparable — judge the EE model **only** by its own trend.
|
| 228 |
+
|
| 229 |
+
**Best checkpoint = the 80k–100k plateau.** `poseMAE` falls 0.0665 → ~0.0368 and then
|
| 230 |
+
flattens from ~70k (70k/80k/90k/100k all within ±0.0004 = eval noise); its strict minimum is
|
| 231 |
+
**0.03674 @ 80k**. `gripAcc` rises essentially monotonically to **0.966 @ 100k**;
|
| 232 |
+
`overall L1` is lowest at **100k (0.03754)**. There is **no open-loop overfitting through
|
| 233 |
+
100k**. We upload **100k** because it gives the best gripper and best overall L1 while its
|
| 234 |
+
`poseMAE` is tied within noise with the 80k minimum — deploy 100k is safe and strictly
|
| 235 |
+
best-gripper. (Pick 80k if you want the strict `poseMAE` minimum; both sit on the plateau.)
|
| 236 |
+
|
| 237 |
+
### The misleading `eval_loss` (the lesson)
|
| 238 |
+
|
| 239 |
+
During training the held-out **denoising `eval_loss`** (LeRobot's in-training validation
|
| 240 |
+
probe, computed under `policy.eval()` on eps 45–50) did the *opposite* of the rollout
|
| 241 |
+
metric:
|
| 242 |
+
|
| 243 |
+
| step | held-out eval_loss |
|
| 244 |
+
|---|---|
|
| 245 |
+
| 2k | 0.0331 |
|
| 246 |
+
| **8k** | **0.0250** (min) |
|
| 247 |
+
| 100k | 0.112 (~4.5× above the min) |
|
| 248 |
+
|
| 249 |
+
Read naively, the held-out `eval_loss` bottoms at **step 8k** and then rises ~4.5×, and
|
| 250 |
+
LeRobot's auto-report calls it **"overfit from ~8k"**. **That verdict is wrong for
|
| 251 |
+
deployment:** the same held-out episodes, evaluated by open-loop rollout, get
|
| 252 |
+
*monotonically better* out to the 70k–100k plateau.
|
| 253 |
+
|
| 254 |
+
**Why the two signals disagree:** a diffusion policy is trained to predict the noise added
|
| 255 |
+
at a **random** timestep, and `eval_loss` scores exactly that random-timestep
|
| 256 |
+
noise-prediction on held-out frames — so it is (a) high-variance/stochastic by construction
|
| 257 |
+
and (b) only loosely coupled to closed-loop action quality. But what drives the robot is the
|
| 258 |
+
**sampled action** — the *integral* of the full reverse-diffusion trajectory (here DDIM-10).
|
| 259 |
+
Those two quantities decorrelate: the network can get "worse" at random-timestep denoising
|
| 260 |
+
MSE while the *sampled* action trajectory keeps getting **closer** to ground truth. **The
|
| 261 |
+
only faithful held-out metric is to actually sample actions and compare them open-loop**,
|
| 262 |
+
which is what `eval_offline.py` does. **Takeaway: for a Diffusion Policy, select checkpoints
|
| 263 |
+
and early-stop by open-loop rollout MAE, not by held-out denoising `eval_loss`.** (The ACT
|
| 264 |
+
sibling did not show this divergence — there the two signals agreed — so this is a
|
| 265 |
+
diffusion-specific pitfall, reconfirmed here on the EE action space.)
|
| 266 |
+
|
| 267 |
+
---
|
| 268 |
+
|
| 269 |
+
## Deployment note — research artifact, NOT wired to the robot
|
| 270 |
+
|
| 271 |
+
**Read this before trying to run the model on hardware.** Unlike the JOINT sibling — whose
|
| 272 |
+
7-D joint actions are **directly actuatable** and which is deployed on the real UR7e via the
|
| 273 |
+
[`Bigenlight/gello_software`](https://github.com/Bigenlight/gello_software) ROS 2 stack —
|
| 274 |
+
this EE model outputs **10-D end-effector poses** (`[x, y, z, r1..r6, grip]`). Those poses
|
| 275 |
+
must be converted to joint commands by **inverse kinematics (IK)** before they can drive the
|
| 276 |
+
arm.
|
| 277 |
+
|
| 278 |
+
**There is no IK deploy path in the current stack.** Accordingly this checkpoint is uploaded
|
| 279 |
+
as a **research artifact / reference for the EE action space**, **NOT** wired for
|
| 280 |
+
real-robot inference. It was **never run on the arm** and there are **no closed-loop
|
| 281 |
+
task-success results** for it.
|
| 282 |
+
|
| 283 |
+
For the actuatable path, use:
|
| 284 |
+
|
| 285 |
+
- the **JOINT model** [`Bigenlight/diffusion_banana_in_pot_joint`](https://huggingface.co/Bigenlight/diffusion_banana_in_pot_joint)
|
| 286 |
+
(7-D joint actions, directly commandable), and
|
| 287 |
+
- the **diffusion deploy node** in
|
| 288 |
+
[`Bigenlight/gello_software`](https://github.com/Bigenlight/gello_software) (ROS 2 Humble,
|
| 289 |
+
UR7e follower, dual RealSense) used to run the JOINT policy.
|
| 290 |
+
|
| 291 |
+
To deploy *this* EE model you would additionally have to add an IK stage (EE pose → joint
|
| 292 |
+
targets, with reachability/limit handling) after `select_action` — that work is out of scope
|
| 293 |
+
for this release.
|
| 294 |
+
|
| 295 |
+
---
|
| 296 |
+
|
| 297 |
+
## Usage / inference
|
| 298 |
+
|
| 299 |
+
The snippet below loads the policy and produces a 10-D EE action. **Note:** that action is
|
| 300 |
+
an end-effector pose — it needs **IK** before it can drive a robot (see the deployment note
|
| 301 |
+
above).
|
| 302 |
+
|
| 303 |
+
### Load the policy (LeRobot 0.6.1)
|
| 304 |
+
|
| 305 |
+
Normalization is **not** baked into `forward()` in LeRobot 0.6.1 — it lives in the
|
| 306 |
+
pre/post-processor pipelines saved with the checkpoint. `select_action` returns a
|
| 307 |
+
**normalized** action; the post-processor converts it back to the EE units.
|
| 308 |
+
|
| 309 |
+
```python
|
| 310 |
+
import torch
|
| 311 |
+
from lerobot.configs import PreTrainedConfig
|
| 312 |
+
from lerobot.policies.factory import get_policy_class, make_pre_post_processors
|
| 313 |
+
|
| 314 |
+
CKPT = "Bigenlight/diffusion_banana_in_pot_ee"
|
| 315 |
+
device = "cuda"
|
| 316 |
+
|
| 317 |
+
# (optional) speed up sampling: DDIM with 10 steps instead of the full DDPM schedule.
|
| 318 |
+
# Mutate the config BEFORE from_pretrained so the sampler is built with these settings.
|
| 319 |
+
cfg = PreTrainedConfig.from_pretrained(CKPT)
|
| 320 |
+
cfg.pretrained_path = CKPT
|
| 321 |
+
cfg.device = device
|
| 322 |
+
cfg.noise_scheduler_type = "DDIM" # valid sampler for a DDPM-trained epsilon model
|
| 323 |
+
cfg.num_inference_steps = 10 # ~10x faster rollouts
|
| 324 |
+
|
| 325 |
+
policy = get_policy_class(cfg.type).from_pretrained(CKPT, config=cfg) # -> DiffusionPolicy
|
| 326 |
+
policy.to(device)
|
| 327 |
+
policy.eval()
|
| 328 |
+
|
| 329 |
+
preprocessor, postprocessor = make_pre_post_processors(
|
| 330 |
+
policy_cfg=cfg,
|
| 331 |
+
pretrained_path=CKPT,
|
| 332 |
+
preprocessor_overrides={"device_processor": {"device": device}},
|
| 333 |
+
)
|
| 334 |
+
```
|
| 335 |
+
|
| 336 |
+
### Produce actions
|
| 337 |
+
|
| 338 |
+
Build the observation dict exactly as training did: EE state `(10,)` plus **both** cameras
|
| 339 |
+
as RGB CHW tensors in `[0, 1]`, **resized to 360×640** (aspect-preserving half-resolution).
|
| 340 |
+
`cam1`/`cam2` must map to the same physical viewpoints as at collection.
|
| 341 |
+
|
| 342 |
+
```python
|
| 343 |
+
policy.reset() # once at the start of each episode/rollout
|
| 344 |
+
preprocessor.reset()
|
| 345 |
+
postprocessor.reset()
|
| 346 |
+
|
| 347 |
+
# obs = {
|
| 348 |
+
# "observation.state": state_10, # (10,) float32: [x,y,z, r1..r6, grip]
|
| 349 |
+
# "observation.images.cam1": img1_chw, # (3, 360, 640) float32 in [0,1]
|
| 350 |
+
# "observation.images.cam2": img2_chw, # (3, 360, 640) float32 in [0,1]
|
| 351 |
+
# "task": "put the right banana in the pot",
|
| 352 |
+
# }
|
| 353 |
+
|
| 354 |
+
with torch.inference_mode():
|
| 355 |
+
proc = preprocessor(obs) # rename -> add batch dim -> device -> normalize
|
| 356 |
+
action = policy.select_action(proc) # (1, 10) NORMALIZED
|
| 357 |
+
action = postprocessor(action) # (1, 10) EE units, on cpu
|
| 358 |
+
ee_target = action.squeeze(0).numpy() # (10,) -> [x, y, z, r1..r6, grip]
|
| 359 |
+
# NOTE: ee_target is an END-EFFECTOR POSE. To drive a robot you must first run IK
|
| 360 |
+
# (ee_target[:9] -> joint targets); no IK deploy path ships with this model.
|
| 361 |
+
```
|
| 362 |
+
|
| 363 |
+
`select_action` returns **one** action per call from an internal queue. Because
|
| 364 |
+
`n_action_steps = 32`, the policy denoises a fresh action sequence, executes 32 actions
|
| 365 |
+
from it, then replans (with `n_obs_steps = 2` frames of observation context). Call
|
| 366 |
+
`policy.reset()` at the start of every episode to clear that queue. The gripper channel
|
| 367 |
+
`grip` is ~binary — threshold at `> 0.5 → close`.
|
| 368 |
+
|
| 369 |
+
### Reproduce the offline evaluation
|
| 370 |
+
|
| 371 |
+
The repo's `eval_offline.py` runs the exact open-loop protocol used for the results table
|
| 372 |
+
(same 360×640 `Resize`, same normalization via the saved processors):
|
| 373 |
+
|
| 374 |
+
```bash
|
| 375 |
+
python eval_offline.py \
|
| 376 |
+
--checkpoint outputs/train/diffusion_ee_val_diag/checkpoints/100000/pretrained_model \
|
| 377 |
+
--episodes 45,46,47,48,49,50 \
|
| 378 |
+
--device cuda \
|
| 379 |
+
--scheduler DDIM --num-inference-steps 10 \
|
| 380 |
+
--out eval_out_diffusion_ee_100k
|
| 381 |
+
```
|
| 382 |
+
|
| 383 |
+
`--scheduler DDIM --num-inference-steps 10` gives the ~10× rollout speedup; omit them to
|
| 384 |
+
sample with the full trained DDPM schedule (`num_train_timesteps = 100`).
|
| 385 |
+
|
| 386 |
+
---
|
| 387 |
+
|
| 388 |
+
## Limitations & intended use
|
| 389 |
+
|
| 390 |
+
- **Research artifact only — not deployable as-is.** The 10-D EE action requires IK to
|
| 391 |
+
actuate and there is **no IK deploy path** in the stack, so this model was **never run on
|
| 392 |
+
hardware** and has **no closed-loop success rate**. For a directly actuatable, deployed
|
| 393 |
+
policy use the [JOINT sibling](https://huggingface.co/Bigenlight/diffusion_banana_in_pot_joint).
|
| 394 |
+
- **Small, single-task lab dataset:** 51 demonstrations, one scene layout, one operator.
|
| 395 |
+
Expect limited generalization to novel object arrangements, lighting, or camera placement.
|
| 396 |
+
- **Success-only demonstrations:** no failure/recovery data; not suited as-is for methods
|
| 397 |
+
that need negative examples.
|
| 398 |
+
- **Offline metrics only:** the best checkpoint (100k) reaches **held-out poseMAE ≈ 0.0372**
|
| 399 |
+
(EE's own mixed-unit scale) and gripper accuracy ≈ 0.966 in open-loop rollout. These are
|
| 400 |
+
*not* closed-loop task success rates, and the EE `poseMAE` is **not comparable** to the
|
| 401 |
+
JOINT model's radian `poseMAE`.
|
| 402 |
+
- **Absolute EE action space:** the policy was only ever conditioned on states near the
|
| 403 |
+
data-collection start pose; any real deployment would additionally need reachability /
|
| 404 |
+
joint-limit handling in the IK stage plus the safety guards used for the JOINT model.
|
| 405 |
+
- **Not for production.** Intended for research in imitation learning / diffusion policies
|
| 406 |
+
for robot manipulation. Workspace-, robot-, and camera-specific.
|
| 407 |
+
- The ResNet18 encoders are **ImageNet-pretrained** (not robotics-pretrained); the UNet
|
| 408 |
+
denoiser is trained from scratch on this task.
|
| 409 |
+
|
| 410 |
+
---
|
| 411 |
+
|
| 412 |
+
## Links
|
| 413 |
+
|
| 414 |
+
- **Dataset:** [`Bigenlight/banana_in_pot_lerobot_v3`](https://huggingface.co/datasets/Bigenlight/banana_in_pot_lerobot_v3)
|
| 415 |
+
- **JOINT sibling model (deployed, actuatable):** [`Bigenlight/diffusion_banana_in_pot_joint`](https://huggingface.co/Bigenlight/diffusion_banana_in_pot_joint)
|
| 416 |
+
- **Experiments repo:** [github.com/Bigenlight/banana-in-pot-experiments](https://github.com/Bigenlight/banana-in-pot-experiments)
|
| 417 |
+
- **Deployment stack (ROS 2 Humble, JOINT path):** [github.com/Bigenlight/gello_software](https://github.com/Bigenlight/gello_software)
|
| 418 |
+
- **Framework:** [LeRobot](https://github.com/huggingface/lerobot) v0.6.1
|
| 419 |
+
|
| 420 |
+
## Citation
|
| 421 |
+
|
| 422 |
+
```bibtex
|
| 423 |
+
@misc{theo2026bananainpotdiffusionee,
|
| 424 |
+
title = {Diffusion Policy for "put the right banana in the pot"
|
| 425 |
+
(UR7e, end-effector action space)},
|
| 426 |
+
author = {Theo and {Bigenlight}},
|
| 427 |
+
year = {2026},
|
| 428 |
+
howpublished = {\url{https://huggingface.co/Bigenlight/diffusion_banana_in_pot_ee}},
|
| 429 |
+
note = {LeRobot 0.6.1 DiffusionPolicy, 10-D EE action, trained on
|
| 430 |
+
banana_in_pot_lerobot_v3; research artifact (needs IK to actuate)}
|
| 431 |
+
}
|
| 432 |
+
```
|
| 433 |
+
|
| 434 |
+
License: **Apache-2.0**.
|
assets/diffusion_ee_openloop_eval.csv
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
checkpoint,poseMAE,poseRMSE,gripMAE,gripAcc,overallL1
|
| 2 |
+
010000,0.06648,0.09027,0.15344,0.886,0.07517
|
| 3 |
+
020000,0.04499,0.06286,0.09818,0.923,0.05031
|
| 4 |
+
030000,0.04345,0.06098,0.09293,0.930,0.04839
|
| 5 |
+
040000,0.03999,0.05790,0.08407,0.926,0.04440
|
| 6 |
+
050000,0.03786,0.05553,0.07187,0.942,0.04126
|
| 7 |
+
060000,0.03900,0.05898,0.06212,0.950,0.04131
|
| 8 |
+
070000,0.03687,0.05557,0.05277,0.956,0.03846
|
| 9 |
+
080000,0.03674,0.05562,0.04661,0.961,0.03773
|
| 10 |
+
090000,0.03718,0.05588,0.05097,0.955,0.03856
|
| 11 |
+
100000,0.03717,0.05594,0.04091,0.966,0.03754
|
assets/diffusion_ee_overfit_diag.png
ADDED
|
config.json
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"type": "diffusion",
|
| 3 |
+
"n_obs_steps": 2,
|
| 4 |
+
"input_features": {
|
| 5 |
+
"observation.state": {
|
| 6 |
+
"type": "STATE",
|
| 7 |
+
"shape": [
|
| 8 |
+
10
|
| 9 |
+
]
|
| 10 |
+
},
|
| 11 |
+
"observation.images.cam1": {
|
| 12 |
+
"type": "VISUAL",
|
| 13 |
+
"shape": [
|
| 14 |
+
3,
|
| 15 |
+
720,
|
| 16 |
+
1280
|
| 17 |
+
]
|
| 18 |
+
},
|
| 19 |
+
"observation.images.cam2": {
|
| 20 |
+
"type": "VISUAL",
|
| 21 |
+
"shape": [
|
| 22 |
+
3,
|
| 23 |
+
720,
|
| 24 |
+
1280
|
| 25 |
+
]
|
| 26 |
+
}
|
| 27 |
+
},
|
| 28 |
+
"output_features": {
|
| 29 |
+
"action": {
|
| 30 |
+
"type": "ACTION",
|
| 31 |
+
"shape": [
|
| 32 |
+
10
|
| 33 |
+
]
|
| 34 |
+
}
|
| 35 |
+
},
|
| 36 |
+
"device": "cuda",
|
| 37 |
+
"use_amp": false,
|
| 38 |
+
"use_peft": false,
|
| 39 |
+
"push_to_hub": false,
|
| 40 |
+
"repo_id": null,
|
| 41 |
+
"private": null,
|
| 42 |
+
"tags": null,
|
| 43 |
+
"license": null,
|
| 44 |
+
"pretrained_path": null,
|
| 45 |
+
"pretrained_revision": null,
|
| 46 |
+
"horizon": 64,
|
| 47 |
+
"n_action_steps": 32,
|
| 48 |
+
"normalization_mapping": {
|
| 49 |
+
"VISUAL": "MEAN_STD",
|
| 50 |
+
"STATE": "MIN_MAX",
|
| 51 |
+
"ACTION": "MIN_MAX"
|
| 52 |
+
},
|
| 53 |
+
"drop_n_last_frames": 31,
|
| 54 |
+
"vision_backbone": "resnet18",
|
| 55 |
+
"resize_shape": [
|
| 56 |
+
360,
|
| 57 |
+
640
|
| 58 |
+
],
|
| 59 |
+
"crop_ratio": 1.0,
|
| 60 |
+
"crop_shape": null,
|
| 61 |
+
"crop_is_random": true,
|
| 62 |
+
"pretrained_backbone_weights": "ResNet18_Weights.IMAGENET1K_V1",
|
| 63 |
+
"use_group_norm": false,
|
| 64 |
+
"spatial_softmax_num_keypoints": 32,
|
| 65 |
+
"use_separate_rgb_encoder_per_camera": true,
|
| 66 |
+
"down_dims": [
|
| 67 |
+
512,
|
| 68 |
+
1024,
|
| 69 |
+
2048
|
| 70 |
+
],
|
| 71 |
+
"kernel_size": 5,
|
| 72 |
+
"n_groups": 8,
|
| 73 |
+
"diffusion_step_embed_dim": 128,
|
| 74 |
+
"use_film_scale_modulation": true,
|
| 75 |
+
"noise_scheduler_type": "DDPM",
|
| 76 |
+
"num_train_timesteps": 100,
|
| 77 |
+
"beta_schedule": "squaredcos_cap_v2",
|
| 78 |
+
"beta_start": 0.0001,
|
| 79 |
+
"beta_end": 0.02,
|
| 80 |
+
"prediction_type": "epsilon",
|
| 81 |
+
"clip_sample": true,
|
| 82 |
+
"clip_sample_range": 1.0,
|
| 83 |
+
"num_inference_steps": null,
|
| 84 |
+
"compile_model": false,
|
| 85 |
+
"compile_mode": "reduce-overhead",
|
| 86 |
+
"do_mask_loss_for_padding": false,
|
| 87 |
+
"optimizer_lr": 0.0001,
|
| 88 |
+
"optimizer_betas": [
|
| 89 |
+
0.95,
|
| 90 |
+
0.999
|
| 91 |
+
],
|
| 92 |
+
"optimizer_eps": 1e-08,
|
| 93 |
+
"optimizer_weight_decay": 1e-06,
|
| 94 |
+
"scheduler_name": "cosine",
|
| 95 |
+
"scheduler_warmup_steps": 500
|
| 96 |
+
}
|
model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:5af316015d01d153d44adc39be42a5af810e9952d70bb7aae38314eb8686c3ad
|
| 3 |
+
size 1112382512
|
policy_postprocessor.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "policy_postprocessor",
|
| 3 |
+
"steps": [
|
| 4 |
+
{
|
| 5 |
+
"registry_name": "unnormalizer_processor",
|
| 6 |
+
"config": {
|
| 7 |
+
"eps": 1e-08,
|
| 8 |
+
"features": {
|
| 9 |
+
"action": {
|
| 10 |
+
"type": "ACTION",
|
| 11 |
+
"shape": [
|
| 12 |
+
10
|
| 13 |
+
]
|
| 14 |
+
}
|
| 15 |
+
},
|
| 16 |
+
"norm_map": {
|
| 17 |
+
"VISUAL": "MEAN_STD",
|
| 18 |
+
"STATE": "MIN_MAX",
|
| 19 |
+
"ACTION": "MIN_MAX"
|
| 20 |
+
}
|
| 21 |
+
},
|
| 22 |
+
"state_file": "policy_postprocessor_step_0_unnormalizer_processor.safetensors"
|
| 23 |
+
},
|
| 24 |
+
{
|
| 25 |
+
"registry_name": "device_processor",
|
| 26 |
+
"config": {
|
| 27 |
+
"device": "cpu",
|
| 28 |
+
"float_dtype": null
|
| 29 |
+
}
|
| 30 |
+
}
|
| 31 |
+
]
|
| 32 |
+
}
|
policy_postprocessor_step_0_unnormalizer_processor.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:4ed85be0c5507baa295f108acc29cf024b0cd82bc3eae6fca036e3fc53175b17
|
| 3 |
+
size 7888
|
policy_preprocessor.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "policy_preprocessor",
|
| 3 |
+
"steps": [
|
| 4 |
+
{
|
| 5 |
+
"registry_name": "rename_observations_processor",
|
| 6 |
+
"config": {
|
| 7 |
+
"rename_map": {}
|
| 8 |
+
}
|
| 9 |
+
},
|
| 10 |
+
{
|
| 11 |
+
"registry_name": "to_batch_processor",
|
| 12 |
+
"config": {}
|
| 13 |
+
},
|
| 14 |
+
{
|
| 15 |
+
"registry_name": "device_processor",
|
| 16 |
+
"config": {
|
| 17 |
+
"device": "cuda",
|
| 18 |
+
"float_dtype": null
|
| 19 |
+
}
|
| 20 |
+
},
|
| 21 |
+
{
|
| 22 |
+
"registry_name": "normalizer_processor",
|
| 23 |
+
"config": {
|
| 24 |
+
"eps": 1e-08,
|
| 25 |
+
"features": {
|
| 26 |
+
"observation.state": {
|
| 27 |
+
"type": "STATE",
|
| 28 |
+
"shape": [
|
| 29 |
+
10
|
| 30 |
+
]
|
| 31 |
+
},
|
| 32 |
+
"observation.images.cam1": {
|
| 33 |
+
"type": "VISUAL",
|
| 34 |
+
"shape": [
|
| 35 |
+
3,
|
| 36 |
+
720,
|
| 37 |
+
1280
|
| 38 |
+
]
|
| 39 |
+
},
|
| 40 |
+
"observation.images.cam2": {
|
| 41 |
+
"type": "VISUAL",
|
| 42 |
+
"shape": [
|
| 43 |
+
3,
|
| 44 |
+
720,
|
| 45 |
+
1280
|
| 46 |
+
]
|
| 47 |
+
},
|
| 48 |
+
"action": {
|
| 49 |
+
"type": "ACTION",
|
| 50 |
+
"shape": [
|
| 51 |
+
10
|
| 52 |
+
]
|
| 53 |
+
}
|
| 54 |
+
},
|
| 55 |
+
"norm_map": {
|
| 56 |
+
"VISUAL": "MEAN_STD",
|
| 57 |
+
"STATE": "MIN_MAX",
|
| 58 |
+
"ACTION": "MIN_MAX"
|
| 59 |
+
}
|
| 60 |
+
},
|
| 61 |
+
"state_file": "policy_preprocessor_step_3_normalizer_processor.safetensors"
|
| 62 |
+
}
|
| 63 |
+
]
|
| 64 |
+
}
|
policy_preprocessor_step_3_normalizer_processor.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:949a6fcbc332b8a330e8471ef5b9e3b68e5ee08c0d5915274577d890ae27ef20
|
| 3 |
+
size 7896
|
train_config.json
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"dataset": {
|
| 3 |
+
"repo_id": "theo/banana_in_pot_ee_action",
|
| 4 |
+
"root": "./banana_in_pot_ee_action_lerobot",
|
| 5 |
+
"episodes": null,
|
| 6 |
+
"image_transforms": {
|
| 7 |
+
"enable": true,
|
| 8 |
+
"max_num_transforms": 1,
|
| 9 |
+
"random_order": false,
|
| 10 |
+
"tfs": {
|
| 11 |
+
"resize": {
|
| 12 |
+
"weight": 1.0,
|
| 13 |
+
"type": "Resize",
|
| 14 |
+
"kwargs": {
|
| 15 |
+
"size": [
|
| 16 |
+
360,
|
| 17 |
+
640
|
| 18 |
+
]
|
| 19 |
+
}
|
| 20 |
+
}
|
| 21 |
+
}
|
| 22 |
+
},
|
| 23 |
+
"revision": null,
|
| 24 |
+
"use_imagenet_stats": true,
|
| 25 |
+
"video_backend": "torchcodec",
|
| 26 |
+
"return_uint8": false,
|
| 27 |
+
"depth_output_unit": "mm",
|
| 28 |
+
"streaming": false,
|
| 29 |
+
"eval_split": 0.117
|
| 30 |
+
},
|
| 31 |
+
"env": null,
|
| 32 |
+
"policy": {
|
| 33 |
+
"type": "diffusion",
|
| 34 |
+
"n_obs_steps": 2,
|
| 35 |
+
"input_features": {
|
| 36 |
+
"observation.state": {
|
| 37 |
+
"type": "STATE",
|
| 38 |
+
"shape": [
|
| 39 |
+
10
|
| 40 |
+
]
|
| 41 |
+
},
|
| 42 |
+
"observation.images.cam1": {
|
| 43 |
+
"type": "VISUAL",
|
| 44 |
+
"shape": [
|
| 45 |
+
3,
|
| 46 |
+
720,
|
| 47 |
+
1280
|
| 48 |
+
]
|
| 49 |
+
},
|
| 50 |
+
"observation.images.cam2": {
|
| 51 |
+
"type": "VISUAL",
|
| 52 |
+
"shape": [
|
| 53 |
+
3,
|
| 54 |
+
720,
|
| 55 |
+
1280
|
| 56 |
+
]
|
| 57 |
+
}
|
| 58 |
+
},
|
| 59 |
+
"output_features": {
|
| 60 |
+
"action": {
|
| 61 |
+
"type": "ACTION",
|
| 62 |
+
"shape": [
|
| 63 |
+
10
|
| 64 |
+
]
|
| 65 |
+
}
|
| 66 |
+
},
|
| 67 |
+
"device": "cuda",
|
| 68 |
+
"use_amp": false,
|
| 69 |
+
"use_peft": false,
|
| 70 |
+
"push_to_hub": false,
|
| 71 |
+
"repo_id": null,
|
| 72 |
+
"private": null,
|
| 73 |
+
"tags": null,
|
| 74 |
+
"license": null,
|
| 75 |
+
"pretrained_path": null,
|
| 76 |
+
"pretrained_revision": null,
|
| 77 |
+
"horizon": 64,
|
| 78 |
+
"n_action_steps": 32,
|
| 79 |
+
"normalization_mapping": {
|
| 80 |
+
"VISUAL": "MEAN_STD",
|
| 81 |
+
"STATE": "MIN_MAX",
|
| 82 |
+
"ACTION": "MIN_MAX"
|
| 83 |
+
},
|
| 84 |
+
"drop_n_last_frames": 31,
|
| 85 |
+
"vision_backbone": "resnet18",
|
| 86 |
+
"resize_shape": [
|
| 87 |
+
360,
|
| 88 |
+
640
|
| 89 |
+
],
|
| 90 |
+
"crop_ratio": 1.0,
|
| 91 |
+
"crop_shape": null,
|
| 92 |
+
"crop_is_random": true,
|
| 93 |
+
"pretrained_backbone_weights": "ResNet18_Weights.IMAGENET1K_V1",
|
| 94 |
+
"use_group_norm": false,
|
| 95 |
+
"spatial_softmax_num_keypoints": 32,
|
| 96 |
+
"use_separate_rgb_encoder_per_camera": true,
|
| 97 |
+
"down_dims": [
|
| 98 |
+
512,
|
| 99 |
+
1024,
|
| 100 |
+
2048
|
| 101 |
+
],
|
| 102 |
+
"kernel_size": 5,
|
| 103 |
+
"n_groups": 8,
|
| 104 |
+
"diffusion_step_embed_dim": 128,
|
| 105 |
+
"use_film_scale_modulation": true,
|
| 106 |
+
"noise_scheduler_type": "DDPM",
|
| 107 |
+
"num_train_timesteps": 100,
|
| 108 |
+
"beta_schedule": "squaredcos_cap_v2",
|
| 109 |
+
"beta_start": 0.0001,
|
| 110 |
+
"beta_end": 0.02,
|
| 111 |
+
"prediction_type": "epsilon",
|
| 112 |
+
"clip_sample": true,
|
| 113 |
+
"clip_sample_range": 1.0,
|
| 114 |
+
"num_inference_steps": null,
|
| 115 |
+
"compile_model": false,
|
| 116 |
+
"compile_mode": "reduce-overhead",
|
| 117 |
+
"do_mask_loss_for_padding": false,
|
| 118 |
+
"optimizer_lr": 0.0001,
|
| 119 |
+
"optimizer_betas": [
|
| 120 |
+
0.95,
|
| 121 |
+
0.999
|
| 122 |
+
],
|
| 123 |
+
"optimizer_eps": 1e-08,
|
| 124 |
+
"optimizer_weight_decay": 1e-06,
|
| 125 |
+
"scheduler_name": "cosine",
|
| 126 |
+
"scheduler_warmup_steps": 500
|
| 127 |
+
},
|
| 128 |
+
"reward_model": null,
|
| 129 |
+
"output_dir": "outputs/train/diffusion_ee_val_diag",
|
| 130 |
+
"job_name": "diffusion_ee_val_diag",
|
| 131 |
+
"resume": false,
|
| 132 |
+
"seed": 1000,
|
| 133 |
+
"cudnn_deterministic": false,
|
| 134 |
+
"num_workers": 4,
|
| 135 |
+
"batch_size": 8,
|
| 136 |
+
"prefetch_factor": 4,
|
| 137 |
+
"persistent_workers": true,
|
| 138 |
+
"steps": 100000,
|
| 139 |
+
"env_eval_freq": 20000,
|
| 140 |
+
"log_freq": 200,
|
| 141 |
+
"eval_steps": 2000,
|
| 142 |
+
"max_eval_samples": 0,
|
| 143 |
+
"tolerance_s": 0.0001,
|
| 144 |
+
"save_checkpoint": true,
|
| 145 |
+
"save_freq": 10000,
|
| 146 |
+
"use_policy_training_preset": true,
|
| 147 |
+
"optimizer": {
|
| 148 |
+
"type": "adam",
|
| 149 |
+
"lr": 0.0001,
|
| 150 |
+
"weight_decay": 1e-06,
|
| 151 |
+
"grad_clip_norm": 10.0,
|
| 152 |
+
"betas": [
|
| 153 |
+
0.95,
|
| 154 |
+
0.999
|
| 155 |
+
],
|
| 156 |
+
"eps": 1e-08
|
| 157 |
+
},
|
| 158 |
+
"scheduler": {
|
| 159 |
+
"type": "diffuser",
|
| 160 |
+
"num_warmup_steps": 500,
|
| 161 |
+
"name": "cosine"
|
| 162 |
+
},
|
| 163 |
+
"eval": {
|
| 164 |
+
"n_episodes": 50,
|
| 165 |
+
"batch_size": 14,
|
| 166 |
+
"use_async_envs": true,
|
| 167 |
+
"recording": false,
|
| 168 |
+
"recording_repo_id": null,
|
| 169 |
+
"recording_private": false
|
| 170 |
+
},
|
| 171 |
+
"wandb": {
|
| 172 |
+
"enable": false,
|
| 173 |
+
"disable_artifact": false,
|
| 174 |
+
"project": "lerobot",
|
| 175 |
+
"entity": null,
|
| 176 |
+
"notes": null,
|
| 177 |
+
"run_id": null,
|
| 178 |
+
"mode": null,
|
| 179 |
+
"add_tags": true
|
| 180 |
+
},
|
| 181 |
+
"peft": null,
|
| 182 |
+
"job": {
|
| 183 |
+
"target": null,
|
| 184 |
+
"image": "huggingface/lerobot-gpu:latest",
|
| 185 |
+
"timeout": "2d",
|
| 186 |
+
"detach": false,
|
| 187 |
+
"tags": []
|
| 188 |
+
},
|
| 189 |
+
"save_checkpoint_to_hub": false,
|
| 190 |
+
"sample_weighting": null,
|
| 191 |
+
"rename_map": {},
|
| 192 |
+
"checkpoint_path": null
|
| 193 |
+
}
|