Commit Graph

3 Commits

Author SHA1 Message Date
Alpamys 1491025a36 feat(trainer): Optimizer & PEFT Zoo (v0.41.0)
Optimizer Zoo (Part A): closed-allowlist SUPPORTED_OPTIMIZERS adds 14 new
entries — BAdam, APOLLO (apollo_adamw), Adam-mini, lomo / adalomo,
grokadamw, schedule_free_adamw / schedule_free_sgd, muon, dion,
came_pytorch, ao_adamw_{fp8,4bit,8bit}. Validates name + lower-cases
deterministically; rejects non-string / empty / null-byte / >64-char.
_OPTIMIZER_PACKAGES wrapped in MappingProxyType (matches v0.36.0 _REGISTRY).

Per-module LR (Part B): training.lr_groups accepts list-of-pairs /
list-of-dicts / {pattern: lr} mapping; canonical [{pattern, lr}, ...]
storage. Capped at MAX_LR_GROUPS=32; per-pattern non-empty string
≤256 chars + null-byte rejection + re.compile + best-effort ReDoS probe;
per-LR (0.0, 1.0] + math.isfinite (rejects NaN AND ±inf) + bool rejection
(matches v0.30.0 Candidate policy); duplicates rejected. lr_groups_from_schema
bridges canonical schema shape into runtime List[LrGroup] for
build_optimizer_param_groups (first-match-wins routing). LrGroup is
@dataclass(frozen=True). PyYAML scientific-notation (1e-4) parses as
string in YAML 1.1; _validate_lr coerces str → float so soup.yaml
round-trips work. base_lr rejects bool / non-positive (defence-in-depth).

PEFT methods (Part C): LoraConfig.init_strategy="loftq" + loftq_iter
∈ [1, 10] + loftq_bits ∈ {2, 4, 8}; cross-validator rejects loftq +
use_dora / use_vera. utils/loftq_init.py exposes validators +
build_loftq_config (lazy peft.LoftQConfig with actionable ImportError
hint). LLaMA Pro: TrainingConfig.expand_layers ∈ [1, 64] +
freeze_trainable_layers (signed, |x| ≤ 1000); cross-validator requires
the pair (LLaMA Pro freezes original layers and trains only new blocks).
field_validator(mode="before") on both rejects bool BEFORE Pydantic ge/le
silently coerces True → 1. expand_model_blocks raises NotImplementedError
with v0.41.1 marker — schema-only release (mirrors v0.27.0 / v0.37.0
stub-then-live pattern). utils/block_expansion._count_layers uses
hasattr(__len__) instead of try/except TypeError so legitimate __len__
bugs surface loudly. use_mod boolean for Mixture-of-Depths (schema only —
live patch deferred to v0.41.1).

Friendly aliases: load_in_8bit / load_in_16bit (Optional[bool]) for
LlamaFactory / Axolotl users. is True policy on both — explicit False is
"no preference", not "off"; mutually-exclusive both-True rejected; alias
combined with explicit Quant Menu format raises rather than silently
overriding. Alias-driven quantization rewrite via direct
self.quantization = ... (Pydantic v2 BaseModel non-frozen path), NOT
object.__setattr__ — code review caught that the latter would silently
bypass any future field_validator on quantization.

Five review agents (4 in parallel + manual smoke for verification-loop):
all CRITICAL/HIGH/MEDIUM/LOW findings fixed. Local smoke caught a real
bug — PyYAML parsing 1e-4 as string — fixed pre-commit with 2 added tests.

5242 tests pass (+120 net new); ruff clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 15:35:35 +05:00
Alpamys 56bea56c08 fix(v0.40.1): QA Hardening — UTF-8 bootstrap, schema strictness, multi-objective preference runtime, CLI UX
Closes the QA findings from the Windows + RTX 3050 4 GB pass (2026-05-07):
- Part A: UTF-8 stdio bootstrap on Windows (closes C1/C4/H1/N5/N8/G5)
- Part B: root-level `lora:` migrates into training.lora (no more silent
  init_strategy bypass); multi-objective preference loss runtime no longer
  raises NotImplementedError (primary-loss approximation; full per-batch
  weighted combination deferred to v0.40.2)
