td-builder commited on
Commit
a6bf422
·
verified ·
1 Parent(s): ad06f87

Upload 149 files

Browse files
Files changed (1) hide show
  1. hugging/td_fuse/selfimprove.py +278 -76
hugging/td_fuse/selfimprove.py CHANGED
@@ -1,18 +1,19 @@
1
  """
2
- TD Self-Improvement v5 — Full Weight Intelligence + Unclogged Layernorms
3
-
4
- CYCLE 2 FIXES (from cycle 1 learnings):
5
- 1. UNFREEZE LAYERNORMS — The worst issues (kurtosis 89, 90) are in layernorms
6
- and k_norms. LoRA can't touch those. Now we directly train them.
7
- 2. HIGHER LORA RANK — r=64 instead of r=32 for more capacity to reshape weights
8
- 3. FIX CODE DATA — CodeAlpaca uses instruction/input/output, not prompt/completion
9
- 4. FIX MMLU FORMAT — No more "The answer is A" multiple choice contamination
10
- 5. AUTO-DETECT CYCLE — Runs from cycle 1 output if it exists, otherwise from healed
11
- 6. QUICK BENCHMARK — 5 questions at the end to sanity-check actual model capability
12
-
13
- The key insight: LoRA only modifies projection weights (q/k/v/o/gate/up/down).
14
- But the WORST health issues are in layernorm and k_norm parameters.
15
- Those need to be directly unfrozen and trained — "unclogging the pipes."
 
16
  """
17
 
18
  import torch
@@ -34,25 +35,25 @@ class SelfImproveConfig:
34
  model_path: str = "" # Auto-detected below
35
  reference_model: str = "Qwen/Qwen3-VL-8B-Instruct"
36
  output_dir: str = "td_fuse_outputs/self_improve"
 
37
 
38
  # How many layers to target
39
  top_n_layers: int = 16
40
  min_improvement_score: float = 0.05
41
 
42
- # LoRA config — higher rank for cycle 2
43
- lora_r: int = 64 # Up from 32 — more capacity to reshape
44
- lora_alpha: int = 128 # 2x rank as usual
45
  train_epochs: int = 3
46
  train_batch: int = 2
47
  train_grad_accum: int = 8
48
  learning_rate: float = 1.5e-5
49
- norm_learning_rate: float = 5e-5 # Higher LR for layernorms (they're stubborn)
50
- save_steps: int = 50
51
  num_train_samples: int = 3000
52
 
53
  # Layernorm unfreezing
54
- unfreeze_norms_for_layers: List[int] = None # Auto-detected from analysis
55
- norm_kurtosis_threshold: float = 15.0 # Unfreeze norms with kurtosis above this
56
 
57
  # Scoring weights
58
  w_health: float = 0.55
@@ -60,6 +61,28 @@ class SelfImproveConfig:
60
  w_coherence: float = 0.20
61
 
62
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
  def auto_detect_model_path() -> Tuple[str, int]:
64
  """Find the best starting model and determine cycle number."""
65
  base = Path("td_fuse_outputs/self_improve")
