LeRobot documentation

Kendi Robot İşleyicinizi Uygulayın

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Kendi Robot İşleyicinizi Uygulayın

Bu eğitimde, kendi Robot İşleyicinizi (Processor) nasıl uygulayacağınızı öğreneceksiniz. Önce özel bir işleyiciye duyulan ihtiyacı ele alır, ardından NormalizerProcessorStep’i örnek olarak kullanarak bir işleyicinin nasıl uygulanacağını, yapılandırılacağını ve serileştirileceğini açıklar. LeRobot ile birlikte gelen işleyici adımları için Ortak İşleyici Adımları bölümüne bakın.

Neden özel bir işlemciye (processor) ihtiyacınız olur?

Çoğu durumda, sensörlerden ham veri okurken veya modeller eylemler ürettiğinde, bu verileri hedef sisteminizle uyumlu hale getirmek için işlemek gerekir. Örneğin, yaygın bir ihtiyaç, verilerin aralıklarını sinir ağları için uygun hale getirmek amacıyla normalize etmektir.

LeRobot'un NormalizerProcessorStep bileşeni bu kritik görevi üstlenir:

# Input: raw joint positions in [0, 180] degrees
raw_action = torch.tensor([90.0, 45.0, 135.0])

# After processing: normalized to [-1, 1] range for model training
normalizer = NormalizerProcessorStep(features=features, norm_map=norm_map, stats=dataset_stats)
normalized_result = normalizer(transition)
# ...

Diğer yaygın işleme ihtiyaçları şunları içerir:

  • Cihaz yerleşimi: Gergilerin CPU/GPU arasında taşınması ve veri türlerinin dönüştürülmesi
  • Biçim dönüştürme: Farklı veri yapıları arasında dönüştürme
  • Toplu işleme: Model uyumluluğu için batch boyutlarının eklenmesi/çıkarılması
  • Güvenlik kısıtlamaları: Robot komutlarına sınırlar uygulama
# Example pipeline combining multiple processors
pipeline = PolicyProcessorPipeline([
    RenameObservationsProcessorStep(rename_map={}),
    AddBatchDimensionProcessorStep(),
    NormalizerProcessorStep(features=features, norm_map=norm_map, stats=stats),
    DeviceProcessorStep(device="cuda"),
    # ...
])

LeRobot, hem girdi verileri hem de çıktı eylemleri için işleme adımlarının dizilerini uygulamak üzere bir boru hattı mekanizması sağlar; bu sayede bu dönüşümleri en iyi performans için doğru sırada bir araya getirmek kolaylaşır.

Kendi işleyicinizi nasıl uygularsınız?

Ana örnek olarak NormalizerProcessorStep sınıfını kullanacağız çünkü bu sınıf, sıkça ihtiyaç duyacağınız durum yönetimi, yapılandırma serileştirme ve tensör işleme gibi temel işlemci kalıplarını göstermektedir.

Sorunuza gerekli olan işleme adımlarının dizisini hazırlayın. Bir işlemci adımı, aşağıdaki yöntemleri uygulayan bir sınıftır:

  • __call__: girdi geçişi için işleme adımını uygular.
  • get_config: işlemci adımının yapılandırmasını alır.
  • state_dict: işlemcinin adım durumunu alır.
  • load_state_dict: işlemcinin adım durumunu yükler.
  • reset: işlemci adımının durumunu sıfırlar.
  • transform_features: işlemci adımının özellik uzayını nasıl değiştirdiğini açıklar.

__call__ metodunu uygulayın

__call__ yöntemi, işlemcinizdeki adımın çekirdeğidir. Bir EnvTransition alır ve değiştirilmiş bir EnvTransition döndürür. NormalizerProcessorStep şu şekilde çalışır:

@dataclass
@ProcessorStepRegistry.register("normalizer_processor")
class NormalizerProcessorStep(ProcessorStep):
    """Normalize observations/actions using dataset statistics."""

    features: dict[str, PolicyFeature]
    norm_map: dict[FeatureType, NormalizationMode]
    stats: dict[str, dict[str, Any]] | None = None
    eps: float = 1e-8
    _tensor_stats: dict = field(default_factory=dict, init=False, repr=False)

    def __post_init__(self):
        """Convert stats to tensors for efficient computation."""
        self.stats = self.stats or {}
        self._tensor_stats = to_tensor(self.stats, device=self.device, dtype=torch.float32)

    def __call__(self, transition: EnvTransition) -> EnvTransition:
        new_transition = transition.copy()
        # Normalize observations
        # ...
        # Normalize action
        # ...
        return new_transition

