| |
| |
|
|
| from typing import Dict, Any, List, Optional |
| from omegaconf import OmegaConf |
| import torch |
|
|
|
|
| def create_dataset(config: OmegaConf, val: bool = False): |
| """ |
| Create dataset based on config. |
| |
| Args: |
| config: Configuration object |
| val: Whether to create validation dataset |
| |
| Returns: |
| Dataset instance |
| """ |
| dataset_type = config.dataset.get('type', 'robotwin') |
| |
| if dataset_type == 'robotwin': |
| from .robotwin2.robotwin_agilex_dataset import RobotWinTaskDataset |
| |
| |
| params = {} |
| |
| |
| if hasattr(config, 'common'): |
| params.update({ |
| 'global_downsample_rate': config.common.global_downsample_rate, |
| 'video_action_freq_ratio': config.common.video_action_freq_ratio, |
| 'num_video_frames': config.common.num_video_frames, |
| 'video_size': (config.common.video_height, config.common.video_width), |
| 'state_dim': config.common.state_dim, |
| 'action_dim': config.common.action_dim, |
| }) |
| |
| |
| if hasattr(config.dataset, 'dataset_dir'): |
| params['dataset_dir'] = config.dataset.dataset_dir |
| if hasattr(config.dataset, 'data_mode'): |
| params['data_mode'] = config.dataset.data_mode |
| if hasattr(config.dataset, 'task_mode'): |
| params['task_mode'] = config.dataset.task_mode |
| if hasattr(config.dataset, 'task_name'): |
| params['task_name'] = config.dataset.task_name |
| if hasattr(config.dataset, 'max_episodes'): |
| params['max_episodes'] = config.dataset.max_episodes |
| if hasattr(config.dataset, 'image_aug'): |
| params['image_aug'] = config.dataset.image_aug and not val |
| if hasattr(config.dataset, 'randomized_limit_per_task'): |
| params['randomized_limit_per_task'] = config.dataset.randomized_limit_per_task |
| |
| |
| if hasattr(config.model, 'vlm') and hasattr(config.model.vlm, 'checkpoint_path'): |
| params['vlm_checkpoint_path'] = config.model.vlm.checkpoint_path |
| |
| |
| if hasattr(config.dataset, 'params'): |
| additional_params = OmegaConf.to_object(config.dataset.params) |
| params.update(additional_params) |
| |
| |
| params['val'] = val |
| |
| return RobotWinTaskDataset(**params) |
| |
| elif dataset_type == 'ac_one': |
| from .ac_one.ac_one_dataset import ACOneDataset |
| |
| |
| params = {} |
| |
| |
| if hasattr(config, 'common'): |
| params.update({ |
| 'global_downsample_rate': config.common.global_downsample_rate, |
| 'video_action_freq_ratio': config.common.video_action_freq_ratio, |
| 'num_video_frames': config.common.num_video_frames, |
| 'video_size': (config.common.video_height, config.common.video_width), |
| }) |
| |
| |
| if hasattr(config.dataset, 'dataset_dir'): |
| params['dataset_dir'] = config.dataset.dataset_dir |
| if hasattr(config.dataset, 'task_mode'): |
| params['task_mode'] = config.dataset.task_mode |
| if hasattr(config.dataset, 'task_name'): |
| params['task_name'] = config.dataset.task_name |
| if hasattr(config.dataset, 'max_episodes'): |
| params['max_episodes'] = config.dataset.max_episodes |
| if hasattr(config.dataset, 'val_episodes'): |
| params['val_episodes'] = config.dataset.val_episodes |
| if hasattr(config.dataset, 'image_aug'): |
| params['image_aug'] = config.dataset.image_aug and not val |
| |
| |
| if hasattr(config.model, 'vlm') and hasattr(config.model.vlm, 'checkpoint_path'): |
| params['vlm_checkpoint_path'] = config.model.vlm.checkpoint_path |
| |
| |
| if hasattr(config.dataset, 'params'): |
| additional_params = OmegaConf.to_object(config.dataset.params) |
| params.update(additional_params) |
| |
| |
| params['val'] = val |
| |
| return ACOneDataset(**params) |
|
|
| elif dataset_type == 'latent_action': |
| from .latent_action.latent_action_dataset import LatentActionDataset |
|
|
| params = {} |
|
|
| |
| if hasattr(config, 'common'): |
| params.update({ |
| 'global_downsample_rate': config.common.global_downsample_rate, |
| 'num_video_frames': config.common.num_video_frames, |
| 'video_size': (config.common.video_height, config.common.video_width), |
| }) |
|
|
| if hasattr(config.dataset, 'dataset_dir'): |
| dataset_dir = list(config.dataset.dataset_dir) |
| params['dataset_dir'] = [str(p) for p in dataset_dir] |
| if hasattr(config.dataset, 'max_episodes'): |
| params['max_episodes'] = config.dataset.max_episodes |
| if hasattr(config.dataset, 'image_aug'): |
| params['image_aug'] = config.dataset.image_aug and not val |
|
|
| |
| if hasattr(config.model, 'vlm') and hasattr(config.model.vlm, 'checkpoint_path'): |
| params['vlm_checkpoint_path'] = config.model.vlm.checkpoint_path |
|
|
| |
| if hasattr(config.dataset, 'params'): |
| additional_params = OmegaConf.to_object(config.dataset.params) |
| params.update(additional_params) |
|
|
| params['val'] = val |
|
|
| return LatentActionDataset(**params) |
|
|
| elif dataset_type == 'aloha_agilex_2': |
| from .aloha_agilex_2.aloha_agilex2_dataset import AlohaAgilex2Dataset |
| |
| |
| params = {} |
| |
| |
| if hasattr(config, 'common'): |
| params.update({ |
| 'global_downsample_rate': config.common.global_downsample_rate, |
| 'video_action_freq_ratio': config.common.video_action_freq_ratio, |
| 'num_video_frames': config.common.num_video_frames, |
| 'video_size': (config.common.video_height, config.common.video_width), |
| }) |
| |
| |
| if hasattr(config.dataset, 'dataset_dir'): |
| params['dataset_dir'] = config.dataset.dataset_dir |
| if hasattr(config.dataset, 'task_mode'): |
| params['task_mode'] = config.dataset.task_mode |
| if hasattr(config.dataset, 'task_name'): |
| params['task_name'] = config.dataset.task_name |
| if hasattr(config.dataset, 'max_episodes'): |
| params['max_episodes'] = config.dataset.max_episodes |
| if hasattr(config.dataset, 'val_episodes'): |
| params['val_episodes'] = config.dataset.val_episodes |
| if hasattr(config.dataset, 'image_aug'): |
| params['image_aug'] = config.dataset.image_aug and not val |
| |
| |
| if hasattr(config.model, 'vlm') and hasattr(config.model.vlm, 'checkpoint_path'): |
| params['vlm_checkpoint_path'] = config.model.vlm.checkpoint_path |
| |
| |
| if hasattr(config.dataset, 'params'): |
| additional_params = OmegaConf.to_object(config.dataset.params) |
| params.update(additional_params) |
| |
| |
| params['val'] = val |
| |
| return AlohaAgilex2Dataset(**params) |
|
|
| elif dataset_type == "manifeel_zarr": |
| from .manifeel.manifeel_zarr_dataset import ManiFeelZarrDataset |
| params = {} |
| if hasattr(config, "common"): |
| params.update({ |
| "global_downsample_rate": config.common.global_downsample_rate, |
| "video_action_freq_ratio": config.common.video_action_freq_ratio, |
| "num_video_frames": config.common.num_video_frames, |
| "video_size": (config.common.video_height, config.common.video_width), |
| }) |
| if hasattr(config.dataset, "dataset_dir"): |
| params["dataset_dir"] = config.dataset.dataset_dir |
| if hasattr(config.dataset, "max_episodes"): |
| params["max_episodes"] = config.dataset.max_episodes |
| if hasattr(config.model, 'vlm') and hasattr(config.model.vlm, 'checkpoint_path'): |
| params['vlm_checkpoint_path'] = config.model.vlm.checkpoint_path |
| params["val"] = val |
| return ManiFeelZarrDataset(**params) |
|
|
| elif dataset_type == 'libero': |
| from .libero_dataset import LiberoDataset |
| params = {} |
| if hasattr(config, 'common'): |
| params.update({ |
| 'global_downsample_rate': config.common.global_downsample_rate, |
| 'video_action_freq_ratio': config.common.video_action_freq_ratio, |
| 'num_video_frames': config.common.num_video_frames, |
| 'video_size': (config.common.video_height, config.common.video_width), |
| 'state_dim': config.common.state_dim, |
| 'action_dim': config.common.action_dim, |
| }) |
| if hasattr(config.dataset, 'dataset_dir'): |
| params['dataset_dir'] = config.dataset.dataset_dir |
| elif hasattr(config.dataset, 'params') and hasattr(config.dataset.params, 'root'): |
| params['dataset_dir'] = config.dataset.params.root |
| if hasattr(config.dataset, 'max_episodes'): |
| params['max_episodes'] = config.dataset.max_episodes |
| if hasattr(config.model, 'vlm') and hasattr(config.model.vlm, 'checkpoint_path'): |
| params['vlm_checkpoint_path'] = config.model.vlm.checkpoint_path |
| return LiberoDataset(**params) |
|
|
| elif dataset_type == 'lerobot': |
| from .lerobot.lerobot_dataset import LeRobotMotusDataset |
|
|
| |
| params = {} |
|
|
| |
| if hasattr(config, 'common'): |
| params.update({ |
| 'global_downsample_rate': config.common.global_downsample_rate, |
| 'video_action_freq_ratio': config.common.video_action_freq_ratio, |
| 'num_video_frames': config.common.num_video_frames, |
| 'video_size': (config.common.video_height, config.common.video_width), |
| }) |
|
|
| |
| if hasattr(config.dataset, 'dataset_dir'): |
| params['dataset_dir'] = config.dataset.dataset_dir |
| if hasattr(config.dataset, 'task_mode'): |
| params['task_mode'] = config.dataset.task_mode |
| if hasattr(config.dataset, 'task_name'): |
| params['task_name'] = config.dataset.task_name |
| if hasattr(config.dataset, 'max_episodes'): |
| params['max_episodes'] = config.dataset.max_episodes |
| if hasattr(config.dataset, 'image_aug'): |
| params['image_aug'] = config.dataset.image_aug and not val |
|
|
| |
| if hasattr(config.model, 'vlm') and hasattr(config.model.vlm, 'checkpoint_path'): |
| params['vlm_checkpoint_path'] = config.model.vlm.checkpoint_path |
|
|
| |
| if hasattr(config.dataset, 'params'): |
| additional_params = OmegaConf.to_object(config.dataset.params) |
| params.update(additional_params) |
|
|
| |
| params['val'] = val |
| |
| return LeRobotMotusDataset(**params) |
|
|
| |
| |
| |
| |
| |
| else: |
| raise ValueError(f"Unknown dataset type: {dataset_type}. Available types: robotwin, aloha_agilex_1, ac_one, aloha_agilex_2, table30") |
|
|
|
|
| def _process_vlm_inputs_batch(vlm_inputs: List[Dict[str, Any]]) -> Dict[str, torch.Tensor]: |
| """Process and batch VLM inputs with padding.""" |
| |
| input_ids_list = [vlm_input['input_ids'] for vlm_input in vlm_inputs] |
| pixel_values_list = [vlm_input.get('pixel_values') for vlm_input in vlm_inputs] |
| image_grid_thw_list = [vlm_input.get('image_grid_thw') for vlm_input in vlm_inputs] |
| attention_mask_list = [vlm_input.get('attention_mask') for vlm_input in vlm_inputs] |
| |
| |
| max_seq_len = max(ids.shape[1] for ids in input_ids_list) |
| padded_input_ids = [] |
| padded_attention_masks = [] |
| |
| for ids, mask in zip(input_ids_list, attention_mask_list): |
| if ids.shape[1] < max_seq_len: |
| padding_size = max_seq_len - ids.shape[1] |
| |
| padding = torch.zeros(ids.shape[0], padding_size, dtype=ids.dtype, device=ids.device) |
| padded_ids = torch.cat([ids, padding], dim=1) |
| |
| if mask is not None: |
| mask_padding = torch.zeros(mask.shape[0], padding_size, dtype=mask.dtype, device=mask.device) |
| padded_mask = torch.cat([mask, mask_padding], dim=1) |
| else: |
| padded_mask = None |
| else: |
| padded_ids = ids |
| padded_mask = mask |
| |
| padded_input_ids.append(padded_ids) |
| padded_attention_masks.append(padded_mask) |
| |
| |
| return { |
| 'input_ids': torch.cat(padded_input_ids, dim=0), |
| 'pixel_values': torch.cat([pv for pv in pixel_values_list if pv is not None], dim=0) if pixel_values_list and any(pv is not None for pv in pixel_values_list) else None, |
| 'image_grid_thw': torch.cat([igt for igt in image_grid_thw_list if igt is not None], dim=0) if image_grid_thw_list and any(igt is not None for igt in image_grid_thw_list) else None, |
| 'attention_mask': torch.cat([mask for mask in padded_attention_masks if mask is not None], dim=0) if any(mask is not None for mask in padded_attention_masks) else None, |
| } |
|
|
|
|
| def _process_language_embeddings_batch(language_embeddings: List[torch.Tensor], text_len: int = 512) -> torch.Tensor: |
| """Process and batch language embeddings with padding.""" |
| padded_embeddings = [] |
| |
| for emb in language_embeddings: |
| if emb.shape[0] <= text_len: |
| padded = torch.cat([emb, emb.new_zeros(text_len - emb.shape[0], emb.shape[1])]) |
| else: |
| padded = emb[:text_len] |
| padded_embeddings.append(padded) |
| |
| |
| return torch.stack(padded_embeddings, dim=0) |
|
|
|
|
| def collate_fn(batch: List[Optional[Dict[str, Any]]]) -> Optional[Dict[str, Any]]: |
| """ |
| Universal collate function for all datasets. |
| |
| Args: |
| batch: List of sample dictionaries (may contain None) |
| |
| Returns: |
| Batched dictionary or None if all samples are None |
| """ |
| |
| batch = [sample for sample in batch if sample is not None] |
| |
| if len(batch) == 0: |
| return None |
| |
| |
| first_frames = torch.stack([sample['first_frame'] for sample in batch]) |
| video_frames = torch.stack([sample['video_frames'] for sample in batch]) |
| action_sequences = torch.stack([sample['action_sequence'] for sample in batch]) |
| has_initial_state = all(('initial_state' in sample and sample['initial_state'] is not None) for sample in batch) |
| initial_states = torch.stack([sample['initial_state'] for sample in batch]) if has_initial_state else None |
| |
| |
| vlm_inputs = [sample.get('vlm_inputs') for sample in batch] |
| processed_vlm_inputs = None |
| if vlm_inputs and all(vlm_input is not None for vlm_input in vlm_inputs): |
| processed_vlm_inputs = _process_vlm_inputs_batch(vlm_inputs) |
| |
| |
| language_embeddings = [sample.get('language_embedding') for sample in batch if 'language_embedding' in sample] |
| processed_language_embeddings = None |
| if language_embeddings and any(emb is not None for emb in language_embeddings): |
| processed_language_embeddings = _process_language_embeddings_batch(language_embeddings) |
| |
| result = { |
| 'first_frame': first_frames, |
| 'video_frames': video_frames, |
| 'action_sequence': action_sequences, |
| 'vlm_inputs': processed_vlm_inputs, |
| 'language_embedding': processed_language_embeddings, |
| } |
|
|
| if initial_states is not None: |
| result['initial_state'] = initial_states |
| |
| return result |
|
|