From 867b58cfb2abaa31c8248cf7a8ee74011c264533 Mon Sep 17 00:00:00 2001 From: Nikodem Bartnik <39432165+NikodemBartnik@users.noreply.github.com> Date: Wed, 15 Jul 2026 16:32:02 +0200 Subject: [PATCH 1/2] generate new readme (#4029) Co-authored-by: Pepijn <138571049+pkooij@users.noreply.github.com> --- src/lerobot/scripts/lerobot_annotate.py | 30 ++++++++++++------------- tests/scripts/test_lerobot_annotate.py | 16 ++++++++++++- 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/src/lerobot/scripts/lerobot_annotate.py b/src/lerobot/scripts/lerobot_annotate.py index e95036a6b..579175052 100644 --- a/src/lerobot/scripts/lerobot_annotate.py +++ b/src/lerobot/scripts/lerobot_annotate.py @@ -127,6 +127,9 @@ def _push_to_hub(root: Path, cfg: AnnotationPipelineConfig) -> None: """ from huggingface_hub import HfApi # noqa: PLC0415 + from lerobot.datasets.io_utils import load_info # noqa: PLC0415 + from lerobot.datasets.utils import create_lerobot_dataset_card # noqa: PLC0415 + repo_id = cfg.new_repo_id or cfg.repo_id commit_message = cfg.push_commit_message or "Add steerable annotations (lerobot-annotate)" api = HfApi() @@ -143,10 +146,17 @@ def _push_to_hub(root: Path, cfg: AnnotationPipelineConfig) -> None: repo_id=repo_id, repo_type="dataset", commit_message=commit_message, - ignore_patterns=[".annotate_staging/**", "**/.DS_Store"], + # README.md is excluded because when pushing to ``new_repo_id`` the + # source card's links (e.g. the visualize badge) would keep pointing + # at the source dataset; a fresh card is generated below instead. + ignore_patterns=[".annotate_staging/**", "**/.DS_Store", "README.md"], ) print(f"[lerobot-annotate] uploaded to https://huggingface.co/datasets/{repo_id}", flush=True) + dataset_info = load_info(root) + card = create_lerobot_dataset_card(dataset_info=dataset_info, license="apache-2.0", repo_id=repo_id) + card.push_to_hub(repo_id=repo_id, repo_type="dataset") + # Tag the upload with the codebase version. ``LeRobotDatasetMetadata`` # resolves the dataset revision via ``get_safe_version`` which scans # for tags like ``v3.0``; without a tag it raises @@ -155,21 +165,9 @@ def _push_to_hub(root: Path, cfg: AnnotationPipelineConfig) -> None: # actually wrote (no accidental drift if the codebase floor moves). from lerobot.datasets.dataset_metadata import CODEBASE_VERSION # noqa: PLC0415 - info_path = root / "meta" / "info.json" - version_tag = CODEBASE_VERSION - if info_path.exists(): - try: - from lerobot.utils.io_utils import load_json # noqa: PLC0415 - - info = load_json(info_path) - ds_version = info.get("codebase_version") - if isinstance(ds_version, str) and ds_version.startswith("v"): - version_tag = ds_version - except Exception as exc: # noqa: BLE001 - print( - f"[lerobot-annotate] could not read codebase_version from info.json ({exc}); falling back to {version_tag}", - flush=True, - ) + version_tag = ( + dataset_info.codebase_version if dataset_info.codebase_version.startswith("v") else CODEBASE_VERSION + ) revision = getattr(commit_info, "oid", None) tag_kwargs = { "repo_id": repo_id, diff --git a/tests/scripts/test_lerobot_annotate.py b/tests/scripts/test_lerobot_annotate.py index 6405bdc52..03f1ee104 100644 --- a/tests/scripts/test_lerobot_annotate.py +++ b/tests/scripts/test_lerobot_annotate.py @@ -30,7 +30,9 @@ def test_push_to_hub_tags_uploaded_dataset_revision(tmp_path, monkeypatch): root = tmp_path / "dataset" (root / "meta").mkdir(parents=True) - (root / "meta" / "info.json").write_text(json.dumps({"codebase_version": "v3.0"})) + (root / "meta" / "info.json").write_text( + json.dumps({"codebase_version": "v3.0", "fps": 30, "features": {}}) + ) calls = {} @@ -55,6 +57,11 @@ def test_push_to_hub_tags_uploaded_dataset_revision(tmp_path, monkeypatch): monkeypatch.setattr("huggingface_hub.HfApi", FakeHfApi) + def fake_card_push(self, **kwargs): + calls["card_push"] = {"content": str(self), **kwargs} + + monkeypatch.setattr("huggingface_hub.DatasetCard.push_to_hub", fake_card_push) + cfg = SimpleNamespace( repo_id="source/dataset", new_repo_id="annotated/dataset", @@ -71,6 +78,13 @@ def test_push_to_hub_tags_uploaded_dataset_revision(tmp_path, monkeypatch): "exist_ok": True, } assert calls["upload_folder"]["repo_id"] == "annotated/dataset" + # The source README must not be copied over: its links (e.g. the + # visualize badge) point at the source dataset. A card regenerated for + # the target repo is pushed instead. + assert "README.md" in calls["upload_folder"]["ignore_patterns"] + assert calls["card_push"]["repo_id"] == "annotated/dataset" + assert "visualize_dataset?path=annotated/dataset" in calls["card_push"]["content"] + assert "source/dataset" not in calls["card_push"]["content"] # A stale tag (e.g. from a previous annotation run) is deleted first so # the new tag always points at the upload we just made. assert calls["delete_tag"] == { From 3f2179f3b69708b6ad009b2e7685dd9d05269ee1 Mon Sep 17 00:00:00 2001 From: Steven Palma Date: Wed, 15 Jul 2026 17:02:01 +0200 Subject: [PATCH 2/2] refactor(evo1): use transformers flash attention probe (#4013) Co-authored-by: Martino Russi <77496684+nepyope@users.noreply.github.com> --- .../policies/evo1/internvl3_embedder.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/lerobot/policies/evo1/internvl3_embedder.py b/src/lerobot/policies/evo1/internvl3_embedder.py index d47105d96..295a4c343 100644 --- a/src/lerobot/policies/evo1/internvl3_embedder.py +++ b/src/lerobot/policies/evo1/internvl3_embedder.py @@ -27,9 +27,11 @@ from lerobot.utils.import_utils import _transformers_available, require_package if TYPE_CHECKING or _transformers_available: from transformers import AutoModel, AutoTokenizer + from transformers.utils import is_flash_attn_2_available else: AutoModel = None AutoTokenizer = None + is_flash_attn_2_available = None IMAGENET_MEAN = (0.485, 0.456, 0.406) IMAGENET_STD = (0.229, 0.224, 0.225) @@ -135,9 +137,13 @@ class InternVL3Embedder(nn.Module): raise ValueError(f"Unsupported EVO1 vlm_dtype '{model_dtype}'") from exc self.model_dtype = model_dtype - attn_implementation = "flash_attention_2" if (use_flash_attn and _flash_attn_available()) else "eager" + attn_implementation = ( + "flash_attention_2" if (use_flash_attn and is_flash_attn_2_available()) else "eager" + ) if use_flash_attn and attn_implementation == "eager": - logger.warning("flash_attn is not installed. Falling back to eager attention.") + logger.warning( + "Flash Attention 2 is unavailable on this runtime. Falling back to eager attention." + ) self.model = AutoModel.from_pretrained( model_name, @@ -359,11 +365,3 @@ class InternVL3Embedder(nn.Module): @property def device(self) -> torch.device: return next(self.model.parameters()).device - - -def _flash_attn_available() -> bool: - try: - import flash_attn # noqa: F401 - except ModuleNotFoundError: - return False - return True