Tam detaylar için tam uygulamayı src/lerobot/processor/normalize_processor.py dosyasında inceleyin.

Temel ilkeler:

  • Yan etkileri önlemek için her zaman transition.copy() kullanın
  • Gözlemleri ve eylemleri tutarlı bir şekilde ele alın
  • Yapılandırmayı durumdan ayırın: get_config() JSON-serializable parametreleri, state_dict() tensörleri döndürür
  • Verimli hesaplama için __post_init__() içinde istatistikleri tensörlere dönüştürün

Yapılandırma ve Durum Yönetimi

İşleyiciler, yapılandırmayı tensör durumundan ayıran üç yöntemle seri hale getirmeyi destekler. NormalizerProcessorStep bunu mükemmel bir şekilde gösterir - durumu içinde veri seti istatistiklerini (tensörler) ve yapılandırmasında hiperparametreleri taşır:

# Continuing the NormalizerProcessorStep example...

def get_config(self) -> dict[str, Any]:
    """JSON-serializable configuration (no tensors)."""
    return {
        "eps": self.eps,
        "features": {k: {"type": v.type.value, "shape": v.shape} for k, v in self.features.items()},
        "norm_map": {ft.value: nm.value for ft, nm in self.norm_map.items()},
        # ...
    }

def state_dict(self) -> dict[str, torch.Tensor]:
    """Tensor state only (e.g., dataset statistics)."""
    flat: dict[str, torch.Tensor] = {}
    for key, sub in self._tensor_stats.items():
        for stat_name, tensor in sub.items():
            flat[f"{key}.{stat_name}"] = tensor.cpu()  # Always save to CPU
    return flat

def load_state_dict(self, state: dict[str, torch.Tensor]) -> None:
    """Restore tensor state at runtime."""
    self._tensor_stats.clear()
    for flat_key, tensor in state.items():
        key, stat_name = flat_key.rsplit(".", 1)
        # Load to processor's configured device
        self._tensor_stats.setdefault(key, {})[stat_name] = tensor.to(
            dtype=torch.float32, device=self.device
        )
        # ...

Kullanım:

# Save (e.g., inside a policy)
config = normalizer.get_config()
tensors = normalizer.state_dict()

# Restore (e.g., loading a pretrained policy)
new_normalizer = NormalizerProcessorStep(**config)
new_normalizer.load_state_dict(tensors)
# Now new_normalizer has the same stats and configuration

Özellikleri dönüştür

transform_features yöntemi, işleyicinizin (processor) özellik adlarını ve biçimlerini nasıl dönüştürdüğünü tanımlar. Bu, politika yapılandırması ve hata ayıklama için hayati önem taşır.

NormalizerProcessorStep için özellikler genellikle değiştirilmeden korunur çünkü normalizasyon anahtarları veya şekilleri değiştirmez:

def transform_features(self, features: dict[PipelineFeatureType, dict[str, PolicyFeature]]) -> dict[PipelineFeatureType, dict[str, PolicyFeature]]:
    """Normalization preserves all feature definitions."""
    return features  # No changes to feature structure
    # ...

İşleyiciniz (processor) verileri yeniden adlandırırsa veya yeniden şekillendirirse, bu yöntemi uygulayarak aşağıdaki bileşenler için eşlemeyi yansıtın. Örneğin, basit bir yeniden adlandırma işleyicisi:

def transform_features(self, features: dict[str, PolicyFeature]) -> dict[str, PolicyFeature]:
    # Simple renaming
    if "pixels" in features:
        features["observation.image"] = features.pop("pixels")

    # Pattern-based renaming
    for key in list(features.keys()):
        if key.startswith("env_state."):
            suffix = key[len("env_state."):]
            features[f"observation.{suffix}"] = features.pop(key)
            # ...

    return features

Temel ilkeler:

  • Eski özelliği kaldırmak ve almak için features.pop(old_key) kullanın
  • Yeniden adlandırılan özelliği eklemek için features[new_key] = old_feature kullanın
  • Her zaman değiştirilmiş özellikler sözlüğünü döndürün
  • Dönüşümleri docstring'de açıkça belgeleyin

Eşlenikler kullanma

