| |
| """Configs for RFT.""" |
| from __future__ import annotations |
|
|
| import os |
| from copy import deepcopy |
| from dataclasses import dataclass, field |
| from enum import Enum |
| from typing import Any, Dict, List, Optional |
|
|
| from omegaconf import OmegaConf |
|
|
| from trinity.common.constants import ( |
| EXPLORER_NAME, |
| LOG_DIR_ENV_VAR, |
| LOG_LEVEL_ENV_VAR, |
| LOG_NODE_IP_ENV_VAR, |
| PLUGIN_DIRS_ENV_VAR, |
| TRAINER_NAME, |
| PromptType, |
| SaveStrategy, |
| StorageType, |
| SyncMethod, |
| SyncStyle, |
| ) |
| from trinity.utils.annotations import Experimental |
| from trinity.utils.log import get_logger |
|
|
| logger = get_logger(__name__) |
|
|
|
|
| def set_if_none(obj, attr, val): |
| if getattr(obj, attr, None) is None: |
| setattr(obj, attr, val) |
|
|
|
|
| @dataclass |
| class FormatConfig: |
| """Configuration for data formatting""" |
|
|
| |
| prompt_type: PromptType = PromptType.MESSAGES |
|
|
| |
| prompt_key: str = "prompt" |
| response_key: str = "response" |
| system_prompt_key: Optional[str] = None |
| system_prompt: Optional[str] = None |
|
|
| |
| messages_key: str = "message" |
|
|
| |
| tools_key: str = "tools" |
| image_key: Optional[str] = None |
| video_key: Optional[str] = None |
|
|
| reply_prefix: Optional[str] = None |
|
|
| |
| workflow_key: str = "" |
| reward_fn_key: str = "" |
|
|
| |
| chosen_key: str = "chosen" |
| rejected_key: str = "rejected" |
|
|
| |
| enable_concatenated_multi_turn: bool = False |
|
|
| |
| chat_template: Optional[str] = None |
|
|
| |
| |
| teacher_hint_key: Optional[str] = None |
|
|
|
|
| @dataclass |
| class GenerationConfig: |
| temperature: Optional[float] = None |
| top_p: Optional[float] = None |
| top_k: int = -1 |
| logprobs: Optional[int] = None |
| max_tokens: Optional[int] = None |
| |
| |
| n: int = 1 |
|
|
|
|
| @dataclass |
| class OptimizerConfig: |
| lr: float = 1e-6 |
| lr_warmup_steps: int = -1 |
| lr_warmup_steps_ratio: float = 0.0 |
| min_lr_ratio: float = 0.0 |
| warmup_style: Optional[str] = None |
| lr_scheduler_type: str = "constant" |
| optimizer_type: str = "adam" |
| betas: List[float] = field(default_factory=lambda: [0.9, 0.999]) |
| weight_decay: float = 0.01 |
| clip_grad: float = 1.0 |
|
|
|
|
| @dataclass |
| class LoRAConfig: |
| """LoRA config, only effective for rollout model, not for auxiliary models.""" |
|
|
| name: Optional[str] = None |
| path: Optional[str] = None |
| base_model_name: Optional[str] = None |
| lora_rank: int = 32 |
| lora_alpha: int = 32 |
| lora_dtype: str = "auto" |
| target_modules: str = "all-linear" |
| exclude_modules: Optional[str] = None |
| is_dummy: bool = False |
|
|
|
|
| @Experimental |
| @dataclass |
| class TaskSelectorConfig: |
| """Data selector config.""" |
|
|
| selector_type: Optional[str] = "sequential" |
|
|
| |
| seed: int = 42 |
|
|
| |
| feature_keys: List[str] = field(default_factory=lambda: []) |
| kwargs: dict = field(default_factory=dict) |
|
|
|
|
| @dataclass |
| class ReplayBufferConfig: |
| """Config for replay buffer used in StorageType.QUEUE.""" |
|
|
| enable: bool = False |
| priority_fn: str = "linear_decay" |
| reuse_cooldown_time: Optional[float] = None |
| priority_fn_args: Dict = field(default_factory=lambda: {"decay": 2.0}) |
|
|
|
|
| @dataclass |
| class OverRolloutConfig: |
| """Config for over-rollout in explorer.""" |
|
|
| ratio: float = 0.0 |
| wait_after_min: float = 30.0 |
| |
| |
|
|
|
|
| @dataclass |
| class DynamicTimeoutConfig: |
| """Config for dynamic timeout in explorer.""" |
|
|
| enable: bool = False |
| ratio: float = 3.0 |
|
|
|
|
| @dataclass |
| class StorageConfig: |
| """Storage config for both taskset and experience buffer. |
| Not visible to users directly. Please use ExperienceBufferConfig or TasksetConfig instead. |
| """ |
|
|
| name: str = "" |
| storage_type: str = StorageType.FILE.value |
| path: Optional[str] = None |
| repeat_times: Optional[int] = None |
|
|
| |
| index: int = 0 |
|
|
| |
| split: str = "train" |
| subset_name: Optional[str] = None |
| format: FormatConfig = field(default_factory=FormatConfig) |
|
|
| |
| capacity: int = 10000 |
| max_read_timeout: float = 1800 |
| replay_buffer: Optional[ReplayBufferConfig] = field(default_factory=ReplayBufferConfig) |
|
|
| |
| max_retry_times: int = 3 |
| max_retry_interval: int = 1 |
|
|
| |
| default_workflow_type: Optional[str] = None |
| default_reward_fn_type: Optional[str] = None |
| rollout_args: GenerationConfig = field(default_factory=GenerationConfig) |
| workflow_args: dict = field(default_factory=dict) |
| reward_fn_args: dict = field(default_factory=dict) |
| task_selector: TaskSelectorConfig = field(default_factory=TaskSelectorConfig) |
|
|
| |
| enable_progress_bar: Optional[bool] = False |
|
|
| |
| ray_namespace: Optional[str] = None |
|
|
| |
| wrap_in_ray: bool = True |
|
|
| |
| schema_type: Optional[str] = None |
|
|
| |
| total_epochs: int = 1 |
|
|
| |
| total_steps: Optional[int] = None |
|
|
| |
| batch_size: int = 0 |
|
|
| |
| tokenizer_path: Optional[str] = None |
|
|
| |
| is_eval: bool = False |
|
|
|
|
| @dataclass |
| class TasksetConfig: |
| name: str = "" |
| storage_type: str = StorageType.FILE.value |
| path: Optional[str] = None |
|
|
| default_workflow_type: Optional[str] = None |
| default_reward_fn_type: Optional[str] = None |
| rollout_args: GenerationConfig = field(default_factory=GenerationConfig) |
| workflow_args: dict = field(default_factory=dict) |
| reward_fn_args: dict = field(default_factory=dict) |
| task_selector: TaskSelectorConfig = field(default_factory=TaskSelectorConfig) |
|
|
| |
| split: str = "train" |
| subset_name: Optional[str] = None |
| format: FormatConfig = field(default_factory=FormatConfig) |
|
|
| |
| max_retry_times: int = 3 |
| max_retry_interval: int = 1 |
|
|
| enable_progress_bar: bool = False |
|
|
| |
| repeat_times: int = 1 |
| |
| index: int = 0 |
| |
| is_eval: bool = False |
| |
| batch_size: int = 0 |
| |
| total_epochs: int = 1 |
| |
| total_steps: Optional[int] = None |
| |
| ray_namespace: Optional[str] = None |
|
|
| def to_storage_config(self) -> StorageConfig: |
| storage_config = StorageConfig( |
| name=self.name, |
| storage_type=self.storage_type, |
| path=self.path, |
| task_selector=self.task_selector, |
| repeat_times=self.repeat_times, |
| split=self.split, |
| subset_name=self.subset_name, |
| format=self.format, |
| max_retry_times=self.max_retry_times, |
| max_retry_interval=self.max_retry_interval, |
| default_workflow_type=self.default_workflow_type, |
| default_reward_fn_type=self.default_reward_fn_type, |
| rollout_args=self.rollout_args, |
| workflow_args=self.workflow_args, |
| reward_fn_args=self.reward_fn_args, |
| enable_progress_bar=self.enable_progress_bar, |
| index=self.index, |
| is_eval=self.is_eval, |
| batch_size=self.batch_size, |
| total_epochs=self.total_epochs, |
| total_steps=self.total_steps, |
| ray_namespace=self.ray_namespace, |
| ) |
| return storage_config |
|
|
|
|
| @dataclass |
| class ExperienceBufferConfig: |
| """Storage Config for trainer input experience buffer.""" |
|
|
| name: str = "" |
| storage_type: str = StorageType.QUEUE.value |
| path: Optional[str] = None |
|
|
| |
| capacity: int = 10000 |
| max_read_timeout: float = 1800 |
| replay_buffer: Optional[ReplayBufferConfig] = field(default_factory=ReplayBufferConfig) |
|
|
| |
| max_retry_times: int = 3 |
| max_retry_interval: int = 1 |
|
|
| |
| split: str = "train" |
| subset_name: Optional[str] = None |
| format: FormatConfig = field(default_factory=FormatConfig) |
| enable_progress_bar: Optional[bool] = False |
|
|
| |
| schema_type: Optional[str] = None |
| |
| index: int = 0 |
| |
| batch_size: int = 0 |
| |
| tokenizer_path: Optional[str] = None |
| |
| total_epochs: int = 1 |
| |
| total_steps: Optional[int] = None |
| |
| ray_namespace: Optional[str] = None |
|
|
| def to_storage_config(self) -> StorageConfig: |
| storage_config = StorageConfig( |
| name=self.name, |
| storage_type=self.storage_type, |
| path=self.path, |
| capacity=self.capacity, |
| max_read_timeout=self.max_read_timeout, |
| replay_buffer=self.replay_buffer, |
| max_retry_times=self.max_retry_times, |
| max_retry_interval=self.max_retry_interval, |
| split=self.split, |
| subset_name=self.subset_name, |
| format=self.format, |
| enable_progress_bar=self.enable_progress_bar, |
| schema_type=self.schema_type, |
| index=self.index, |
| batch_size=self.batch_size, |
| tokenizer_path=self.tokenizer_path, |
| total_epochs=self.total_epochs, |
| total_steps=self.total_steps, |
| ray_namespace=self.ray_namespace, |
| ) |
| return storage_config |
|
|
|
|
| @dataclass |
| class OperatorConfig: |
| name: str = "" |
| args: Dict[str, Any] = field(default_factory=dict) |
|
|
|
|
| @Experimental |
| @dataclass |
| class ExperiencePipelineConfig: |
| """Config for experience pipeline. |
| |
| Experience Pipeline is used to pre-process rollout experiences for better training. |
| """ |
|
|
| |
| operators: List[OperatorConfig] = field(default_factory=list) |
| save_input: bool = True |
| |
| input_save_path: Optional[str] = None |
|
|
| |
|
|
| |
| |
| inputs: Dict[str, ExperienceBufferConfig] = field(default_factory=dict) |
| |
| output: Optional[ExperienceBufferConfig] = None |
|
|
|
|
| @Experimental |
| @dataclass |
| class TaskPipelineConfig: |
| """Config for task pipeline. |
| |
| Task Pipeline is used to pre-process raw tasks for better exploring. Currently, we only support using |
| Data-Juicer operators for task pipeline. |
| """ |
|
|
| |
| operators: List[OperatorConfig] = field(default_factory=list) |
| |
| num_process: int = 4 |
| |
| config_path: Optional[str] = None |
|
|
| |
| |
| inputs: List[str] = field(default_factory=list) |
| |
| output: Optional[TasksetConfig] = None |
|
|
| |
| target_fields: List[str] = field(default_factory=list) |
|
|
| |
| |
| |
| |
| |
| priority_weights: Dict[str, float] = field(default_factory=dict) |
|
|
| |
| top_k: int = -1 |
|
|
|
|
| @Experimental |
| @dataclass |
| class DataProcessorConfig: |
| """Data Processor config""" |
|
|
| |
| |
| task_pipeline: Optional[TaskPipelineConfig] = None |
| |
| experience_pipeline: Optional[ExperiencePipelineConfig] = field( |
| default_factory=ExperiencePipelineConfig |
| ) |
|
|
|
|
| @dataclass |
| class TinkerConfig: |
| enable: bool = False |
| rank: int = 32 |
| seed: Optional[int] = None |
| train_mlp: bool = True |
| train_attn: bool = True |
| train_unembed: bool = True |
|
|
|
|
| @dataclass |
| class ModelConfig: |
| |
| model_path: str = "" |
| critic_model_path: str = "" |
|
|
| custom_chat_template: Optional[str] = None |
| chat_template_path: Optional[ |
| str |
| ] = None |
|
|
| |
| temperature: float = 1.0 |
| top_p: float = 1.0 |
| top_k: int = -1 |
| logprobs: int = 0 |
|
|
| |
| max_model_len: Optional[int] = None |
|
|
| |
| |
|
|
| |
| max_prompt_tokens: Optional[int] = None |
| |
| max_response_tokens: Optional[int] = None |
| |
| min_response_tokens: int = 0 |
| |
| |
| enable_prompt_truncation: bool = True |
| |
| repetition_penalty: float = 1.0 |
|
|
| |
| lora_configs: Optional[List[LoRAConfig]] = None |
| fully_sharded_loras: bool = False |
| max_cpu_loras: Optional[int] = None |
|
|
| |
| rope_scaling: Optional[dict] = None |
| rope_theta: Optional[float] = None |
|
|
| |
| tinker: TinkerConfig = field(default_factory=TinkerConfig) |
|
|
|
|
| @dataclass |
| class InferenceModelConfig: |
| |
| model_path: Optional[str] = None |
| name: Optional[str] = None |
|
|
| engine_type: str = "vllm" |
| engine_num: int = 1 |
| tensor_parallel_size: int = 1 |
| use_v1: bool = True |
| enforce_eager: bool = False |
| enable_prefix_caching: bool = True |
| enable_chunked_prefill: bool = True |
| gpu_memory_utilization: float = 0.9 |
| dtype: str = "bfloat16" |
| seed: int = 42 |
|
|
| |
| temperature: Optional[float] = None |
| top_p: Optional[float] = None |
| top_k: Optional[int] = None |
| logprobs: Optional[int] = None |
|
|
| |
| max_model_len: Optional[int] = None |
| |
| max_prompt_tokens: Optional[int] = None |
| |
| max_response_tokens: Optional[int] = None |
| |
| min_response_tokens: Optional[int] = None |
| |
| enable_prompt_truncation: Optional[bool] = None |
| |
| repetition_penalty: Optional[float] = None |
| |
| ignore_eos: bool = False |
|
|
| |
| chat_template: Optional[str] = None |
|
|
| |
| enable_thinking: bool = False |
|
|
| |
| enable_history: bool = False |
|
|
| |
| enable_openai_api: bool = False |
| enable_log_requests: bool = False |
|
|
| |
| enable_auto_tool_choice: bool = False |
|
|
| tool_call_parser: Optional[str] = None |
|
|
| reasoning_parser: Optional[str] = None |
|
|
| |
| bundle_indices: str = "" |
| ray_namespace: Optional[str] = None |
|
|
| |
| enable_lora: bool = False |
| enable_runtime_lora_updating: bool = False |
| lora_modules: Optional[List[Dict]] = None |
| lora_kwargs: Optional[dict] = field(default_factory=dict) |
|
|
| |
| rope_scaling: Optional[dict] = None |
| rope_theta: Optional[float] = None |
|
|
|
|
| @dataclass |
| class AlgorithmConfig: |
| """Config for algorithm.""" |
|
|
| algorithm_type: str = "ppo" |
| |
| repeat_times: int = 1 |
|
|
| optimizer: OptimizerConfig = field(default_factory=OptimizerConfig) |
|
|
| |
| sample_strategy: Optional[str] = None |
| sample_strategy_args: Optional[dict] = None |
|
|
| advantage_fn: Optional[str] = None |
| |
| advantage_fn_args: Optional[dict] = None |
|
|
| kl_penalty_fn: Optional[str] = None |
| |
| kl_penalty_fn_args: Optional[dict] = None |
|
|
| policy_loss_fn: Optional[str] = None |
| |
| policy_loss_fn_args: Optional[dict] = None |
|
|
| kl_loss_fn: Optional[str] = None |
| |
| kl_loss_fn_args: Optional[dict] = None |
|
|
| entropy_loss_fn: Optional[str] = None |
| |
| entropy_loss_fn_args: Optional[dict] = None |
|
|
| |
| |
| loss_agg_mode: Optional[str] = None |
|
|
|
|
| @dataclass |
| class ClusterConfig: |
| """Config for the cluster.""" |
|
|
| ray_address: str = "auto" |
| node_num: int = 0 |
| gpu_per_node: int = 0 |
|
|
| |
| total_gpu_num: int = 0 |
| rollout_gpu_num: int = 0 |
| auxiliary_model_gpu_num: int = 0 |
| explorer_gpu_num: int = 0 |
| trainer_gpu_num: int = 0 |
| trainer_node_num: int = 0 |
| trainer_gpu_num_per_node: int = 0 |
|
|
|
|
| @Experimental |
| @dataclass |
| class ExplorerInput: |
| """Config for explorer input.""" |
|
|
| taskset: Optional[TasksetConfig] = None |
| tasksets: List[TasksetConfig] = field(default_factory=list) |
| eval_tasksets: List[TasksetConfig] = field(default_factory=list) |
| |
| default_workflow_type: Optional[str] = None |
| default_eval_workflow_type: Optional[str] = None |
| default_reward_fn_type: Optional[str] = None |
|
|
|
|
| @dataclass |
| class TrainerInput: |
| """Config for trainer input.""" |
|
|
| |
| |
| experience_buffer: Optional[ExperienceBufferConfig] = None |
|
|
| |
| auxiliary_buffers: Dict[str, ExperienceBufferConfig] = field(default_factory=dict) |
|
|
|
|
| @dataclass |
| class BufferConfig: |
| """Config for buffer.""" |
|
|
| batch_size: int = 1 |
| train_batch_size: int = 0 |
| total_epochs: int = 1 |
| total_steps: Optional[int] = None |
|
|
| |
| explorer_input: ExplorerInput = field(default_factory=ExplorerInput) |
|
|
| |
| trainer_input: TrainerInput = field(default_factory=TrainerInput) |
|
|
| |
| explorer_output: Optional[StorageConfig] = None |
| tokenizer_path: Optional[str] = None |
| pad_token_id: Optional[int] = None |
| cache_dir: Optional[str] = None |
|
|
|
|
| @dataclass |
| class ExplorerConfig: |
| """Config for explorer.""" |
|
|
| name: str = EXPLORER_NAME |
| |
| |
| runner_per_model: int = 8 |
| max_timeout: int = 1800 |
| max_retry_times: int = 2 |
| env_vars: dict = field(default_factory=dict) |
|
|
| |
| |
| |
| |
| |
| |
| |
| concurrent_mode: str = "sequential" |
| |
| |
| max_repeat_times_per_runner: Optional[int] = None |
|
|
| runner_num: Optional[int] = None |
|
|
| |
| |
| rollout_model: InferenceModelConfig = field(default_factory=InferenceModelConfig) |
| |
| auxiliary_models: List[InferenceModelConfig] = field(default_factory=list) |
|
|
| |
| eval_interval: int = 100 |
| eval_on_startup: bool = True |
|
|
| |
| bench_on_latest_checkpoint: bool = False |
|
|
| |
| proxy_port: int = 8010 |
| |
| listen_address: str = "0.0.0.0" |
| |
| service_status_check_interval: int = 60 |
| |
| min_running_model_num: int = 1 |
| |
| db_url: Optional[str] = None |
|
|
| |
| over_rollout: OverRolloutConfig = field(default_factory=OverRolloutConfig) |
| dynamic_timeout: DynamicTimeoutConfig = field(default_factory=DynamicTimeoutConfig) |
| |
| runner_state_report_interval: int = 0 |
|
|
|
|
| @dataclass |
| class TrainerConfig: |
| name: str = TRAINER_NAME |
| trainer_type: str = "verl" |
| trainer_strategy: str = "fsdp" |
| save_interval: int = 0 |
| enable_preview: bool = True |
| total_steps: Optional[ |
| int |
| ] = None |
|
|
| save_hf_checkpoint: str = "last" |
| |
| |
| |
|
|
| |
| grad_clip: float = 1.0 |
| use_dynamic_bsz: bool = True |
| |
| max_token_len_per_gpu: Optional[int] = None |
| ulysses_sequence_parallel_size: int = 1 |
| fix_actor_microbatch_loss_scale: bool = False |
| |
|
|
| save_strategy: SaveStrategy = SaveStrategy.UNRESTRICTED |
| max_checkpoints_to_keep: Optional[int] = None |
|
|
| trainer_config: Any = field(default_factory=dict) |
| trainer_config_path: str = "" |
|
|
|
|
| @dataclass |
| class MonitorConfig: |
| |
| monitor_type: str = "tensorboard" |
| |
| monitor_args: Optional[Dict] = None |
| |
| detailed_stats: bool = False |
| |
| |
| enable_ray_timeline: bool = False |
| |
| cache_dir: str = "" |
|
|
|
|
| @dataclass |
| class SynchronizerConfig: |
| """Configs for model weight synchronization.""" |
|
|
| sync_method: SyncMethod = SyncMethod.NCCL |
| sync_style: SyncStyle = SyncStyle.FIXED |
| |
| sync_interval: int = 1 |
| |
| sync_offset: int = 0 |
| |
| sync_timeout: int = 3600 |
| |
| wait_for_checkpoint: bool = False |
|
|
| |
| explorer_world_size: Optional[int] = None |
| ray_namespace: str = "" |
|
|
|
|
| @dataclass |
| class DataJuicerServiceConfig: |
| """Config for Data-Juicer. |
| |
| Please update `trinity.service.data_juicer.server.server.py` correspondingly if you change the fields here. |
| """ |
|
|
| |
| server_url: Optional[str] = None |
|
|
| |
| auto_start: bool = False |
|
|
| |
| |
| port: Optional[int] = None |
| |
|
|
|
|
| @dataclass |
| class ServiceConfig: |
| """Configs for outside services.""" |
|
|
| data_juicer: Optional[DataJuicerServiceConfig] = None |
|
|
|
|
| @dataclass |
| class LogConfig: |
| """Configs for logger.""" |
|
|
| level: str = "INFO" |
| group_by_node: bool = False |
| |
| save_dir: str = "" |
|
|
|
|
| @dataclass |
| class StageConfig: |
| """Configs for a stage.""" |
|
|
| stage_name: str |
| mode: Optional[str] = None |
| algorithm: Optional[AlgorithmConfig] = None |
| buffer: Optional[BufferConfig] = None |
| data_processor: Optional[DataProcessorConfig] = None |
| explorer: Optional[ExplorerConfig] = None |
| trainer: Optional[TrainerConfig] = None |
|
|
|
|
| @dataclass |
| class Config: |
| """Global Configuration""" |
|
|
| mode: str = "both" |
| project: str = "Trinity-RFT" |
| group: str = "" |
| name: str = "rft" |
| |
| checkpoint_root_dir: str = "" |
| |
| checkpoint_job_dir: str = "" |
| |
| ray_namespace: str = "" |
| |
| continue_from_checkpoint: bool = True |
|
|
| algorithm: AlgorithmConfig = field(default_factory=AlgorithmConfig) |
| data_processor: DataProcessorConfig = field(default_factory=DataProcessorConfig) |
| model: ModelConfig = field(default_factory=ModelConfig) |
| cluster: ClusterConfig = field(default_factory=ClusterConfig) |
| buffer: BufferConfig = field(default_factory=BufferConfig) |
| explorer: ExplorerConfig = field(default_factory=ExplorerConfig) |
| trainer: TrainerConfig = field(default_factory=TrainerConfig) |
| monitor: MonitorConfig = field(default_factory=MonitorConfig) |
| synchronizer: SynchronizerConfig = field(default_factory=SynchronizerConfig) |
| service: ServiceConfig = field(default_factory=ServiceConfig) |
| log: LogConfig = field(default_factory=LogConfig) |
|
|
| |
| stages: List[StageConfig] = field(default_factory=list) |
|
|
| def save(self, config_path: str) -> None: |
| """Save config to file.""" |
| with open(config_path, "w", encoding="utf-8") as f: |
| OmegaConf.save(self, f) |
|
|
| def __iter__(self): |
| """Iterate over configs with each stage applied in order. |
| |
| Yields: |
| Config: The config after applying each stage. |
| """ |
| for stage in self.stages: |
| new_config = deepcopy(self) |
| for field_name in stage.__dataclass_fields__: |
| stage_value = getattr(stage, field_name) |
| if stage_value is not None and hasattr(new_config, field_name): |
| setattr(new_config, field_name, stage_value) |
| if stage.stage_name: |
| new_config.name = f"{self.name}/{stage.stage_name}" |
| |
| new_config.trainer.save_hf_checkpoint = "last" |
| new_config.stages = [] |
| yield new_config |
|
|
| def check_and_update(self) -> Config: |
| """Check and update the config.""" |
| from trinity.common.config_validator import validators |
|
|
| |
| for validator in validators: |
| validator.validate(self) |
| return self |
|
|
| def flatten(self) -> Dict[str, Any]: |
| """Flatten the config into a single-level dict with dot-separated keys for nested fields.""" |
|
|
| def _flatten(obj, parent_key="", sep="."): |
| items = {} |
| if hasattr(obj, "__dataclass_fields__"): |
| obj = vars(obj) |
| if isinstance(obj, dict): |
| for k, v in obj.items(): |
| new_key = f"{parent_key}{sep}{k}" if parent_key else k |
| items.update(_flatten(v, new_key, sep=sep)) |
| elif isinstance(obj, list): |
| for i, v in enumerate(obj): |
| new_key = f"{parent_key}{sep}{i}" if parent_key else str(i) |
| items.update(_flatten(v, new_key, sep=sep)) |
| elif isinstance(obj, Enum): |
| items[parent_key] = obj.value |
| else: |
| items[parent_key] = obj |
| return items |
|
|
| return _flatten(self) |
|
|
| def get_envs(self) -> Dict[str, str]: |
| """Get the environment variables from the config.""" |
| return { |
| PLUGIN_DIRS_ENV_VAR: os.getenv(PLUGIN_DIRS_ENV_VAR, ""), |
| LOG_LEVEL_ENV_VAR: self.log.level, |
| LOG_DIR_ENV_VAR: self.log.save_dir, |
| LOG_NODE_IP_ENV_VAR: "1" if self.log.group_by_node else "0", |
| } |
|
|
|
|
| def load_config(config_path: str) -> Config: |
| """Load the configuration from the given path.""" |
| |
| schema = OmegaConf.structured(Config) |
| yaml_config = OmegaConf.load(config_path) |
| try: |
| config = OmegaConf.merge(schema, yaml_config) |
| return OmegaConf.to_object(config) |
| except Exception as e: |
| raise ValueError(f"Invalid configuration: {e}") from e |
|
|