LeRobot documentation
Kendi Robot İşleyicinizi Uygulayın
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 featuresTemel 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_featurekullanı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:
- İşleyicinizi gerekli yöntemlere (
__call__,get_config,state_dict,load_state_dict,reset,transform_features) sahip bir dataclass olarak tanımlayın - Keşfedilebilirlik için kayıt edin,
@ProcessorStepRegistry.register("name")kullanarak - Bunu diğer işleme adımlarıyla birlikte bir
DataProcessorPipelineiçine entegre edin - Mümkün olduğunda
ObservationProcessorStepgibi temel sınıfları kullanarak gereksiz kodu azaltın - Ç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