@@ -441,9 +464,6 @@ def detect_clogged_norms(health_scores: Dict[str, Dict], threshold: float = 15.0
441
  """
442
  clogged = []
443
  for name, h in health_scores.items():
444
- # Only look at norm layers
445
- # Qwen3-VL has: input_layernorm, post_attention_layernorm
446
- # Also check for any norm-like parameter (norm, ln)
447
  if any(norm_type in name.lower() for norm_type in ["layernorm", "ln_", "_norm"]):
448
  kurt = abs(h["stats"]["kurtosis"])
449
  if kurt > threshold:
@@ -452,6 +472,91 @@ def detect_clogged_norms(health_scores: Dict[str, Dict], threshold: float = 15.0
452
  return clogged
453
 
454
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
455
  # ============================================================
456
  # STEP 6: LoRA + UNFROZEN NORMS IMPROVEMENT
457
  # ============================================================
@@ -486,6 +591,11 @@ def improve_with_lora(model_path: str, target_layers: List[int],
486
  )
487
  tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
488
 
 
 
 
 
 
489
  # Apply LoRA on projection weights
490
  lora_config = LoraConfig(
491
  r=cfg.lora_r,
@@ -522,34 +632,28 @@ def improve_with_lora(model_path: str, target_layers: List[int],
522
  print(f"\n LoRA trainable + {unfrozen_count} unfrozen norm layers ({unfrozen_params:,} params)")
523
  model.print_trainable_parameters()
524
 
525
- # Load DIVERSE training data — 5 categories, ALL BUGS FIXED
526
- print("\n Loading diverse training data...")
 
527
  train_texts = []
528
- per_category = cfg.num_train_samples // 5
529
 
530
- # Category 1: General text
531
- try:
532
- ds = load_dataset("neuralmagic/LLM_compression_calibration", split="train")
533
- count = 0
534
- for row in ds:
535
- if count >= per_category:
536
- break
537
- text = row.get("text", "")
538
- if len(text) > 100:
539
- chat = (f"<|im_start|>user\nContinue this text naturally.<|im_end|>\n"
540
- f"<|im_start|>assistant\n{text[:800]}<|im_end|>")
541
- train_texts.append(chat)
542
- count += 1
543
- print(f" General text: {count}")
544
- except Exception as e:
545
- print(f" WARNING: General text failed: {e}")
546
 
547
- # Category 2: Math reasoning
548
  try:
549
  ds = load_dataset("openai/gsm8k", "main", split="train")
550
  count = 0
551
  for row in ds:
552
- if count >= per_category:
553
  break
554
  q, a = row.get("question", ""), row.get("answer", "")
555
  if q and a:
@@ -557,72 +661,149 @@ def improve_with_lora(model_path: str, target_layers: List[int],
557
  f"<|im_start|>assistant\n<think>\n{a}\n</think><|im_end|>")
558
  train_texts.append(chat)
559
  count += 1
560
- print(f" Math reasoning: {count}")
561
  except Exception as e:
562
- print(f" WARNING: Math data failed: {e}")
563
 
564
- # Category 3: Code — FIXED: correct field names
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
565
  try:
566
  ds = load_dataset("sahil2801/CodeAlpaca-20k", split="train")
567
  count = 0
568
  for row in ds:
569
- if count >= per_category:
570
  break
571
- # CodeAlpaca uses instruction/input/output, NOT prompt/completion
572
  inst = row.get("instruction", "")
573
  inp = row.get("input", "")
574
  out = row.get("output", "")
575
- if inst and out:
576
  prompt = f"{inst}\n{inp}" if inp else inst
577
  chat = (f"<|im_start|>user\n{prompt}<|im_end|>\n"
578
  f"<|im_start|>assistant\n{out}<|im_end|>")
579
  train_texts.append(chat)
580
  count += 1
581
- print(f" Code: {count}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
582
  except Exception as e:
583
- print(f" WARNING: Code data failed: {e}")
584
 
585
- # Category 4: Instruction following
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
586
  try:
587
  ds = load_dataset("yahma/alpaca-cleaned", split="train")
588
  count = 0
589
  for row in ds:
590
- if count >= per_category:
591
  break
592
  inst = row.get("instruction", "")
593
  inp = row.get("input", "")
594
  out = row.get("output", "")
595
- if inst and out:
596
  prompt = f"{inst}\n{inp}" if inp else inst
597
  chat = (f"<|im_start|>user\n{prompt}<|im_end|>\n"
598
  f"<|im_start|>assistant\n{out}<|im_end|>")
599
  train_texts.append(chat)
600
  count += 1
601
- print(f" Instructions: {count}")
602
  except Exception as e:
603
- print(f" WARNING: Instruction data failed: {e}")
604
 
605
- # Category 5: Reasoning — FIXED: proper format, no "answer is A/B/C"
606
  try:
607
- ds = load_dataset("TIGER-Lab/MMLU-Pro", split="test")
608
  count = 0
609
  for row in ds:
610
- if count >= per_category:
611
  break
612
- q = row.get("question", "")
613
- # Get the actual answer text from options using answer_index
614
- options = row.get("options", [])
615
- answer_idx = row.get("answer_index", -1)
616
- if q and options and 0 <= answer_idx < len(options):
617
- answer_text = options[answer_idx]
618
- chat = (f"<|im_start|>user\n{q}<|im_end|>\n"
619
- f"<|im_start|>assistant\n<think>\nLet me reason through this.\n"
620
- f"{answer_text}\n</think>\n{answer_text}<|im_end|>")
621
  train_texts.append(chat)
622
  count += 1
623
- print(f" Reasoning/logic: {count}")
624
  except Exception as e:
625
- print(f" WARNING: Reasoning data failed: {e}")
626
 
627
  print(f"\n Total training samples: {len(train_texts)}")
628
 
@@ -685,6 +866,7 @@ def improve_with_lora(model_path: str, target_layers: List[int],
685
  gradient_accumulation_steps=cfg.train_grad_accum,
686
  learning_rate=cfg.learning_rate,
687
  bf16=True,
 
688
  logging_steps=max(1, total_steps // 20),
689
  save_strategy="steps",
690
  save_steps=cfg.save_steps,
@@ -803,13 +985,22 @@ def run_cycle(cfg: SelfImproveConfig = None):
803
  else:
804
  cycle_num = 2 if "improve" in cfg.model_path else 1
805
 
 
 
 
 
806
  start = time.time()
 
807
  print("=" * 60)
808
- print(f"TD SELF-IMPROVEMENT v5 — NORM UNCLOGGING + LoRA")
809
  print(f"Cycle: {cycle_num}")
810
  print(f"Model: {cfg.model_path}")
811
- print(f"LoRA rank: {cfg.lora_r} (up from 32)")
 
 
812
  print(f"Norm training: ENABLED (LR={cfg.norm_learning_rate})")
 
 
813
  print(f"Started: {time.strftime('%H:%M:%S')}")
814
  print("=" * 60)
815
 
@@ -842,8 +1033,7 @@ def run_cycle(cfg: SelfImproveConfig = None):
842
  )
843
  ref_analysis = analyze_model_weights(str(ref_path), "Qwen3-VL-8B (reference)")
844
  damage_scores = compute_damage_scores(model_analysis, ref_analysis)
845
- print(f" Cleaning up reference...")
846
- shutil.rmtree(str(ref_path), ignore_errors=True)
847
  gc.collect()
848
 
849
  # STEP 4: Coherence
@@ -870,6 +1060,18 @@ def run_cycle(cfg: SelfImproveConfig = None):
870
  else:
871
  print(f"\n No clogged norms above threshold {cfg.norm_kurtosis_threshold}")
872
 
 
 
 
 
 
 
 
 
 
 
 
 
873
  # Save report
874
  report_dir = Path(cfg.output_dir)
875
  report_dir.mkdir(parents=True, exist_ok=True)
 
1
  """
2
+ TD Self-Improvement v6 — MEGA CYCLE
3
+
4
+ v5 fixes + MEGA MODE for cycle 3+:
5
+ - 8000+ training samples (was 3000)
6
+ - Priority: code, math, reasoning, creativity (top), then general (second)
7
+ - LoRA r=128 (was 64) — maximum reshape capacity
8
+ - ALL 36 layers targeted (was 16)
9
+ - gradient_checkpointing for speed + VRAM savings
10
+ - batch_size 4 (was 2) — 2x faster per step
11
+ - Norm unclogging continues from cycle 2
12
+
13
+ SPEED OPTIMIZATIONS:
14
+ - gradient_checkpointing = True (saves ~40% VRAM, allows bigger batches)
15
+ - batch_size 4 + grad_accum 4 = effective batch 16 (same quality, faster)
16
+ - Processes 2x more samples per forward pass = ~2x faster wall clock
17
  """
18
 
19
  import torch
 
35
  model_path: str = "" # Auto-detected below
36
  reference_model: str = "Qwen/Qwen3-VL-8B-Instruct"
37
  output_dir: str = "td_fuse_outputs/self_improve"
38
+ mega_mode: bool = False # Auto-enabled for cycle 3+
39
 
40
  # How many layers to target
41
  top_n_layers: int = 16
42
  min_improvement_score: float = 0.05
43
 
44
+ # LoRA config
45
+ lora_r: int = 64
46
+ lora_alpha: int = 128
47
  train_epochs: int = 3
48
  train_batch: int = 2
49
  train_grad_accum: int = 8
50
  learning_rate: float = 1.5e-5
51
+ norm_learning_rate: float = 5e-5
52
+ save_steps: int = 100
53
  num_train_samples: int = 3000
54
 
55
  # Layernorm unfreezing
56
+ norm_kurtosis_threshold: float = 15.0
 
57
 
58
  # Scoring weights
59
  w_health: float = 0.55
 
61
  w_coherence: float = 0.20
62
 
63
 
64
+ def apply_mega_mode(cfg: SelfImproveConfig):
65
+ """Crank everything up for mega cycles (3+)."""
66
+ print("\n *** MEGA MODE ENABLED ***")
67
+ cfg.mega_mode = True
68
+ cfg.top_n_layers = 36 # ALL layers — leave nothing behind
69
+ cfg.min_improvement_score = 0.0 # Target everything
70
+ cfg.lora_r = 128 # Maximum reshape capacity
71
+ cfg.lora_alpha = 256 # 2x rank
72
+ cfg.train_epochs = 3 # 3 epochs over 8000 samples = plenty
73
+ cfg.train_batch = 4 # 2x bigger batch — 2x faster
74
+ cfg.train_grad_accum = 4 # Effective batch = 16 (same quality)
75
+ cfg.num_train_samples = 8000 # Nearly 3x more data
76
+ cfg.learning_rate = 1e-5 # Slightly lower LR for stability with more data
77
+ cfg.norm_learning_rate = 1e-3 # Much higher — norms need strong signal to move during training
78
+ cfg.save_steps = 200 # Save less often (faster)
79
+ print(f" LoRA: r={cfg.lora_r}, alpha={cfg.lora_alpha}")
80
+ print(f" Layers: ALL {cfg.top_n_layers}")
81
+ print(f" Data: {cfg.num_train_samples} samples")
82
+ print(f" Batch: {cfg.train_batch} × {cfg.train_grad_accum} = {cfg.train_batch * cfg.train_grad_accum}")
83
+ print(f" Speed: gradient_checkpointing + batch 4")
84
+
85
+
86
  def auto_detect_model_path() -> Tuple[str, int]:
87
  """Find the best starting model and determine cycle number."""
88
  base = Path("td_fuse_outputs/self_improve")
 
464
  """
465
  clogged = []
466
  for name, h in health_scores.items():
 
 
 
467
  if any(norm_type in name.lower() for norm_type in ["layernorm", "ln_", "_norm"]):
468
  kurt = abs(h["stats"]["kurtosis"])
469
  if kurt > threshold:
 
472
  return clogged
473
 
474
 
475
+ def repair_clogged_norms(model_path: str, clogged_norms: List[str],
476
+ ref_path: str, health_scores: Dict[str, Dict]) -> str:
477
+ """
478
+ DIRECT SURGICAL REPAIR of clogged layernorms.
479
+
480
+ Training can't fix kurtosis of 2446 — gradient signal too weak for 1D norms.
481
+ Instead: blend broken norms with reference values.
482
+
483
+ Strategy:
484
+ - Kurtosis > 100: 80% reference, 20% current (severely broken)
485
+ - Kurtosis > 50: 60% reference, 40% current
486
+ - Kurtosis > 15: 40% reference, 60% current (mildly clogged)
487
+
488
+ This is like replacing a clogged pipe instead of pushing harder.
489
+ """
490
+ if not clogged_norms:
491
+ print(" No clogged norms to repair.")
492
+ return model_path
493
+
494
+ print(f"\n{'='*50}")
495
+ print(f"SURGICAL NORM REPAIR — {len(clogged_norms)} clogged norms")
496
+ print(f"{'='*50}")
497
+
498
+ from safetensors.torch import load_file, save_file
499
+ import glob
500
+
501
+ # Load reference norms
502
+ print(" Loading reference norms...")
503
+ ref_norms = {}
504
+ for st_file in sorted(glob.glob(f"{ref_path}/*.safetensors")):
505
+ state = load_file(st_file, device="cpu")
506
+ for name, tensor in state.items():
507
+ if name in clogged_norms:
508
+ ref_norms[name] = tensor.clone()
509
+ del state
510
+
511
+ print(f" Matched {len(ref_norms)}/{len(clogged_norms)} norms in reference")
512
+
513
+ if not ref_norms:
514
+ print(" WARNING: No reference norms found! Skipping repair.")
515
+ return model_path
516
+
517
+ # Load and repair model weights
518
+ repaired = 0
519
+ st_files = sorted(glob.glob(f"{model_path}/*.safetensors"))
520
+
521
+ for st_file in st_files:
522
+ state = load_file(st_file, device="cpu")
523
+ changed = False
524
+
525
+ for name in list(state.keys()):
526
+ if name in ref_norms:
527
+ kurt = abs(health_scores[name]["stats"]["kurtosis"])
528
+
529
+ # Blend ratio based on severity
530
+ if kurt > 100:
531
+ ref_weight = 0.80 # Severely broken — mostly use reference
532
+ elif kurt > 50:
533
+ ref_weight = 0.60
534
+ else:
535
+ ref_weight = 0.40 # Mildly clogged
536
+
537
+ old_tensor = state[name]
538
+ ref_tensor = ref_norms[name].to(old_tensor.dtype)
539
+
540
+ # Blend: new = ref_weight * reference + (1-ref_weight) * current
541
+ state[name] = ref_weight * ref_tensor + (1 - ref_weight) * old_tensor
542
+
543
+ # Compute new kurtosis
544
+ t = state[name].float()
545
+ new_kurt = abs(((t - t.mean()) / max(t.std().item(), 1e-8)).pow(4).mean().item() - 3)
546
+
547
+ print(f" {name}: kurtosis {kurt:.1f} → {new_kurt:.1f} (blend {ref_weight:.0%} ref)")
548
+ repaired += 1
549
+ changed = True
550
+
551
+ if changed:
552
+ save_file(state, st_file)
553
+ del state
554
+
555
+ gc.collect()
556
+ print(f"\n Repaired {repaired} norms via reference blending")
557
+ return model_path
558
+
559
+
560
  # ============================================================
561
  # STEP 6: LoRA + UNFROZEN NORMS IMPROVEMENT
562
  # ============================================================
 
591
  )