overrides kullanarak adım parametrelerini yükleme zamanında geçersiz kılabilirsiniz. Bu, seri hale getirilemeyen nesneler veya siteye özel ayarlar için kullanışlıdır. Hem politika fabrikalarında hem de DataProcessorPipeline.from_pretrained(...) ile birlikte çalışır.

Temel model uyarlama: Bu, genellikle orijinal eğitim istatistiklerine erişiminizin olmadığı temel önceden eğitilmiş politikalarla çalışırken özellikle faydalıdır. Normalizörü, belirli robotunuza veya ortam verilerinize uyarlamak için kendi veri seti istatistiklerinizi enjekte edebilirsiniz.

Örnek: robot üzerinde politika değerlendirme sırasında cihazı ve yeniden adlandırma haritasını geçersiz kılın. Bunu, CUDA üzerinde eğitilmiş bir politikayı yalnızca CPU'ya sahip bir robotta çalıştırmak veya robot, veri setinden farklı adlar kullandığında kamera anahtarlarını yeniden eşlemek için kullanın.

from_pretrained ile doğrudan kullanım:

from lerobot.datasets import LeRobotDataset
from lerobot.processor import PolicyProcessorPipeline

# Load a foundational policy trained on diverse robot data
# but adapt normalization to your specific robot/environment
new_stats = LeRobotDataset(repo_id="username/my-dataset").meta.stats
processor = PolicyProcessorPipeline.from_pretrained(
    "huggingface/foundational-robot-policy",  # Pretrained foundation model
    config_filename="policy_preprocessor.json",  # The policy's saved preprocessor
    overrides={
        "normalizer_processor": {"stats": new_stats},     # Inject your robot's statistics
        "device_processor": {"device": "cuda:0"},         # registry name for registered steps
        "rename_observations_processor": {"rename_map": robot_key_map}, # Map your robot's observation keys
        # ...
    },
)

En İyi Uygulamalar

Tüm LeRobot işlemci uygulamalarının analizine dayanarak, ana kalıplar ve uygulamalar şunlardır:

1. Güvenli Veri İşleme

Giriş verilerinin kopyalarını oluşturarak istenmeyen yan etkilerden kaçının. Verileri yerinde değiştirmek yerine transition.copy() ve observation.copy() kullanın. Bu, işleyicinizin (processor) hattaki (pipeline) diğer bileşenleri yanlışlıkla etkilemesini önler.

İşleme öncesinde gerekli verileri kontrol edin ve eksik verileri zarifçe ele alın. İşleyiciniz belirli anahtarları (görsel işleme için "pixels" gibi) bekliyorsa, varlıklarını önce doğrulayın. İsteğe bağlı veriler için transition.get() gibi güvenli erişim desenlerini kullanın ve None değerlerini uygun şekilde ele alın.

Veri doğrulaması başarısız olduğunda, kullanıcıların neyin yanlış gittiğini ve nasıl düzeltebileceklerini anlamalarına yardımcı olacak, net ve uygulanabilir hata mesajları sağlayın.

2. Uygun Temel Sınıfları Seçin

LeRobot, şablon kodunu azaltan ve tutarlılığı sağlayan özel temel sınıflar sunar. Yalnızca gözlemleri değiştirmeniz gerekiyorsa ObservationProcessorStep, yalnızca eylem işleme için ActionProcessorStep ve sözlük tabanlı robot eylemleri için özellikle RobotActionProcessorStep kullanın.

Sadece tüm geçiş üzerinde tam kontrol gerektirdiğinde veya birden fazla geçiş bileşenini eş zamanlı işlediğinde doğrudan ProcessorStep sınıfından türetme yapın. Özel taban sınıflar, geçiş yönetimini sizin için ele alır ve tip güvenliğini sağlar.

3. Kayıt ve Adlandırma

İşleyicilerinizi, ad çakışmalarını önlemek için "robotics_lab/safety_clipper" veya "acme_corp/vision_enhancer" gibi kuruluş önekleri kullanan açıklayıcı ve ad alanlı adlarla @ProcessorStepRegistry.register() aracılığıyla kaydedin. Diğer uygulamalarla çakışabilecek "processor" veya "step" gibi genel adlardan kaçının.

Doğru kayıt, işleyicilerinizin keşfedilebilir olmasını sağlar ve hatları kaydetme ve yükleme sırasında temiz seri hale getirme/seri halinden çıkarma işlemlerine olanak tanır.

