Add UploadCheckpointsCallback (transformers v5 removed PushToHubCallback; periodic saves were local-only)
Browse files- train_lora.py +48 -7
train_lora.py
CHANGED
|
@@ -18,11 +18,13 @@ from the harness's own ATIF trace.
|
|
| 18 |
"""
|
| 19 |
|
| 20 |
import os
|
|
|
|
| 21 |
from functools import partial
|
| 22 |
|
| 23 |
from datasets import Dataset
|
|
|
|
| 24 |
from peft import LoraConfig
|
| 25 |
-
from transformers import AutoTokenizer
|
| 26 |
from trl.experimental.async_grpo.async_grpo_config import AsyncGRPOConfig
|
| 27 |
from trl.experimental.async_grpo.async_grpo_trainer import AsyncGRPOTrainer
|
| 28 |
from trl.experimental.async_grpo.openenv_harness import HarnessRolloutWorker
|
|
@@ -41,6 +43,47 @@ TOOL_CALL_BUDGET = 32 # reference for the efficiency bonus; tune to the task p
|
|
| 41 |
MAX_BONUS = 0.1
|
| 42 |
|
| 43 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
def correctness_plus_efficiency(outcome):
|
| 45 |
"""1/0 correctness, plus <= 0.1 for a correct answer in fewer tool calls.
|
| 46 |
|
|
@@ -124,12 +167,9 @@ def main():
|
|
| 124 |
"seed": 42,
|
| 125 |
}
|
| 126 |
if ADAPTER_REPO:
|
| 127 |
-
#
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
hub_model_id=ADAPTER_REPO,
|
| 131 |
-
hub_strategy="every_save",
|
| 132 |
-
)
|
| 133 |
config = AsyncGRPOConfig(**config_kwargs)
|
| 134 |
|
| 135 |
# LoRA on attention + MLP projections. Module names verified against the
|
|
@@ -150,6 +190,7 @@ def main():
|
|
| 150 |
processing_class=tokenizer,
|
| 151 |
rollout_worker=worker,
|
| 152 |
peft_config=peft_config,
|
|
|
|
| 153 |
)
|
| 154 |
trainer.train()
|
| 155 |
trainer.save_model("./checkpoints/final") # adapter_model.safetensors + adapter_config.json
|
|
|
|
| 18 |
"""
|
| 19 |
|
| 20 |
import os
|
| 21 |
+
import threading
|
| 22 |
from functools import partial
|
| 23 |
|
| 24 |
from datasets import Dataset
|
| 25 |
+
from huggingface_hub import HfApi
|
| 26 |
from peft import LoraConfig
|
| 27 |
+
from transformers import AutoTokenizer, TrainerCallback
|
| 28 |
from trl.experimental.async_grpo.async_grpo_config import AsyncGRPOConfig
|
| 29 |
from trl.experimental.async_grpo.async_grpo_trainer import AsyncGRPOTrainer
|
| 30 |
from trl.experimental.async_grpo.openenv_harness import HarnessRolloutWorker
|
|
|
|
| 43 |
MAX_BONUS = 0.1
|
| 44 |
|
| 45 |
|
| 46 |
+
class UploadCheckpointsCallback(TrainerCallback):
|
| 47 |
+
"""Push every checkpoint to the Hub, in the background.
|
| 48 |
+
|
| 49 |
+
transformers v5 removed PushToHubCallback: periodic _save_checkpoint writes
|
| 50 |
+
only to local disk (save_model is called with _internal_call=True, which
|
| 51 |
+
skips the push), and `hub_strategy="every_save"` is vestigial. Without this
|
| 52 |
+
callback a crashed job loses the whole run.
|
| 53 |
+
"""
|
| 54 |
+
|
| 55 |
+
def __init__(self, repo_id):
|
| 56 |
+
self.repo_id = repo_id
|
| 57 |
+
self._threads = []
|
| 58 |
+
|
| 59 |
+
def on_save(self, args, state, control, **kwargs):
|
| 60 |
+
if not (self.repo_id and state.is_world_process_zero):
|
| 61 |
+
return control
|
| 62 |
+
ckpt = os.path.join(args.output_dir, f"checkpoint-{state.global_step}")
|
| 63 |
+
t = threading.Thread(target=self._upload, args=(ckpt,), daemon=True)
|
| 64 |
+
t.start()
|
| 65 |
+
self._threads.append(t)
|
| 66 |
+
return control
|
| 67 |
+
|
| 68 |
+
def _upload(self, ckpt):
|
| 69 |
+
try:
|
| 70 |
+
HfApi().upload_folder(
|
| 71 |
+
repo_id=self.repo_id,
|
| 72 |
+
folder_path=ckpt,
|
| 73 |
+
path_in_repo=os.path.basename(ckpt),
|
| 74 |
+
# Keep adapter + trainer state, skip multi-GB optimizer shards.
|
| 75 |
+
ignore_patterns=["optimizer.pt", "optimizer/**", "*.pth"],
|
| 76 |
+
)
|
| 77 |
+
print(f"[hub] uploaded {ckpt}", flush=True)
|
| 78 |
+
except Exception as exc: # never let an upload hiccup kill training
|
| 79 |
+
print(f"[hub] checkpoint upload failed: {exc}", flush=True)
|
| 80 |
+
|
| 81 |
+
def on_train_end(self, args, state, control, **kwargs):
|
| 82 |
+
for t in self._threads:
|
| 83 |
+
t.join(timeout=600)
|
| 84 |
+
return control
|
| 85 |
+
|
| 86 |
+
|
| 87 |
def correctness_plus_efficiency(outcome):
|
| 88 |
"""1/0 correctness, plus <= 0.1 for a correct answer in fewer tool calls.
|
| 89 |
|
|
|
|
| 167 |
"seed": 42,
|
| 168 |
}
|
| 169 |
if ADAPTER_REPO:
|
| 170 |
+
# push_to_hub covers the END-of-training push; periodic checkpoints are
|
| 171 |
+
# pushed by UploadCheckpointsCallback (transformers v5 dropped that path).
|
| 172 |
+
config_kwargs.update(push_to_hub=True, hub_model_id=ADAPTER_REPO)
|
|
|
|
|
|
|
|
|
|
| 173 |
config = AsyncGRPOConfig(**config_kwargs)
|
| 174 |
|
| 175 |
# LoRA on attention + MLP projections. Module names verified against the
|
|
|
|
| 190 |
processing_class=tokenizer,
|
| 191 |
rollout_worker=worker,
|
| 192 |
peft_config=peft_config,
|
| 193 |
+
callbacks=[UploadCheckpointsCallback(ADAPTER_REPO)],
|
| 194 |
)
|
| 195 |
trainer.train()
|
| 196 |
trainer.save_model("./checkpoints/final") # adapter_model.safetensors + adapter_config.json
|