592
  tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
593
 
594
+ # Enable gradient checkpointing for mega mode (saves ~40% VRAM)
595
+ if cfg.mega_mode:
596
+ model.gradient_checkpointing_enable()
597
+ print(" Gradient checkpointing: ENABLED (saves ~40% VRAM)")
598
+
599
  # Apply LoRA on projection weights
600
  lora_config = LoraConfig(
601
  r=cfg.lora_r,
 
632
  print(f"\n LoRA trainable + {unfrozen_count} unfrozen norm layers ({unfrozen_params:,} params)")
633
  model.print_trainable_parameters()
634
 
635
+ # Load training data — priority-weighted categories
636
+ # MEGA MODE: code/math/reasoning/creativity get 2x allocation
637
+ print("\n Loading training data...")
638
  train_texts = []
639
+ total = cfg.num_train_samples
640
 
641
+ if cfg.mega_mode:
642
+ # Priority split: code=2000, math=2000, reasoning=1500, creativity=1000, instructions=1000, general=500
643
+ alloc = {"code": int(total*0.25), "math": int(total*0.25),
644
+ "reasoning": int(total*0.19), "creativity": int(total*0.12),
645
+ "instructions": int(total*0.12), "general": int(total*0.07)}
646
+ else:
647
+ per = total // 5
648
+ alloc = {"code": per, "math": per, "reasoning": per,
649
+ "creativity": 0, "instructions": per, "general": per}
 
 
 
 
 
 
 
650
 
651
+ # 1. MATH (top priority)
652
  try:
653
  ds = load_dataset("openai/gsm8k", "main", split="train")
654
  count = 0
655
  for row in ds:
656
+ if count >= alloc["math"]:
657
  break
658
  q, a = row.get("question", ""), row.get("answer", "")
659
  if q and a:
 
661
  f"<|im_start|>assistant\n<think>\n{a}\n</think><|im_end|>")