4. Durum Yönetimi Desenleri

Yapılandırma parametreleri (JSON-serializable değerler) ile iç durum (tensörler, tamponlar) arasında ayrım yapın. Yapıcıda veya dize gösteriminde yer almaması gereken iç durum için init=False, repr=False alanlarına sahip dataclass alanlarını kullanın.

Epizotlar arasında iç durumu temizlemek için reset() metodunu uygulayın. Bu, hareketli ortalamalar veya zamansal filtreler gibi zamanla veri biriktiren durumlu işleyiciler için hayati önem taşır.

get_config()'in yalnızca JSON-serializable yapılandırma döndürmesi gerektiğini, state_dict()'in ise tensör durumunu ayrı olarak ele aldığını unutmayın.

5. Girdi Doğrulama ve Hata Yönetimi

İşleme öncesinde girdi türlerini ve şekillerini doğrulayın. Algoritmalarınızla uyumluluğu sağlamak için dtype ve boyutlar gibi tensör özelliklerini kontrol edin. Robot eylemleri için, gerekli duruş bileşenlerinin veya eklem değerlerinin mevcut olduğunu ve beklenen aralıklar içinde olduğunu doğrulayın.

İşleme gerektirmeyen sınır durumları için erken dönüşler kullanın. Beklenen ve gerçek veri türlerini veya şekillerini içeren açık ve açıklayıcı hata mesajları sağlayın. Bu, kullanıcılar için hata ayıklamayı çok daha kolay hale getirir.

6. Cihaz ve Veri Türü Farkındalığı

İşleyicilerinizi, girdi tensörlerinin cihazına ve veri türüne (dtype) otomatik olarak uyum sağlaması için tasarlayın. Dahili tensörler (normalizasyon istatistikleri gibi), çoklu GPU eğitimine, karma hassasiyete ve dağıtık kurulumlara uyumluluğu sağlamak için girdi tensörünün cihazı ve veri türüyle (dtype) eşleşmelidir.

İşleyicinizin dahili durumunu belirtilen cihaza taşıyan bir to() yöntemi uygulayın. Cihaz/tür uyumluluğunu çalışma zamanında kontrol edin ve gerektiğinde dahili durumu otomatik olarak taşıyın. Bu desen, manuel müdahale olmadan farklı donanım yapılandırmaları arasında kesintisiz çalışmayı mümkün kılar.

Sonuç

LeRobot'ta özel işlemciler (processors) uygulamak için gereken tüm araçlara sahipsiniz! Temel adımlar şunlardır:

  1. İşleyicinizi gerekli yöntemlere (__call__, get_config, state_dict, load_state_dict, reset, transform_features) sahip bir dataclass olarak tanımlayın
  2. Keşfedilebilirlik için kayıt edin, @ProcessorStepRegistry.register("name") kullanarak
  3. Bunu diğer işleme adımlarıyla birlikte bir DataProcessorPipeline içine entegre edin
  4. Mümkün olduğunda ObservationProcessorStep gibi temel sınıfları kullanarak gereksiz kodu azaltın
  5. Çoklu GPU ve karma hassasiyet kurulumlarını desteklemek için cihaz/tür farkındalığı uygulayın

İşleyici sistemi, modüler ve birleştirilebilir olacak şekilde tasarlanmıştır; böylece karmaşık veri işleme hatlarını basit ve odaklı bileşenlerden oluşturabilirsiniz. Hem eğitim için sensör verilerini ön işleme yapıyor hem de robot çalıştırması için model çıktılarını son işleme yapıyor olun, özel işleyiciler robotik uygulamanızın gerektirdiği herhangi bir veri dönüşümünü ele almanız için esneklik sağlar.

Sağlam işlemciler için temel ilkeler:

  • Cihaz/tür uyumu: İç tensörler, girdi tensörleriyle eşleşmelidir
  • Açık hata mesajları: Kullanıcıların neyin yanlış gittiğini anlamasına yardımcı olun
  • Taban sınıf kullanımı: Şablon kodunu azaltmak için uzmanlaşmış taban sınıflarını kullanın
  • Özellik sözleşmeleri: transform_features() ile veri yapısı değişikliklerini bildirin

Basit başlayın, kapsamlı test edin ve işleyicilerinizin farklı donanım yapılandırmaları arasında sorunsuz çalıştığından emin olun!

Update on GitHub