Upload train_sft.py with huggingface_hub
Browse files- train_sft.py +30 -2
train_sft.py
CHANGED
|
@@ -31,11 +31,35 @@ Jobs box is ephemeral so push_to_hub must be on.
|
|
| 31 |
import argparse
|
| 32 |
|
| 33 |
import torch
|
|
|
|
| 34 |
from datasets import load_dataset
|
| 35 |
from peft import LoraConfig
|
| 36 |
from transformers import AutoModelForImageTextToText, AutoProcessor
|
| 37 |
from trl import SFTConfig, SFTTrainer
|
| 38 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 39 |
|
| 40 |
def build_collator(processor, model_config):
|
| 41 |
"""Render our (system/user/assistant + image) rows into a batch.
|
|
@@ -133,11 +157,15 @@ def main():
|
|
| 133 |
|
| 134 |
# Adapt attention + MLP projections across the language tower; leave the
|
| 135 |
# vision encoder frozen (grounding signal comes from the LM reading tokens).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 136 |
peft_config = LoraConfig(
|
| 137 |
r=16, lora_alpha=32, lora_dropout=0.05, bias="none",
|
| 138 |
task_type="CAUSAL_LM",
|
| 139 |
-
target_modules=
|
| 140 |
-
"gate_proj", "up_proj", "down_proj"],
|
| 141 |
modules_to_save=None,
|
| 142 |
)
|
| 143 |
|
|
|
|
| 31 |
import argparse
|
| 32 |
|
| 33 |
import torch
|
| 34 |
+
import torch.nn as nn
|
| 35 |
from datasets import load_dataset
|
| 36 |
from peft import LoraConfig
|
| 37 |
from transformers import AutoModelForImageTextToText, AutoProcessor
|
| 38 |
from trl import SFTConfig, SFTTrainer
|
| 39 |
|
| 40 |
+
PROJ_SUFFIXES = ("q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj")
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
def find_lora_targets(model):
|
| 44 |
+
"""FULL module names of the language-tower projection Linears.
|
| 45 |
+
|
| 46 |
+
Gemma 4's vision tower wraps its projections in `Gemma4ClippableLinear`
|
| 47 |
+
(not `nn.Linear`), which PEFT can't adapt, and matching by bare suffix (e.g.
|
| 48 |
+
"q_proj") would also grab those and crash. So we walk the graph and return
|
| 49 |
+
the *fully-qualified* names of the real `nn.Linear` projections under
|
| 50 |
+
`language_model`. PEFT matches those exactly, leaving the vision encoder
|
| 51 |
+
frozen and skipping MoE expert Parameters (which aren't Modules).
|
| 52 |
+
"""
|
| 53 |
+
targets = []
|
| 54 |
+
for name, module in model.named_modules():
|
| 55 |
+
if not isinstance(module, nn.Linear):
|
| 56 |
+
continue
|
| 57 |
+
if "language_model" not in name:
|
| 58 |
+
continue
|
| 59 |
+
if name.split(".")[-1] in PROJ_SUFFIXES:
|
| 60 |
+
targets.append(name)
|
| 61 |
+
return targets
|
| 62 |
+
|
| 63 |
|
| 64 |
def build_collator(processor, model_config):
|
| 65 |
"""Render our (system/user/assistant + image) rows into a batch.
|
|
|
|
| 157 |
|
| 158 |
# Adapt attention + MLP projections across the language tower; leave the
|
| 159 |
# vision encoder frozen (grounding signal comes from the LM reading tokens).
|
| 160 |
+
targets = find_lora_targets(model)
|
| 161 |
+
print(f"[train] LoRA targets: {len(targets)} language-model Linear projections "
|
| 162 |
+
f"(e.g. {targets[:2]})")
|
| 163 |
+
if not targets:
|
| 164 |
+
raise RuntimeError("no language_model projection Linears found for LoRA")
|
| 165 |
peft_config = LoraConfig(
|
| 166 |
r=16, lora_alpha=32, lora_dropout=0.05, bias="none",
|
| 167 |
task_type="CAUSAL_LM",
|
| 168 |
+
target_modules=targets,
|
|
|
|
| 169 |
modules_to_save=None,
|
| 170 |
)
|
| 171 |
|