662
  train_texts.append(chat)
663
  count += 1
664
+ print(f" Math (GSM8K): {count}")
665
  except Exception as e:
666
+ print(f" WARNING: GSM8K failed: {e}")
667
 
668
+ # Extra math for mega mode — harder competition math
669
+ if cfg.mega_mode and count < alloc["math"]:
670
+ try:
671
+ ds2 = load_dataset("lighteval/MATH", "all", split="train", trust_remote_code=True)
672
+ extra = 0
673
+ for row in ds2:
674
+ if count + extra >= alloc["math"]:
675
+ break
676
+ q = row.get("problem", "")
677
+ a = row.get("solution", "")
678
+ if q and a:
679
+ chat = (f"<|im_start|>user\n{q}\nSolve this step by step.<|im_end|>\n"
680
+ f"<|im_start|>assistant\n<think>\n{a}\n</think><|im_end|>")
681
+ train_texts.append(chat)
682
+ extra += 1
683
+ print(f" Math (MATH hard): {extra}")
684
+ except Exception as e:
685
+ print(f" WARNING: MATH dataset failed: {e}")
686
+
687
+ # 2. CODE (top priority)
688
  try:
689
  ds = load_dataset("sahil2801/CodeAlpaca-20k", split="train")
690
  count = 0
691
  for row in ds:
692
+ if count >= alloc["code"]:
693
  break
 
694
  inst = row.get("instruction", "")
695
  inp = row.get("input", "")
696
  out = row.get("output", "")
697
+ if inst and out and len(out) > 20:
698
  prompt = f"{inst}\n{inp}" if inp else inst
699
  chat = (f"<|im_start|>user\n{prompt}<|im_end|>\n"
700
  f"<|im_start|>assistant\n{out}<|im_end|>")
701
  train_texts.append(chat)
702
  count += 1
703
+ print(f" Code (CodeAlpaca): {count}")
704
+ except Exception as e:
705
+ print(f" WARNING: CodeAlpaca failed: {e}")
706
+
707
+ # Extra code for mega mode
708
+ if cfg.mega_mode and count < alloc["code"]:
709
+ try:
710
+ ds2 = load_dataset("m-a-p/CodeFeedback-Filtered-Instruction", split="train")
711
+ extra = 0
712
+ for row in ds2:
713
+ if count + extra >= alloc["code"]:
714
+ break
715
+ q = row.get("query", "")
716
+ a = row.get("answer", "")
717
+ if q and a and len(a) > 30:
718
+ chat = (f"<|im_start|>user\n{q}<|im_end|>\n"
719
+ f"<|im_start|>assistant\n{a[:1500]}<|im_end|>")
720
+ train_texts.append(chat)
721
+ extra += 1
722
+ print(f" Code (CodeFeedback): {extra}")
723
+ except Exception as e:
724
+ print(f" WARNING: CodeFeedback failed: {e}")
725
+
726
+ # 3. REASONING (top priority)
727
+ try:
728
+ ds = load_dataset("TIGER-Lab/MMLU-Pro", split="test")
729
+ count = 0
730
+ for row in ds:
731
+ if count >= alloc["reasoning"]:
732
+ break
733
+ q = row.get("question", "")
734
+ options = row.get("options", [])
735
+ answer_idx = row.get("answer_index", -1)
736
+ if q and options and 0 <= answer_idx < len(options):
737
+ answer_text = options[answer_idx]
738
+ chat = (f"<|im_start|>user\n{q}<|im_end|>\n"
739
+ f"<|im_start|>assistant\n<think>\nLet me reason through this.\n"
740
+ f"{answer_text}\n</think>\n{answer_text}<|im_end|>")
741
+ train_texts.append(chat)
742
+ count += 1
743
+ print(f" Reasoning (MMLU-Pro): {count}")
744
  except Exception as e:
745
+ print(f" WARNING: MMLU-Pro failed: {e}")
746
 
747
+ # 4. CREATIVITY (mega mode priority)
748
+ if alloc.get("creativity", 0) > 0:
749
+ try:
750
+ ds = load_dataset("yahma/alpaca-cleaned", split="train")
751
+ count = 0
752
+ creative_words = ["write", "story", "poem", "creative", "imagine", "describe",
753
+ "compose", "draft", "narrative", "fiction", "essay", "letter",
754
+ "explain", "summarize", "rewrite", "paraphrase"]
755
+ for row in ds:
756
+ if count >= alloc["creativity"]:
757
+ break
758
+ inst = row.get("instruction", "").lower()
759
+ out = row.get("output", "")
760
+ if any(w in inst for w in creative_words) and out and len(out) > 50:
761
+ inp = row.get("input", "")
762
+ prompt = f"{row['instruction']}\n{inp}" if inp else row["instruction"]
763
+ chat = (f"<|im_start|>user\n{prompt}<|im_end|>\n"
764
+ f"<|im_start|>assistant\n{out}<|im_end|>")
765
+ train_texts.append(chat)
766
+ count += 1
767
+ print(f" Creativity (Alpaca filtered): {count}")
768
+ except Exception as e:
769
+ print(f" WARNING: Creativity data failed: {e}")
770
+
771
+ # 5. INSTRUCTIONS (general)
772
  try:
773
  ds = load_dataset("yahma/alpaca-cleaned", split="train")
774
  count = 0
775
  for row in ds:
776
+ if count >= alloc.get("instructions", 0):
777
  break
