refactor: migrate config system to Pydantic dataclasses

- Replace hand-rolled BaseConfig (from_dict/to_dict/_coerce/_unwrap_optional) with pydantic.dataclasses
- from_dict now uses cls(**d), to_dict uses dataclasses.asdict + json.dumps filter
- TrainConfig: required fields are now truly required (no default=None), delete manual validate()/__post_init__
- Remove dead required() helper and metadata={'help': ...} annotations
- Fix gradient_checkpointing_modules type from List[str] to List[type]
- Add pydantic>=2.0 as direct dependency in pyproject.toml
- Add numpy-style Parameters docstrings to all config classes
- Enable use_attribute_docstrings in BaseConfig for schema generation
- LoRAConfig also migrated to pydantic dataclass
This commit is contained in:
2026-07-30 08:25:32 +08:00
parent 6a97524db4
commit 164be9708b
7 changed files with 218 additions and 314 deletions
+17 -77
View File
@@ -1,92 +1,32 @@
import json import json
from dataclasses import MISSING, dataclass, fields from dataclasses import asdict
from pathlib import Path from pathlib import Path
from typing import Any, Dict, Optional, Self, Union, get_type_hints from typing import Any, Dict, Self, Union
from pydantic import ConfigDict
from pydantic.dataclasses import dataclass
@dataclass @dataclass(config=ConfigDict(use_attribute_docstrings=True))
class BaseConfig: class BaseConfig:
def to_dict(self) -> Dict[str, Any]: def to_dict(self) -> Dict[str, Any]:
d = {} result = {}
for fld in fields(self): for k, v in asdict(self).items():
v = getattr(self, fld.name) if isinstance(v, tuple):
if isinstance(v, (str, int, float, bool)): v = list(v)
d[fld.name] = v
elif v is None:
d[fld.name] = None
elif isinstance(v, (dict, list, tuple)):
try: try:
val = list(v) if isinstance(v, tuple) else v json.dumps(v)
json.dumps(val) result[k] = v
d[fld.name] = val
except (TypeError, ValueError): except (TypeError, ValueError):
# Skip non-serializable runtime objects (e.g. model_fn, dataset).
# TrainConfig mixes hyperparams with callables/datasets; only the
# JSON-serializable subset is written to checkpoint meta.
pass pass
elif isinstance(v, BaseConfig): return result
d[fld.name] = v.to_dict()
elif hasattr(v, "__dataclass_fields__"):
sub = {}
for f in fields(v):
a = getattr(v, f.name)
sub[f.name] = list(a) if isinstance(a, tuple) else a
d[fld.name] = sub
return d
@classmethod @classmethod
def from_dict(cls, d: Dict[str, Any]) -> Self: def from_dict(cls, d: Dict[str, Any]) -> Self:
hints = get_type_hints(cls) return cls(**d)
inst = cls.__new__(cls)
for fld in fields(cls):
if fld.name in d:
v = d[fld.name]
target = cls._unwrap_optional(hints.get(fld.name))
if target is not None:
try:
v = cls._coerce(v, target)
except (TypeError, ValueError):
pass
object.__setattr__(inst, fld.name, v)
elif fld.default is not MISSING:
object.__setattr__(inst, fld.name, fld.default)
elif fld.default_factory is not MISSING:
object.__setattr__(inst, fld.name, fld.default_factory())
else:
object.__setattr__(inst, fld.name, None)
return inst
@staticmethod
def _unwrap_optional(tp) -> Optional[type]:
if tp is None:
return None
origin = getattr(tp, "__origin__", None)
if origin is not None:
args = getattr(tp, "__args__", ())
non_none = [a for a in args if a is not type(None)]
return non_none[0] if non_none else None
return tp
@staticmethod
def _coerce(value: Any, target_type: type) -> Any:
if target_type is bool and isinstance(value, bool):
return value
if (
target_type is int
and isinstance(value, (int, float))
and not isinstance(value, bool)
):
return int(value)
if (
target_type is float
and isinstance(value, (int, float))
and not isinstance(value, bool)
):
return float(value)
if target_type is str and isinstance(value, str):
return value
if isinstance(value, target_type):
return value
if isinstance(value, dict) and issubclass(target_type, BaseConfig):
return target_type.from_dict(value)
raise TypeError
@classmethod @classmethod
def from_file(cls, path: Union[str, Path]) -> Self: def from_file(cls, path: Union[str, Path]) -> Self:
+58 -11
View File
@@ -1,6 +1,7 @@
from dataclasses import dataclass
from typing import Any, Dict, Optional from typing import Any, Dict, Optional
from pydantic.dataclasses import dataclass
from astrai.config.base import BaseConfig from astrai.config.base import BaseConfig
from astrai.factory import BaseFactory from astrai.factory import BaseFactory
@@ -17,7 +18,12 @@ class ConfigFactory(BaseFactory[BaseConfig]):
@dataclass @dataclass
class BaseModelConfig(BaseConfig): class BaseModelConfig(BaseConfig):
"""Base config with ``model_type`` dispatch and file I/O.""" """Base config with ``model_type`` dispatch and file I/O.
Args:
model_type (Optional[str]): Model type identifier for AutoModel dispatch. Defaults to None.
neftune_alpha (float): NEFTune noise alpha, 0=disabled, typical: 5.0. Defaults to 0.0.
"""
model_type: Optional[str] = None model_type: Optional[str] = None
neftune_alpha: float = 0.0 neftune_alpha: float = 0.0
@@ -26,7 +32,34 @@ class BaseModelConfig(BaseConfig):
@dataclass @dataclass
@ConfigFactory.register("autoregressive_lm") @ConfigFactory.register("autoregressive_lm")
class AutoRegressiveLMConfig(BaseModelConfig): class AutoRegressiveLMConfig(BaseModelConfig):
"""Configuration for autoregressive language model.""" """Configuration for autoregressive language model.
Args:
model_type (Optional[str]): Model type identifier for AutoModel dispatch. Defaults to None.
neftune_alpha (float): NEFTune noise alpha, 0=disabled, typical: 5.0. Defaults to 0.0.
vocab_size (Optional[int]): Vocabulary size. Defaults to None.
hidden_size (Optional[int]): Hidden dimension size. Defaults to None.
num_hidden_layers (Optional[int]): Number of transformer layers. Defaults to None.
rms_norm_eps (Optional[float]): Epsilon for RMSNorm. Defaults to None.
intermediate_size (Optional[int]): Intermediate size in FFN. Defaults to None.
tie_word_embeddings (Optional[bool]): Whether to tie embedding and lm_head weights. Defaults to None.
max_position_embeddings (Optional[int]): Maximum sequence length the model was trained with. Defaults to None.
rope_theta (Optional[float]): Base frequency for RoPE. Defaults to None.
rope_scaling (Optional[dict]): RoPE scaling config, e.g. {"type": "linear", "factor": 4.0}. Defaults to None.
attn_type (str): Attention type: 'gqa' or 'mla'. Defaults to "gqa".
num_attention_heads (Optional[int]): Number of query attention heads. Defaults to None.
num_key_value_heads (Optional[int]): Number of key/value heads for GQA. Defaults to None.
use_qk_norm (Optional[bool]): Whether to apply RMSNorm to Q/K. Defaults to None.
use_gated_attention (Optional[bool]): Whether to use gated attention. Defaults to None.
kv_lora_rank (Optional[int]): KV compression rank, MLA only. Defaults to None.
qk_nope_head_dim (Optional[int]): Non-RoPE head dimension, MLA only. Defaults to None.
qk_rope_head_dim (Optional[int]): RoPE head dimension, MLA only. Defaults to None.
ffn_type (str): FFN type: 'mlp' or 'moe'. Defaults to "mlp".
n_routed_experts (Optional[int]): Number of routed experts, MoE only. Defaults to None.
n_shared_experts (Optional[int]): Number of shared experts, MoE only. Defaults to None.
n_activated_experts (Optional[int]): Number of activated experts per token, MoE only. Defaults to None.
topk_method (Optional[str]): Top-k routing method, MoE only. Defaults to None.
"""
vocab_size: Optional[int] = None vocab_size: Optional[int] = None
hidden_size: Optional[int] = None hidden_size: Optional[int] = None
@@ -34,21 +67,17 @@ class AutoRegressiveLMConfig(BaseModelConfig):
rms_norm_eps: Optional[float] = None rms_norm_eps: Optional[float] = None
intermediate_size: Optional[int] = None intermediate_size: Optional[int] = None
tie_word_embeddings: Optional[bool] = None tie_word_embeddings: Optional[bool] = None
max_position_embeddings: Optional[int] = None max_position_embeddings: Optional[int] = None
rope_theta: Optional[float] = None rope_theta: Optional[float] = None
rope_scaling: Optional[dict] = None rope_scaling: Optional[dict] = None
attn_type: str = "gqa" attn_type: str = "gqa"
num_attention_heads: Optional[int] = None num_attention_heads: Optional[int] = None
num_key_value_heads: Optional[int] = None num_key_value_heads: Optional[int] = None
use_qk_norm: Optional[bool] = None use_qk_norm: Optional[bool] = None
use_gated_attention: Optional[bool] = None use_gated_attention: Optional[bool] = None
kv_lora_rank: Optional[int] = None kv_lora_rank: Optional[int] = None
qk_nope_head_dim: Optional[int] = None qk_nope_head_dim: Optional[int] = None
qk_rope_head_dim: Optional[int] = None qk_rope_head_dim: Optional[int] = None
ffn_type: str = "mlp" ffn_type: str = "mlp"
n_routed_experts: Optional[int] = None n_routed_experts: Optional[int] = None
n_shared_experts: Optional[int] = None n_shared_experts: Optional[int] = None
@@ -59,24 +88,42 @@ class AutoRegressiveLMConfig(BaseModelConfig):
@dataclass @dataclass
@ConfigFactory.register("embedding") @ConfigFactory.register("embedding")
class EncoderConfig(BaseModelConfig): class EncoderConfig(BaseModelConfig):
"""Configuration for embedding encoder model.""" """Configuration for embedding encoder model.
Args:
model_type (Optional[str]): Model type identifier for AutoModel dispatch. Defaults to None.
neftune_alpha (float): NEFTune noise alpha, 0=disabled, typical: 5.0. Defaults to 0.0.
vocab_size (Optional[int]): Vocabulary size. Defaults to None.
hidden_size (Optional[int]): Hidden dimension size. Defaults to None.
num_hidden_layers (Optional[int]): Number of transformer layers. Defaults to None.
rms_norm_eps (Optional[float]): Epsilon for RMSNorm. Defaults to None.
intermediate_size (Optional[int]): Intermediate size in FFN. Defaults to None.
max_position_embeddings (Optional[int]): Maximum sequence length the model was trained with. Defaults to None.
rope_theta (Optional[float]): Base frequency for RoPE. Defaults to None.
rope_scaling (Optional[dict]): RoPE scaling config, e.g. {"type": "linear", "factor": 4.0}. Defaults to None.
attn_type (str): Attention type: 'gqa' or 'mla'. Defaults to "gqa".
num_attention_heads (Optional[int]): Number of query attention heads. Defaults to None.
num_key_value_heads (Optional[int]): Number of key/value heads for GQA. Defaults to None.
use_qk_norm (Optional[bool]): Whether to apply RMSNorm to Q/K. Defaults to None.
use_gated_attention (Optional[bool]): Whether to use gated attention. Defaults to None.
ffn_type (str): FFN type: 'mlp' or 'moe'. Defaults to "mlp".
pooling_type (Optional[str]): Pooling strategy for embedding, e.g. 'mean', 'cls'. Defaults to None.
normalize_embeddings (Optional[bool]): Whether to L2-normalize output embeddings. Defaults to None.
"""
vocab_size: Optional[int] = None vocab_size: Optional[int] = None
hidden_size: Optional[int] = None hidden_size: Optional[int] = None
num_hidden_layers: Optional[int] = None num_hidden_layers: Optional[int] = None
rms_norm_eps: Optional[float] = None rms_norm_eps: Optional[float] = None
intermediate_size: Optional[int] = None intermediate_size: Optional[int] = None
max_position_embeddings: Optional[int] = None max_position_embeddings: Optional[int] = None
rope_theta: Optional[float] = None rope_theta: Optional[float] = None
rope_scaling: Optional[dict] = None rope_scaling: Optional[dict] = None
attn_type: str = "gqa" attn_type: str = "gqa"
num_attention_heads: Optional[int] = None num_attention_heads: Optional[int] = None
num_key_value_heads: Optional[int] = None num_key_value_heads: Optional[int] = None
use_qk_norm: Optional[bool] = None use_qk_norm: Optional[bool] = None
use_gated_attention: Optional[bool] = None use_gated_attention: Optional[bool] = None
ffn_type: str = "mlp" ffn_type: str = "mlp"
pooling_type: Optional[str] = None pooling_type: Optional[str] = None
normalize_embeddings: Optional[bool] = None normalize_embeddings: Optional[bool] = None
+35 -45
View File
@@ -5,9 +5,11 @@ modes, both driven declaratively through ``input.sections`` or
``input.sources``. ``input.sources``.
""" """
from dataclasses import dataclass, field from dataclasses import field
from typing import Dict, List, Optional from typing import Dict, List, Optional
from pydantic.dataclasses import dataclass
from astrai.config.base import BaseConfig from astrai.config.base import BaseConfig
@@ -25,6 +27,10 @@ class InputConfig(BaseConfig):
"chosen": {"sections": [{"field": "chosen", ...}]}, "chosen": {"sections": [{"field": "chosen", ...}]},
"rejected": {"sections": [{"field": "rejected", ...}]}, "rejected": {"sections": [{"field": "rejected", ...}]},
}}} }}}
Args:
sections (Optional[List[Dict]]): Section list for single-output mode. Defaults to None.
sources (Optional[Dict[str, Dict]]): Source map for multi-output mode, DPO/GRPO. Defaults to None.
""" """
sections: Optional[List[Dict]] = None sections: Optional[List[Dict]] = None
@@ -33,34 +39,17 @@ class InputConfig(BaseConfig):
@dataclass @dataclass
class ProcessingConfig(BaseConfig): class ProcessingConfig(BaseConfig):
"""Processing configuration. """Processing configuration for tokenization and packing.
Parameters Args:
---------- max_seq_len (int): Maximum sequence length. Defaults to 2048.
max_seq_len : int min_chars (int): Minimum number of characters to keep. Defaults to 50.
Maximum sequence length (default: 2048). max_chars (int): Maximum number of characters to keep. Defaults to 2_000_000.
min_chars : int max_items (Optional[int]): Maximum number of items to process, None=unlimited. Defaults to None.
Minimum number of characters to keep (default: 50). batch_size (int): Number of records tokenized together. Defaults to 256.
max_chars : int packing_strategy (str): How to pack sequences: 'simple', 'bfd', or 'bfd_split'. Defaults to "simple".
Maximum number of characters to keep (default: 2_000_000). max_packed_len (int): Maximum length of a packed bin. Defaults to 8192.
max_items : Optional[int] truncation_mode (str): How to truncate over-length sequences: 'keep_start' or 'keep_end'. Defaults to "keep_start".
Maximum number of items to process (default: None, unlimited).
batch_size : int
Number of records tokenized together (default: 256).
packing_strategy : str
How to pack sequences into a contiguous stream.
- ``"simple"``: sequential concatenation (default, backward compatible).
- ``"bfd"``: best-fit decreasing bin packing, minimises wasted tokens.
- ``"bfd_split"``: BFD with over-length sequences split into chunks.
max_packed_len : int
Maximum length of a packed bin. Sequences longer than this are
truncated or split depending on ``packing_strategy`` (default: 8192).
truncation_mode : str
How to truncate sequences longer than ``max_packed_len``.
- ``"keep_start"``: keep the first ``max_packed_len`` tokens (default).
- ``"keep_end"``: keep the last ``max_packed_len`` tokens.
""" """
max_seq_len: int = 2048 max_seq_len: int = 2048
@@ -75,24 +64,14 @@ class ProcessingConfig(BaseConfig):
@dataclass @dataclass
class OutputConfig(BaseConfig): class OutputConfig(BaseConfig):
"""Output configuration. """Output configuration for storage.
Parameters Args:
---------- domain_key (Optional[str]): Domain key for the output store. Defaults to None.
domain_key : Optional[str] storage_format (str): Storage format: 'bin' or 'jsonl'. Defaults to "bin".
Domain key for the output store (default: None). max_tokens_per_shard (int): Maximum tokens per shard before splitting. Defaults to 100_000_000.
storage_format : str dtype (Dict[str, str]): Per-key dtype overrides, e.g. {"input_ids": "int32"}. Defaults to {}.
Storage format, one of ``"bin"``, ``"jsonl"`` (default: ``"bin"``). position_ids_mode (str): Position ids mode: 'none', 'doc_reset', or 'continuous'. Defaults to "doc_reset".
max_tokens_per_shard : int
Maximum tokens per shard before splitting (default: 100_000_000).
dtype : Dict[str, str]
Per-key dtype overrides, e.g. ``{"input_ids": "int32"}`` (default: {}).
position_ids_mode : Optional[str]
How to compute position_ids in packed sequences.
- ``"none"``: do not generate (default).
- ``"doc_reset"``: reset to 0 at each document boundary.
- ``"continuous"``: sequential 0, 1, 2, ... (pretrain, single doc).
""" """
domain_key: Optional[str] = None domain_key: Optional[str] = None
@@ -104,6 +83,17 @@ class OutputConfig(BaseConfig):
@dataclass @dataclass
class PipelineConfig(BaseConfig): class PipelineConfig(BaseConfig):
"""Top-level preprocessing pipeline config.
Args:
version (int): Config schema version. Defaults to 1.
input (InputConfig): Input mapping config.
mask (Dict[str, str]): Per-field mask labels, e.g. {"system": "mask", "assistant": "train"}. Defaults to {}.
mask_default (str): Default mask label for unlisted fields. Defaults to "mask".
preprocessing (ProcessingConfig): Processing config.
output (OutputConfig): Output config.
"""
version: int = 1 version: int = 1
input: InputConfig = field(default_factory=InputConfig) input: InputConfig = field(default_factory=InputConfig)
mask: Dict[str, str] = field(default_factory=dict) mask: Dict[str, str] = field(default_factory=dict)
+92 -162
View File
@@ -1,7 +1,9 @@
from dataclasses import dataclass, field, fields from dataclasses import field
from typing import Any, Callable, Dict, List, Optional from typing import Any, Callable, Dict, List, Optional
import torch.nn as nn import torch.nn as nn
from pydantic import ConfigDict
from pydantic.dataclasses import dataclass
from torch.optim import Optimizer from torch.optim import Optimizer
from torch.optim.lr_scheduler import LRScheduler from torch.optim.lr_scheduler import LRScheduler
from torch.utils.data import Dataset from torch.utils.data import Dataset
@@ -10,175 +12,103 @@ from astrai.config.base import BaseConfig
from astrai.model.components.lora import LoRAConfig from astrai.model.components.lora import LoRAConfig
def required(**kw): @dataclass(config=ConfigDict(arbitrary_types_allowed=True))
return {"required": True, **kw}
@dataclass
class TrainConfig(BaseConfig): class TrainConfig(BaseConfig):
# basic setting """Training configuration.
model_fn: Callable[[], nn.Module] = field(
default=None, metadata=required(help="Model factory for training.")
)
strategy: str = field(default=None, metadata=required(help="Training strategy."))
dataset: Dataset = field(
default=None, metadata=required(help="Dataset for training.")
)
optimizer_fn: Callable[[nn.Module], Optimizer] = field(
default=None, metadata=required(help="Optimizer factory for training.")
)
scheduler_fn: Callable[[Optimizer], LRScheduler] = field(
default=None, metadata=required(help="Scheduler factory for training.")
)
n_epoch: int = field(default=1, metadata={"help": "Number of epochs for training."})
batch_per_device: int = field(
default=4, metadata={"help": "Batch size per device."}
)
grad_accum_steps: int = field(
default=1, metadata={"help": "Number of iterations between steps."}
)
max_grad_norm: Optional[float] = field(
default=1.0,
metadata={"help": "Maximum gradient norm. None disables clipping."},
)
gradient_checkpointing_modules: List[str] = field(
default_factory=list,
metadata={"help": "Module types to enable activation checkpointing for."},
)
compile_mode: Optional[str] = field(
default=None,
metadata={
"help": "torch.compile mode: 'default', 'reduce-overhead', 'max-autotune', or None to disable."
},
)
# checkpoint setting Combines hyperparameters with runtime objects (model_fn, dataset, etc.).
start_epoch: int = field(default=0, metadata={"help": "Start epoch for training."}) Only JSON-serializable fields are written to checkpoint meta via to_dict().
start_samples: int = field(
default=0,
metadata={
"help": "Start samples count (per rank). Superseded by checkpoint consumed_samples."
},
)
ckpt_dir: str = field(
default="./checkpoint", metadata={"help": "Checkpoint directory."}
)
ckpt_interval: int = field(
default=5000,
metadata={"help": "Number of optimizer steps between checkpoints."},
)
# lora setting Args:
lora: Optional[LoRAConfig] = field( model_fn (Callable[[], nn.Module]): Model factory for training.
default=None, strategy (str): Training strategy (seq, sft, dpo, grpo, online_*).
metadata={"help": "LoRA config. None means full fine-tuning."}, dataset (Dataset): Dataset for training.
) optimizer_fn (Callable[[nn.Module], Optimizer]): Optimizer factory for training.
scheduler_fn (Callable[[Optimizer], LRScheduler]): Scheduler factory for training.
n_epoch (int): Number of epochs for training. Defaults to 1.
batch_per_device (int): Batch size per device. Defaults to 4.
grad_accum_steps (int): Number of iterations between optimizer steps. Defaults to 1.
max_grad_norm (Optional[float]): Maximum gradient norm. None disables clipping. Defaults to 1.0.
gradient_checkpointing_modules (List[type]): Module types to enable activation checkpointing for. Defaults to [].
compile_mode (Optional[str]): torch.compile mode: 'default', 'reduce-overhead', 'max-autotune', or None. Defaults to None.
start_epoch (int): Start epoch for training. Defaults to 0.
start_samples (int): Start samples count (per rank). Superseded by checkpoint consumed_samples. Defaults to 0.
ckpt_dir (str): Checkpoint directory. Defaults to "./checkpoint".
ckpt_interval (int): Number of optimizer steps between checkpoints. Defaults to 5000.
lora (Optional[LoRAConfig]): LoRA config. None means full fine-tuning. Defaults to None.
metrics (List[str]): Metrics to record during training. Defaults to ["loss", "lr", "grad_norm"].
random_seed (int): Random seed. Defaults to 3407.
num_workers (int): Number of workers for dataloader. Defaults to 0.
prefetch_factor (Optional[int]): Prefetch factor for dataloader. Defaults to None.
pin_memory (bool): Pin memory for dataloader. Defaults to False.
collate_fn (Optional[Callable[[List[Any]], Any]]): Collate function for dataloader (e.g. dpo_collate_fn). Defaults to None.
nprocs (int): Number of processes for distributed training. Defaults to 1.
backend (str): Distributed training backend. Defaults to "nccl".
master_addr (str): Master address for distributed training. Defaults to "localhost".
master_port (str): Master port for distributed training. Defaults to "29500".
parallel_mode (str): Parallel strategy: none, ddp, fsdp. Defaults to "none".
start_method (str): Multiprocessing start method: spawn/fork/forkserver. Defaults to "spawn".
device_type (str): Device type for distributed training. Defaults to "cuda".
val_dataset (Optional[Dataset]): Dataset for validation. Defaults to None.
val_split (Optional[float]): Ratio to split from training dataset for validation, e.g. 0.05. Defaults to None.
val_step (int): Number of optimizer steps between validation runs. Defaults to 1000.
neftune_alpha (float): NEFTune noise alpha, 0=disabled, typical: 5.0. Defaults to 0.0.
rollout_interval (int): Number of optimizer steps between online rollouts. Defaults to 512.
rollout_temperature (float): Sampling temperature for online rollout. Defaults to 0.7.
rollout_top_k (int): Top-k filtering for online rollout, 0=disable. Defaults to 0.
rollout_top_p (float): Top-p (nucleus) filtering for online rollout. Defaults to 0.9.
rollout_max_tokens (int): Maximum generated tokens per response in rollout. Defaults to 1024.
reward_model_fn (Optional[Callable]): Factory for reward model, required for online RL strategies. Defaults to None.
executor_kwargs (Dict[str, Any]): Extra kwargs passed to ExecutorFactory.create(). Defaults to {}.
extra_kwargs (Dict[str, Any]): Other arguments. Defaults to {}.
"""
# metric setting model_fn: Callable[[], nn.Module]
metrics: List[str] = field( strategy: str
default_factory=lambda: ["loss", "lr", "grad_norm"], dataset: Dataset
metadata={"help": "Metrics to record during training."}, optimizer_fn: Callable[[nn.Module], Optimizer]
) scheduler_fn: Callable[[Optimizer], LRScheduler]
n_epoch: int = 1
batch_per_device: int = 4
grad_accum_steps: int = 1
max_grad_norm: Optional[float] = 1.0
gradient_checkpointing_modules: List[type] = field(default_factory=list)
compile_mode: Optional[str] = None
# dataloader setting start_epoch: int = 0
random_seed: int = field(default=3407, metadata={"help": "Random seed."}) start_samples: int = 0
num_workers: int = field( ckpt_dir: str = "./checkpoint"
default=0, metadata={"help": "Number of workers for dataloader."} ckpt_interval: int = 5000
)
prefetch_factor: Optional[int] = field(
default=None, metadata={"help": "Prefetch factor for dataloader."}
)
pin_memory: bool = field(
default=False, metadata={"help": "Pin memory for dataloader."}
)
collate_fn: Optional[Callable[[List[Any]], Any]] = field(
default=None,
metadata={"help": "Collate function for dataloader (e.g. dpo_collate_fn)."},
)
# distributed training lora: Optional[LoRAConfig] = None
nprocs: int = field(
default=1, metadata={"help": "Number of processes for distributed training."}
)
backend: str = field(
default="nccl", metadata={"help": "Distributed training backend."}
)
master_addr: str = field(
default="localhost",
metadata={"help": "Master address for distributed training."},
)
master_port: str = field(
default="29500", metadata={"help": "Master port for distributed training."}
)
parallel_mode: str = field(
default="none",
metadata={"help": "Parallel strategy: none, ddp, fsdp."},
)
start_method: str = field(
default="spawn",
metadata={"help": "Multiprocessing start method (spawn/fork/forkserver)."},
)
# others metrics: List[str] = field(default_factory=lambda: ["loss", "lr", "grad_norm"])
device_type: str = field(
default="cuda", metadata={"help": "Device type for distributed training."}
)
val_dataset: Optional[Dataset] = field(
default=None, metadata={"help": "Dataset for validation."}
)
val_split: Optional[float] = field(
default=None,
metadata={
"help": "Ratio to split from training dataset for validation (e.g. 0.05). Ignored if val_dataset is set."
},
)
val_step: int = field(
default=1000,
metadata={"help": "Number of optimizer steps between validation runs."},
)
neftune_alpha: float = field(
default=0.0,
metadata={"help": "NEFTune noise alpha (0=disabled, typical: 5.0)."},
)
# online rollout random_seed: int = 3407
rollout_interval: int = field( num_workers: int = 0
default=512, prefetch_factor: Optional[int] = None
metadata={"help": "Number of optimizer steps between online rollouts."}, pin_memory: bool = False
) collate_fn: Optional[Callable[[List[Any]], Any]] = None
rollout_temperature: float = field(
default=0.7, metadata={"help": "Sampling temperature for online rollout."}
)
rollout_top_k: int = field(
default=0, metadata={"help": "Top-k filtering for online rollout (0=disable)."}
)
rollout_top_p: float = field(
default=0.9,
metadata={"help": "Top-p (nucleus) filtering for online rollout."},
)
rollout_max_tokens: int = field(
default=1024,
metadata={"help": "Maximum generated tokens per response in rollout."},
)
reward_model_fn: Optional[Callable] = field(
default=None,
metadata={
"help": "Factory for reward model (required for online RL strategies)."
},
)
executor_kwargs: Dict[str, Any] = field( nprocs: int = 1
default_factory=dict, backend: str = "nccl"
metadata={"help": "Extra kwargs passed to ExecutorFactory.create()."}, master_addr: str = "localhost"
) master_port: str = "29500"
extra_kwargs: Dict[str, Any] = field( parallel_mode: str = "none"
default_factory=dict, metadata={"help": "Other arguments."} start_method: str = "spawn"
)
def __post_init__(self): device_type: str = "cuda"
self.validate() val_dataset: Optional[Dataset] = None
val_split: Optional[float] = None
val_step: int = 1000
neftune_alpha: float = 0.0
def validate(self): rollout_interval: int = 512
for fld in fields(self): rollout_temperature: float = 0.7
if fld.metadata.get("required") and getattr(self, fld.name) is None: rollout_top_k: int = 0
raise ValueError(f"TrainConfig.{fld.name} is required but got None.") rollout_top_p: float = 0.9
rollout_max_tokens: int = 1024
reward_model_fn: Optional[Callable] = None
executor_kwargs: Dict[str, Any] = field(default_factory=dict)
extra_kwargs: Dict[str, Any] = field(default_factory=dict)
+10 -15
View File
@@ -22,13 +22,10 @@ class BaseToolParser(ABC):
Maintains streaming state internally so that each call to :meth:`feed` Maintains streaming state internally so that each call to :meth:`feed`
can diff against previously emitted content. can diff against previously emitted content.
Parameters Args:
---------- tools (list of dict, optional): Tool definitions from the request.
tools : list of dict, optional tool_choice (str): ``"auto"`` / ``"required"`` / ``"none"`` or a named
Tool definitions from the request. tool choice dict.
tool_choice : str
``"auto"`` / ``"required"`` / ``"none"`` or a named tool choice
dict.
""" """
def __init__(self, tools: Optional[List[Dict]] = None, tool_choice: str = "auto"): def __init__(self, tools: Optional[List[Dict]] = None, tool_choice: str = "auto"):
@@ -51,14 +48,12 @@ class BaseToolParser(ABC):
Returns an empty list when nothing new should be emitted. Returns an empty list when nothing new should be emitted.
Parameters Args:
---------- body (str): The complete accumulated generated text so far.
body : str current_token_ids (list of int, optional): All token IDs decoded
The complete accumulated generated text so far. into *body* (cumulative).
current_token_ids : list of int, optional delta_token_ids (list of int, optional): Only the token IDs for
All token IDs decoded into *body* (cumulative). this chunk.
delta_token_ids : list of int, optional
Only the token IDs for this chunk.
""" """
@abstractmethod @abstractmethod
+2 -1
View File
@@ -1,11 +1,12 @@
import logging import logging
from dataclasses import asdict, dataclass from dataclasses import asdict
from pathlib import Path from pathlib import Path
from typing import Optional, Set from typing import Optional, Set
import torch import torch
import torch.nn as nn import torch.nn as nn
import torch.nn.functional as F import torch.nn.functional as F
from pydantic.dataclasses import dataclass
from astrai.model.components.linear import Linear from astrai.model.components.linear import Linear
from astrai.serialization import ( from astrai.serialization import (
+1
View File
@@ -15,6 +15,7 @@ dependencies = [
"safetensors==0.5.3", "safetensors==0.5.3",
"huggingface-hub==0.34.3", "huggingface-hub==0.34.3",
"jinja2>=3.0.0", "jinja2>=3.0.0",
"pydantic>=2.0",
"fastapi", "fastapi",
"uvicorn[standard]", "uvicorn[standard]",
"click>=8.0", "click>=8.0",