- Part C: autopilot 7B → 1B fallback + safetensors cache probe;
  transformers <5.0.0 cap with INCOMPATIBLE flag in `soup doctor`;
  quickstart auto-switches to SmolLM2-135M on ≤6 GB VRAM; --find-lr
  load_local → load_raw_data import fix
- Part D (subset): dynamic --template help (H4); init --force (M2);
  migrate JSONL friendly error (N2); eval custom -o independent of
  attach-to-registry + loop-shadow bug fix (G10); history suggests
  dataset registry (N6); doctor importlib.metadata fallback (M1) +
  GPU diagnostic distinguishes CPU build (N3) + dual-Python detector (N4)
- Part E: recipe fuzzy-match suggestions (M3); sample filename embeds
  strategy (no overwrite); JSONL BOM auto-strip

Net +64 tests (4656 → 4720). 4 review agents clean (python/code/security/tdd).
Long-tail UX papercuts (H2/H3/N7/M4/M5 + #36/#50/#51) deferred to v0.40.2.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 12:03:16 +05:00
Alpamys e6a9c087c3 feat(lora): v0.39.0 — LoRA Quality (PiSSA + ReLoRA + per-pattern rank + surgical patches + templates registry)
Five PEFT-surface improvements that LlamaFactory and Axolotl maintain:

- LoraConfig.init_strategy Literal["random","pissa","olora"]; PiSSA SVD init
  via PEFT init_lora_weights="pissa". Back-compat: use_olora=True aligns to
  init_strategy="olora" via dict-copy model_validator(mode="before"); explicit
  conflict (use_olora=True + init_strategy="pissa"/"random") rejected.
  Mutual-exclusion vs DoRA / VeRA.

- ReLoRA callback (utils/relora.py): frozen ReLoRAPolicy with bounds-checked
  steps [1, 1e7] / warmup_ratio [0,1] / prune_ratio (0,1) (strict — prevents
  zero-everything footgun); magnitude_prune_tensor (in-place torch.kthvalue,
  rejects non-Tensor / single-element short-circuit); duck-typed
  ReLoRACallback (no transformers import at module load). TrainingConfig
  fields relora_steps / relora_warmup_ratio / relora_reset_optimizer /
  relora_prune_ratio. SoupConfig _validate_relora_supported_tasks gates to
  task=sft + transformers backend with distinct MLX-backend error message;
  multi-trainer expansion deferred to v0.39.1 (mirrors v0.27.0 MII /
  v0.37.0 multipack / v0.38.0 quant menu stub-then-live pattern).

- LoraConfig.rank_pattern / alpha_pattern Optional[Dict[str,int]]; field
  validator caps at 256 keys × value (0, 1024], rejects bool / null-byte /
  empty key. Cross-validator rejects with use_vera=True (VeRA shares one
  rank). peft_builder propagates into LoraConfig init_kwargs.

- utils/peft_patches.py: is_gemma4_model uses regex word boundary
  (?:^|[^a-z0-9])gemma-?4(?:[^a-z0-9]|$) so "ungemma4ed" no longer matches.
  apply_gemma4_clippable_patch swaps ClippableLinear → nn.Linear by class
  name (weight-copy fallback logs at DEBUG). strip_lora_dropout_for_3d_experts
  zeroes lora_dropout.p on 3-D weights (handles ModuleDict variant for
  PEFT >=0.10). apply_surgical_patches orchestrator validates model_name.
  Wired into sft.py _setup_transformers with is_gemma4_model gate before
  the pre-LoRA swap; post-LoRA 3-D dropout strip runs unconditionally
  (architecture-detected internally).

- 16 inline templates migrated to soup_cli/templates/*.yaml + manifest.json
  + load_template loader (path-traversal-rejecting name validator;
  os.path.realpath + commonpath containment so a tampered manifest cannot
  read files outside the package directory; 256 KB file-size cap with
  inline fallback). Inline TEMPLATES kept with deprecation comment
  (planned removal v0.41.0+); test_templates_yaml asserts byte-equality
  of all 16 inline ↔ YAML pairs to prevent silent drift.

Net +164 tests (4374 → 4538). All 5 review-agent waves clean before tag.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 16:18:07 +05:00