778
  inst = row.get("instruction", "")
779
  inp = row.get("input", "")
780
  out = row.get("output", "")
781
+ if inst and out and len(out) > 30:
782
  prompt = f"{inst}\n{inp}" if inp else inst
783
  chat = (f"<|im_start|>user\n{prompt}<|im_end|>\n"
784
  f"<|im_start|>assistant\n{out}<|im_end|>")
785
  train_texts.append(chat)
786
  count += 1
787
+ print(f" Instructions (Alpaca): {count}")
788
  except Exception as e:
789
+ print(f" WARNING: Alpaca failed: {e}")
790
 
791
+ # 6. GENERAL TEXT (lowest priority)
792
  try:
793
+ ds = load_dataset("neuralmagic/LLM_compression_calibration", split="train")
794
  count = 0
795
  for row in ds:
796
+ if count >= alloc.get("general", 0):
797
  break
798
+ text = row.get("text", "")
799
+ if len(text) > 100:
800
+ chat = (f"<|im_start|>user\nContinue this text naturally.<|im_end|>\n"
801
+ f"<|im_start|>assistant\n{text[:800]}<|im_end|>")
 
 
 
 
 
802
  train_texts.append(chat)
803
  count += 1
804
+ print(f" General text: {count}")
805
  except Exception as e:
806
+ print(f" WARNING: General text failed: {e}")
807
 
808
  print(f"\n Total training samples: {len(train_texts)}")
809
 
 
866
  gradient_accumulation_steps=cfg.train_grad_accum,
867
  learning_rate=cfg.learning_rate,
868
  bf16=True,
869
+ gradient_checkpointing=cfg.mega_mode, # Saves ~40% VRAM in mega mode
870
  logging_steps=max(1, total_steps // 20),
871
  save_strategy="steps",
872
  save_steps=cfg.save_steps,
 
985
  else:
986
  cycle_num = 2 if "improve" in cfg.model_path else 1
987
 
988
+ # MEGA MODE for cycle 3+
989
+ if cycle_num >= 3 and not cfg.mega_mode:
990
+ apply_mega_mode(cfg)
991
+
992
  start = time.time()
993
+ mode_label = "MEGA CYCLE" if cfg.mega_mode else "NORM UNCLOGGING + LoRA"
994
  print("=" * 60)
995
+ print(f"TD SELF-IMPROVEMENT v6 — {mode_label}")
996
  print(f"Cycle: {cycle_num}")
997
  print(f"Model: {cfg.model_path}")
998
+ print(f"LoRA rank: {cfg.lora_r}")
999
+ print(f"Samples: {cfg.num_train_samples}")
1000
+ print(f"Batch: {cfg.train_batch} × {cfg.train_grad_accum} = {cfg.train_batch * cfg.train_grad_accum}")
1001
  print(f"Norm training: ENABLED (LR={cfg.norm_learning_rate})")
1002
+ if cfg.mega_mode:
1003
+ print(f"Gradient checkpointing: ENABLED")
1004
  print(f"Started: {time.strftime('%H:%M:%S')}")
1005
  print("=" * 60)
1006
 
 
1033
  )
1034
  ref_analysis = analyze_model_weights(str(ref_path), "Qwen3-VL-8B (reference)")
1035
  damage_scores = compute_damage_scores(model_analysis, ref_analysis)
1036
+ # DON'T delete reference yet — we need it for norm repair
 
1037
  gc.collect()
1038
 
1039
  # STEP 4: Coherence
 
1060
  else:
1061
  print(f"\n No clogged norms above threshold {cfg.norm_kurtosis_threshold}")
1062
 
1063
+ # STEP 5c: REPAIR clogged norms surgically
1064
+ if clogged_norms:
1065
+ print(f"\n{'='*40}")
1066
+ print("STEP 5c/7: SURGICAL NORM REPAIR")
1067
+ print(f"{'='*40}")
1068
+ repair_clogged_norms(cfg.model_path, clogged_norms, str(ref_path), health_scores)
1069
+
1070
+ # Clean up reference now
1071
+ print(f" Cleaning up reference weights...")
1072
+ shutil.rmtree(str(ref_path), ignore_errors=True)
1073
+ gc.collect()
1074
+
1075
  # Save report
1076
  report_dir = Path(cfg.output_dir)
1077
  report_dir.mkdir(parents=True, exist_ok=True)