div18 commited on
Commit Β·
aaad9f1
1
Parent(s): 8425a53
final commit
Browse files- training/config.yaml +7 -5
- training/eval.py +5 -62
- training/launch_train.py +33 -70
- training/plotting.py +5 -3
- training/train.py +28 -80
training/config.yaml
CHANGED
|
@@ -80,15 +80,16 @@ generation_do_sample: true
|
|
| 80 |
|
| 81 |
# ---- Evaluation ----
|
| 82 |
eval_interval: 50 # Evaluate every N iterations
|
| 83 |
-
eval_episodes:
|
| 84 |
-
eval_max_steps: 60
|
| 85 |
|
| 86 |
# ---- Checkpointing ----
|
| 87 |
checkpoint_interval: 5 # Save checkpoint every 5 iters (every ~15 min)
|
| 88 |
save_total_limit: 5 # Max checkpoints on Hub
|
| 89 |
|
| 90 |
-
# ---- Metrics ----
|
| 91 |
-
|
|
|
|
| 92 |
|
| 93 |
# ---- Output ----
|
| 94 |
output_dir: "/workspace/antiatropos_checkpoints" # Base dir β run_id subfolder auto-created
|
|
@@ -100,7 +101,8 @@ plot_dpi: 150 # Resolution
|
|
| 100 |
|
| 101 |
# ---- Hugging Face Hub ----
|
| 102 |
hub_model_repo: "" # e.g. "pranavkk/antiatropos-qlora-qwen3.5-4b"
|
| 103 |
-
|
|
|
|
| 104 |
push_to_hub: true # Push adapter + metrics after training
|
| 105 |
|
| 106 |
# ---- Reproducibility ----
|
|
|
|
| 80 |
|
| 81 |
# ---- Evaluation ----
|
| 82 |
eval_interval: 50 # Evaluate every N iterations
|
| 83 |
+
eval_episodes: 2 # Episodes per task during eval
|
| 84 |
+
eval_max_steps: 30 # 30 steps Γ 2 episodes per task = 60 total
|
| 85 |
|
| 86 |
# ---- Checkpointing ----
|
| 87 |
checkpoint_interval: 5 # Save checkpoint every 5 iters (every ~15 min)
|
| 88 |
save_total_limit: 5 # Max checkpoints on Hub
|
| 89 |
|
| 90 |
+
# ---- Metrics & Logging ----
|
| 91 |
+
# Metrics, logs, eval results, and plots are pushed to hub_model_repo/<run_id>/
|
| 92 |
+
# alongside checkpoints. No separate dataset repo needed.
|
| 93 |
|
| 94 |
# ---- Output ----
|
| 95 |
output_dir: "/workspace/antiatropos_checkpoints" # Base dir β run_id subfolder auto-created
|
|
|
|
| 101 |
|
| 102 |
# ---- Hugging Face Hub ----
|
| 103 |
hub_model_repo: "" # e.g. "pranavkk/antiatropos-qlora-qwen3.5-4b"
|
| 104 |
+
# All metrics, logs, eval results, and plots are pushed to this repo under <run_id>/
|
| 105 |
+
# along with checkpoints.
|
| 106 |
push_to_hub: true # Push adapter + metrics after training
|
| 107 |
|
| 108 |
# ---- Reproducibility ----
|
training/eval.py
CHANGED
|
@@ -5,7 +5,8 @@ Runs episodes with:
|
|
| 5 |
1. The fine-tuned model (current LoRA adapter)
|
| 6 |
2. The heuristic baseline
|
| 7 |
|
| 8 |
-
Compares average rewards across tasks.
|
|
|
|
| 9 |
"""
|
| 10 |
|
| 11 |
from __future__ import annotations
|
|
@@ -128,70 +129,12 @@ def evaluate(
|
|
| 128 |
# Save eval results
|
| 129 |
import os
|
| 130 |
os.makedirs(output_dir, exist_ok=True)
|
| 131 |
-
|
|
|
|
| 132 |
json.dump(summary, f, indent=2)
|
|
|
|
| 133 |
|
| 134 |
return summary
|
| 135 |
|
| 136 |
|
| 137 |
-
def push_eval_results(
|
| 138 |
-
results: Dict[str, Any],
|
| 139 |
-
hub_dataset: str,
|
| 140 |
-
run_id: str,
|
| 141 |
-
iteration: int,
|
| 142 |
-
) -> None:
|
| 143 |
-
"""Push eval results as a row to the HF metrics dataset."""
|
| 144 |
-
if not hub_dataset:
|
| 145 |
-
return
|
| 146 |
-
|
| 147 |
-
row = {
|
| 148 |
-
"run_id": run_id,
|
| 149 |
-
"step": iteration,
|
| 150 |
-
"type": "eval",
|
| 151 |
-
**{f"eval_{k}": v for k, v in results.items() if not isinstance(v, dict)},
|
| 152 |
-
}
|
| 153 |
-
# Flatten per-task results
|
| 154 |
-
for task_id, task_results in results.get("per_task", {}).items():
|
| 155 |
-
for metric, value in task_results.items():
|
| 156 |
-
row[f"eval_{task_id}_{metric}"] = value
|
| 157 |
-
|
| 158 |
-
_append_to_dataset(row, hub_dataset)
|
| 159 |
-
|
| 160 |
|
| 161 |
-
def _append_to_dataset(row: Dict[str, Any], hub_dataset: str) -> None:
|
| 162 |
-
"""Append a row to a JSONL file on Hub (creates if not exists)."""
|
| 163 |
-
try:
|
| 164 |
-
from huggingface_hub import HfApi
|
| 165 |
-
api = HfApi()
|
| 166 |
-
|
| 167 |
-
# Download existing data or start fresh
|
| 168 |
-
import tempfile, os
|
| 169 |
-
tmp_dir = tempfile.mkdtemp()
|
| 170 |
-
jsonl_path = os.path.join(tmp_dir, "metrics.jsonl")
|
| 171 |
-
|
| 172 |
-
try:
|
| 173 |
-
api.hf_hub_download(
|
| 174 |
-
repo_id=hub_dataset,
|
| 175 |
-
filename="metrics.jsonl",
|
| 176 |
-
repo_type="dataset",
|
| 177 |
-
local_dir=tmp_dir,
|
| 178 |
-
)
|
| 179 |
-
except Exception:
|
| 180 |
-
pass # File doesn't exist yet β that's fine
|
| 181 |
-
|
| 182 |
-
# Append row
|
| 183 |
-
with open(jsonl_path, "a") as f:
|
| 184 |
-
f.write(json.dumps(row) + "\n")
|
| 185 |
-
|
| 186 |
-
# Upload back
|
| 187 |
-
api.upload_file(
|
| 188 |
-
path_or_fileobj=jsonl_path,
|
| 189 |
-
path_in_repo="metrics.jsonl",
|
| 190 |
-
repo_id=hub_dataset,
|
| 191 |
-
repo_type="dataset",
|
| 192 |
-
commit_message=f"AntiAtropos metrics β {row.get('run_id', 'unknown')} step {row.get('step', '?')}",
|
| 193 |
-
)
|
| 194 |
-
print(f"[eval] Metrics pushed to {hub_dataset}")
|
| 195 |
-
|
| 196 |
-
except Exception as e:
|
| 197 |
-
print(f"[eval] Failed to push metrics: {e}")
|
|
|
|
| 5 |
1. The fine-tuned model (current LoRA adapter)
|
| 6 |
2. The heuristic baseline
|
| 7 |
|
| 8 |
+
Compares average rewards across tasks. Results are saved locally and pushed
|
| 9 |
+
via push_run_files_to_hub (in train.py) under hub_model_repo/<run_id>/eval_results.json.
|
| 10 |
"""
|
| 11 |
|
| 12 |
from __future__ import annotations
|
|
|
|
| 129 |
# Save eval results
|
| 130 |
import os
|
| 131 |
os.makedirs(output_dir, exist_ok=True)
|
| 132 |
+
eval_path = f"{output_dir}/eval_results.json"
|
| 133 |
+
with open(eval_path, "w") as f:
|
| 134 |
json.dump(summary, f, indent=2)
|
| 135 |
+
print(f" [eval] Saved results β {eval_path}")
|
| 136 |
|
| 137 |
return summary
|
| 138 |
|
| 139 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 140 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
training/launch_train.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
| 2 |
"""
|
| 3 |
launch_train.py β Launch full AntiAtropos training on Hugging Face Jobs.
|
| 4 |
|
| 5 |
-
Pushes model checkpoints, metrics
|
| 6 |
The local server is co-located for zero-latency environment interaction.
|
| 7 |
Supports automatic resume from latest Hub checkpoint.
|
| 8 |
|
|
@@ -10,56 +10,38 @@ Prerequisites:
|
|
| 10 |
1. pip install "huggingface_hub>=0.25.0"
|
| 11 |
2. huggingface-cli login (or set HF_TOKEN env var)
|
| 12 |
3. HF Pro/Team account (required for GPU jobs)
|
| 13 |
-
4. The Hub model
|
| 14 |
-
Alternatively create
|
| 15 |
hf repo create <hub-model-repo> --type model
|
| 16 |
-
hf repo create <hub-metrics-dataset> --type dataset
|
| 17 |
|
| 18 |
Lifecycle:
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
β ββββββββββββββββββββββββββββββββββββββββ β
|
| 22 |
-
β β uvicorn :8000 ββββ train.py β β
|
| 23 |
-
β β (simulator) (GPU model) β β
|
| 24 |
-
β ββββββββββββ¬ββββββββββββββββββββββββββββ β
|
| 25 |
-
β β push adapter + plots β
|
| 26 |
-
β βΌ β
|
| 27 |
-
β HF Hub Model Repo β
|
| 28 |
-
β (checkpoint-25, checkpoint-50, ...) β
|
| 29 |
-
β β push metrics.jsonl β
|
| 30 |
-
β βΌ β
|
| 31 |
-
β HF Hub Metrics Dataset β
|
| 32 |
-
βββββββββββββββββββββββββββββββββββββββββββββββ
|
| 33 |
|
| 34 |
Usage:
|
| 35 |
-
# Quick test (
|
| 36 |
python training/launch_train.py \
|
| 37 |
--hub-model-repo Keshav051/antiatropos-qlora \
|
| 38 |
-
--hub-metrics-dataset Keshav051/antiatropos-training-metrics \
|
| 39 |
--num-iterations 20 --num-episodes 4
|
| 40 |
|
| 41 |
-
# Full training (a10g-large
|
| 42 |
python training/launch_train.py \
|
| 43 |
-
--hub-model-repo Keshav051/antiatropos-qlora
|
| 44 |
-
--hub-metrics-dataset Keshav051/antiatropos-training-metrics
|
| 45 |
|
| 46 |
# Custom flavor / longer timeout:
|
| 47 |
python training/launch_train.py \
|
| 48 |
--hub-model-repo Keshav051/antiatropos-qlora \
|
| 49 |
-
--hub-metrics-dataset Keshav051/antiatropos-training-metrics \
|
| 50 |
--flavor a10g-xlarge --timeout 12h \
|
| 51 |
--num-iterations 2000 --num-episodes 24
|
| 52 |
|
| 53 |
# Resume from latest Hub checkpoint:
|
| 54 |
python training/launch_train.py \
|
| 55 |
--hub-model-repo Keshav051/antiatropos-qlora \
|
| 56 |
-
--hub-metrics-dataset Keshav051/antiatropos-training-metrics \
|
| 57 |
--run-id exp_002
|
| 58 |
|
| 59 |
# Dry run (prints job command without launching):
|
| 60 |
python training/launch_train.py \
|
| 61 |
--hub-model-repo Keshav051/antiatropos-qlora \
|
| 62 |
-
--hub-metrics-dataset Keshav051/antiatropos-training-metrics \
|
| 63 |
--dry-run
|
| 64 |
"""
|
| 65 |
|
|
@@ -76,12 +58,12 @@ TRAINING_DIR = Path(__file__).resolve().parent
|
|
| 76 |
|
| 77 |
DOCKER_IMAGE = "pytorch/pytorch:2.10.0-cuda12.6-cudnn9-devel"
|
| 78 |
|
| 79 |
-
DEFAULT_NUM_ITERATIONS =
|
| 80 |
-
DEFAULT_NUM_EPISODES =
|
| 81 |
DEFAULT_MAX_STEPS = 20
|
| 82 |
DEFAULT_EVAL_INTERVAL = 50
|
| 83 |
-
DEFAULT_CHECKPOINT_INTERVAL =
|
| 84 |
-
DEFAULT_PLOT_INTERVAL =
|
| 85 |
|
| 86 |
|
| 87 |
def build_job_command() -> str:
|
|
@@ -123,7 +105,6 @@ def build_job_command() -> str:
|
|
| 123 |
"echo '[bootstrap] Launching training (local server, Hub persistence)...'\n"
|
| 124 |
"export PYTORCH_ALLOC_CONF='expandable_segments:True' # required by Qwen3.5 to avoid OOM fragmentation\n"
|
| 125 |
"ANTIATROPOS_HUB_MODEL_REPO=$HUB_MODEL_REPO "
|
| 126 |
-
"ANTIATROPOS_HUB_METRICS_DATASET=$HUB_METRICS_DATASET "
|
| 127 |
"ANTIATROPOS_ENV_URL=http://localhost:8000 "
|
| 128 |
"python training/train.py "
|
| 129 |
"--run-id $RUN_ID "
|
|
@@ -146,48 +127,38 @@ def build_job_command() -> str:
|
|
| 146 |
|
| 147 |
def ensure_hub_repos(
|
| 148 |
hub_model_repo: str,
|
| 149 |
-
hub_metrics_dataset: str,
|
| 150 |
hf_token: Optional[str],
|
| 151 |
) -> None:
|
| 152 |
-
"""Check if Hub
|
| 153 |
if not hf_token:
|
| 154 |
print(" [hub] No HF_TOKEN available, skipping repo check")
|
| 155 |
return
|
| 156 |
|
|
|
|
|
|
|
|
|
|
| 157 |
try:
|
| 158 |
from huggingface_hub import HfApi
|
| 159 |
|
| 160 |
api = HfApi()
|
| 161 |
|
| 162 |
-
|
| 163 |
-
(hub_model_repo, "model")
|
| 164 |
-
(
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
|
|
|
|
|
|
|
| 170 |
)
|
| 171 |
-
|
| 172 |
-
info = api.repo_info(repo_id=repo_id, repo_type=repo_type)
|
| 173 |
-
print(f" [hub] Repo OK: {base_url}/{repo_id}")
|
| 174 |
-
except Exception:
|
| 175 |
-
print(f" [hub] Creating repo: {repo_id} ({repo_type})...")
|
| 176 |
-
api.create_repo(
|
| 177 |
-
repo_id=repo_id,
|
| 178 |
-
repo_type=repo_type,
|
| 179 |
-
private=True,
|
| 180 |
-
exist_ok=True,
|
| 181 |
-
)
|
| 182 |
-
print(f" [hub] Created: {base_url}/{repo_id}")
|
| 183 |
except Exception as e:
|
| 184 |
-
print(f"\n [hub] WARNING: Could not verify/create Hub
|
| 185 |
-
print(" [hub] Create
|
| 186 |
print(f" hf repo create {hub_model_repo} --type model")
|
| 187 |
-
print(f"
|
| 188 |
-
print(f" Then visit:")
|
| 189 |
-
print(f" https://huggingface.co/{hub_model_repo}")
|
| 190 |
-
print(f" https://huggingface.co/datasets/{hub_metrics_dataset}")
|
| 191 |
|
| 192 |
|
| 193 |
def main() -> None:
|
|
@@ -212,14 +183,8 @@ def main() -> None:
|
|
| 212 |
parser.add_argument(
|
| 213 |
"--hub-model-repo",
|
| 214 |
required=True,
|
| 215 |
-
help="HF Hub model repo for checkpoints,
|
| 216 |
-
"(e.g. Keshav051/antiatropos-qlora)",
|
| 217 |
-
)
|
| 218 |
-
parser.add_argument(
|
| 219 |
-
"--hub-metrics-dataset",
|
| 220 |
-
required=True,
|
| 221 |
-
help="HF Hub dataset repo for training metrics.jsonl "
|
| 222 |
-
"(e.g. Keshav051/antiatropos-training-metrics)",
|
| 223 |
)
|
| 224 |
parser.add_argument(
|
| 225 |
"--run-id",
|
|
@@ -300,7 +265,6 @@ def main() -> None:
|
|
| 300 |
print(f" Timeout: {args.timeout}")
|
| 301 |
print(f" Code repo: {args.repo}")
|
| 302 |
print(f" Hub model repo: {args.hub_model_repo}")
|
| 303 |
-
print(f" Hub metrics dataset: {args.hub_metrics_dataset}")
|
| 304 |
print(f" Run ID: {run_id}")
|
| 305 |
print(f" Loss type: {args.loss_type}")
|
| 306 |
if args.loss_type == "grpo":
|
|
@@ -361,7 +325,7 @@ def main() -> None:
|
|
| 361 |
# ---- Ensure Hub repos exist ----
|
| 362 |
if not args.no_create_repos and hf_token:
|
| 363 |
ensure_hub_repos(
|
| 364 |
-
args.hub_model_repo,
|
| 365 |
)
|
| 366 |
|
| 367 |
# ---- Launch via run_job ----
|
|
@@ -385,7 +349,6 @@ def main() -> None:
|
|
| 385 |
"REPO": args.repo,
|
| 386 |
"RUN_ID": run_id,
|
| 387 |
"HUB_MODEL_REPO": args.hub_model_repo,
|
| 388 |
-
"HUB_METRICS_DATASET": args.hub_metrics_dataset,
|
| 389 |
"NUM_ITERATIONS": str(args.num_iterations),
|
| 390 |
"NUM_EPISODES": str(args.num_episodes),
|
| 391 |
"MAX_STEPS": str(args.max_steps),
|
|
|
|
| 2 |
"""
|
| 3 |
launch_train.py β Launch full AntiAtropos training on Hugging Face Jobs.
|
| 4 |
|
| 5 |
+
Pushes model checkpoints, metrics, logs, and plots to HF Hub model repo.
|
| 6 |
The local server is co-located for zero-latency environment interaction.
|
| 7 |
Supports automatic resume from latest Hub checkpoint.
|
| 8 |
|
|
|
|
| 10 |
1. pip install "huggingface_hub>=0.25.0"
|
| 11 |
2. huggingface-cli login (or set HF_TOKEN env var)
|
| 12 |
3. HF Pro/Team account (required for GPU jobs)
|
| 13 |
+
4. The Hub model repo is auto-created if it doesn't exist.
|
| 14 |
+
Alternatively create it manually:
|
| 15 |
hf repo create <hub-model-repo> --type model
|
|
|
|
| 16 |
|
| 17 |
Lifecycle:
|
| 18 |
+
All run artifacts (checkpoints, metrics, logs, eval results, plots)
|
| 19 |
+
are pushed to <hub-model-repo>/<run_id>/ on the Hub.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
|
| 21 |
Usage:
|
| 22 |
+
# Quick test (~10 min):
|
| 23 |
python training/launch_train.py \
|
| 24 |
--hub-model-repo Keshav051/antiatropos-qlora \
|
|
|
|
| 25 |
--num-iterations 20 --num-episodes 4
|
| 26 |
|
| 27 |
+
# Full training (a10g-large ~ $0.34/hr, ~2h):
|
| 28 |
python training/launch_train.py \
|
| 29 |
+
--hub-model-repo Keshav051/antiatropos-qlora
|
|
|
|
| 30 |
|
| 31 |
# Custom flavor / longer timeout:
|
| 32 |
python training/launch_train.py \
|
| 33 |
--hub-model-repo Keshav051/antiatropos-qlora \
|
|
|
|
| 34 |
--flavor a10g-xlarge --timeout 12h \
|
| 35 |
--num-iterations 2000 --num-episodes 24
|
| 36 |
|
| 37 |
# Resume from latest Hub checkpoint:
|
| 38 |
python training/launch_train.py \
|
| 39 |
--hub-model-repo Keshav051/antiatropos-qlora \
|
|
|
|
| 40 |
--run-id exp_002
|
| 41 |
|
| 42 |
# Dry run (prints job command without launching):
|
| 43 |
python training/launch_train.py \
|
| 44 |
--hub-model-repo Keshav051/antiatropos-qlora \
|
|
|
|
| 45 |
--dry-run
|
| 46 |
"""
|
| 47 |
|
|
|
|
| 58 |
|
| 59 |
DOCKER_IMAGE = "pytorch/pytorch:2.10.0-cuda12.6-cudnn9-devel"
|
| 60 |
|
| 61 |
+
DEFAULT_NUM_ITERATIONS = 15
|
| 62 |
+
DEFAULT_NUM_EPISODES = 6
|
| 63 |
DEFAULT_MAX_STEPS = 20
|
| 64 |
DEFAULT_EVAL_INTERVAL = 50
|
| 65 |
+
DEFAULT_CHECKPOINT_INTERVAL = 5
|
| 66 |
+
DEFAULT_PLOT_INTERVAL = 10
|
| 67 |
|
| 68 |
|
| 69 |
def build_job_command() -> str:
|
|
|
|
| 105 |
"echo '[bootstrap] Launching training (local server, Hub persistence)...'\n"
|
| 106 |
"export PYTORCH_ALLOC_CONF='expandable_segments:True' # required by Qwen3.5 to avoid OOM fragmentation\n"
|
| 107 |
"ANTIATROPOS_HUB_MODEL_REPO=$HUB_MODEL_REPO "
|
|
|
|
| 108 |
"ANTIATROPOS_ENV_URL=http://localhost:8000 "
|
| 109 |
"python training/train.py "
|
| 110 |
"--run-id $RUN_ID "
|
|
|
|
| 127 |
|
| 128 |
def ensure_hub_repos(
|
| 129 |
hub_model_repo: str,
|
|
|
|
| 130 |
hf_token: Optional[str],
|
| 131 |
) -> None:
|
| 132 |
+
"""Check if the Hub model repo exists; create it automatically if not."""
|
| 133 |
if not hf_token:
|
| 134 |
print(" [hub] No HF_TOKEN available, skipping repo check")
|
| 135 |
return
|
| 136 |
|
| 137 |
+
if not hub_model_repo:
|
| 138 |
+
return
|
| 139 |
+
|
| 140 |
try:
|
| 141 |
from huggingface_hub import HfApi
|
| 142 |
|
| 143 |
api = HfApi()
|
| 144 |
|
| 145 |
+
try:
|
| 146 |
+
info = api.repo_info(repo_id=hub_model_repo, repo_type="model")
|
| 147 |
+
print(f" [hub] Repo OK: https://huggingface.co/{hub_model_repo}")
|
| 148 |
+
except Exception:
|
| 149 |
+
print(f" [hub] Creating repo: {hub_model_repo} (model)...")
|
| 150 |
+
api.create_repo(
|
| 151 |
+
repo_id=hub_model_repo,
|
| 152 |
+
repo_type="model",
|
| 153 |
+
private=True,
|
| 154 |
+
exist_ok=True,
|
| 155 |
)
|
| 156 |
+
print(f" [hub] Created: https://huggingface.co/{hub_model_repo}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 157 |
except Exception as e:
|
| 158 |
+
print(f"\n [hub] WARNING: Could not verify/create Hub repo: {e}")
|
| 159 |
+
print(" [hub] Create it manually:")
|
| 160 |
print(f" hf repo create {hub_model_repo} --type model")
|
| 161 |
+
print(f" Then visit: https://huggingface.co/{hub_model_repo}")
|
|
|
|
|
|
|
|
|
|
| 162 |
|
| 163 |
|
| 164 |
def main() -> None:
|
|
|
|
| 183 |
parser.add_argument(
|
| 184 |
"--hub-model-repo",
|
| 185 |
required=True,
|
| 186 |
+
help="HF Hub model repo for checkpoints, metrics, logs, and plots "
|
| 187 |
+
"(e.g. Keshav051/antiatropos-qlora). All run artifacts go under <run_id>/.",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 188 |
)
|
| 189 |
parser.add_argument(
|
| 190 |
"--run-id",
|
|
|
|
| 265 |
print(f" Timeout: {args.timeout}")
|
| 266 |
print(f" Code repo: {args.repo}")
|
| 267 |
print(f" Hub model repo: {args.hub_model_repo}")
|
|
|
|
| 268 |
print(f" Run ID: {run_id}")
|
| 269 |
print(f" Loss type: {args.loss_type}")
|
| 270 |
if args.loss_type == "grpo":
|
|
|
|
| 325 |
# ---- Ensure Hub repos exist ----
|
| 326 |
if not args.no_create_repos and hf_token:
|
| 327 |
ensure_hub_repos(
|
| 328 |
+
args.hub_model_repo, hf_token
|
| 329 |
)
|
| 330 |
|
| 331 |
# ---- Launch via run_job ----
|
|
|
|
| 349 |
"REPO": args.repo,
|
| 350 |
"RUN_ID": run_id,
|
| 351 |
"HUB_MODEL_REPO": args.hub_model_repo,
|
|
|
|
| 352 |
"NUM_ITERATIONS": str(args.num_iterations),
|
| 353 |
"NUM_EPISODES": str(args.num_episodes),
|
| 354 |
"MAX_STEPS": str(args.max_steps),
|
training/plotting.py
CHANGED
|
@@ -520,6 +520,7 @@ def push_plots_to_hub(
|
|
| 520 |
plot_paths: List[str],
|
| 521 |
hub_repo: str,
|
| 522 |
iteration: int,
|
|
|
|
| 523 |
) -> None:
|
| 524 |
if not hub_repo or not plot_paths:
|
| 525 |
return
|
|
@@ -528,14 +529,15 @@ def push_plots_to_hub(
|
|
| 528 |
api = HfApi()
|
| 529 |
for path in plot_paths:
|
| 530 |
filename = Path(path).name
|
|
|
|
| 531 |
api.upload_file(
|
| 532 |
path_or_fileobj=path,
|
| 533 |
-
path_in_repo=f"
|
| 534 |
repo_id=hub_repo,
|
| 535 |
repo_type="model",
|
| 536 |
-
commit_message=f"Training plots - iteration {iteration}",
|
| 537 |
)
|
| 538 |
-
print(f"[plotting] Pushed {len(plot_paths)} plots to {hub_repo}")
|
| 539 |
except Exception as e:
|
| 540 |
print(f"[plotting] Push failed: {e}")
|
| 541 |
|
|
|
|
| 520 |
plot_paths: List[str],
|
| 521 |
hub_repo: str,
|
| 522 |
iteration: int,
|
| 523 |
+
run_id: str = "",
|
| 524 |
) -> None:
|
| 525 |
if not hub_repo or not plot_paths:
|
| 526 |
return
|
|
|
|
| 529 |
api = HfApi()
|
| 530 |
for path in plot_paths:
|
| 531 |
filename = Path(path).name
|
| 532 |
+
prefix = f"{run_id}/" if run_id else ""
|
| 533 |
api.upload_file(
|
| 534 |
path_or_fileobj=path,
|
| 535 |
+
path_in_repo=f"{prefix}plots/{filename}",
|
| 536 |
repo_id=hub_repo,
|
| 537 |
repo_type="model",
|
| 538 |
+
commit_message=f"[{run_id}] Training plots - iteration {iteration}",
|
| 539 |
)
|
| 540 |
+
print(f"[plotting] Pushed {len(plot_paths)} plots to {hub_repo}/{prefix}plots/")
|
| 541 |
except Exception as e:
|
| 542 |
print(f"[plotting] Push failed: {e}")
|
| 543 |
|
training/train.py
CHANGED
|
@@ -66,7 +66,7 @@ from openenv_loop import (
|
|
| 66 |
rollout_episode,
|
| 67 |
rollout_heuristic_episode,
|
| 68 |
)
|
| 69 |
-
from eval import evaluate
|
| 70 |
from plotting import (
|
| 71 |
generate_all_plots,
|
| 72 |
push_plots_to_hub,
|
|
@@ -516,63 +516,22 @@ def grpo_loss_fn(
|
|
| 516 |
|
| 517 |
|
| 518 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 519 |
-
#
|
| 520 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 521 |
|
| 522 |
-
def push_train_metrics(
|
| 523 |
-
metrics: Dict[str, Any],
|
| 524 |
-
hub_dataset: str,
|
| 525 |
-
) -> None:
|
| 526 |
-
"""Push training metrics row to the Hub dataset."""
|
| 527 |
-
if not hub_dataset:
|
| 528 |
-
return
|
| 529 |
-
|
| 530 |
-
try:
|
| 531 |
-
from huggingface_hub import HfApi
|
| 532 |
-
api = HfApi()
|
| 533 |
-
import tempfile
|
| 534 |
-
|
| 535 |
-
tmp_dir = tempfile.mkdtemp()
|
| 536 |
-
jsonl_path = os.path.join(tmp_dir, "metrics.jsonl")
|
| 537 |
-
|
| 538 |
-
try:
|
| 539 |
-
api.hf_hub_download(
|
| 540 |
-
repo_id=hub_dataset,
|
| 541 |
-
filename="metrics.jsonl",
|
| 542 |
-
repo_type="dataset",
|
| 543 |
-
local_dir=tmp_dir,
|
| 544 |
-
)
|
| 545 |
-
except Exception:
|
| 546 |
-
pass
|
| 547 |
-
|
| 548 |
-
with open(jsonl_path, "a") as f:
|
| 549 |
-
f.write(json.dumps(metrics) + "\n")
|
| 550 |
-
|
| 551 |
-
api.upload_file(
|
| 552 |
-
path_or_fileobj=jsonl_path,
|
| 553 |
-
path_in_repo="metrics.jsonl",
|
| 554 |
-
repo_id=hub_dataset,
|
| 555 |
-
repo_type="dataset",
|
| 556 |
-
commit_message=f"train metrics β {metrics.get('run_id')} iter {metrics.get('iteration')}",
|
| 557 |
-
)
|
| 558 |
-
except Exception as e:
|
| 559 |
-
print(f"[train] Metrics push failed: {e}")
|
| 560 |
-
|
| 561 |
|
| 562 |
def push_run_files_to_hub(
|
| 563 |
run_id: str,
|
| 564 |
output_dir: Path,
|
| 565 |
-
|
| 566 |
iteration: int,
|
| 567 |
) -> None:
|
| 568 |
-
"""Upload step_metrics.jsonl, iter_metrics.jsonl,
|
| 569 |
|
| 570 |
-
Files are uploaded under <run_id>/
|
| 571 |
-
|
| 572 |
-
|
| 573 |
-
Called every push_interval iterations and at the end of training.
|
| 574 |
"""
|
| 575 |
-
if not
|
| 576 |
return
|
| 577 |
|
| 578 |
files_to_push = [
|
|
@@ -582,6 +541,14 @@ def push_run_files_to_hub(
|
|
| 582 |
("run_info.json", f"{run_id}/run_info.json"),
|
| 583 |
]
|
| 584 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 585 |
try:
|
| 586 |
from huggingface_hub import HfApi
|
| 587 |
api = HfApi()
|
|
@@ -594,15 +561,15 @@ def push_run_files_to_hub(
|
|
| 594 |
api.upload_file(
|
| 595 |
path_or_fileobj=str(local_path),
|
| 596 |
path_in_repo=hub_path,
|
| 597 |
-
repo_id=
|
| 598 |
-
repo_type="
|
| 599 |
commit_message=f"[{run_id}] iter {iteration}: {local_name}",
|
| 600 |
)
|
| 601 |
pushed.append(local_name)
|
| 602 |
except Exception as e:
|
| 603 |
print(f" [push] Failed to push {local_name}: {e}")
|
| 604 |
if pushed:
|
| 605 |
-
print(f" [push]
|
| 606 |
flush=True)
|
| 607 |
except Exception as e:
|
| 608 |
print(f"[train] Hub file push failed: {e}")
|
|
@@ -802,7 +769,6 @@ def train(cfg: Dict[str, Any]) -> None:
|
|
| 802 |
print(f"[train] Run manifest: {run_info_path}")
|
| 803 |
|
| 804 |
hub_model_repo = cfg.get("hub_model_repo", "")
|
| 805 |
-
hub_metrics_dataset = cfg.get("hub_metrics_dataset", "")
|
| 806 |
push_to_hub_flag = cfg.get("push_to_hub", True)
|
| 807 |
|
| 808 |
# ---- Verify environment ----
|
|
@@ -863,7 +829,6 @@ def train(cfg: Dict[str, Any]) -> None:
|
|
| 863 |
max_grad_norm = cfg.get("max_grad_norm", 1.0)
|
| 864 |
checkpoint_interval = cfg.get("checkpoint_interval", 10) # default: every 10 iters
|
| 865 |
eval_interval = cfg.get("eval_interval", 50)
|
| 866 |
-
push_interval = cfg.get("push_interval", 10)
|
| 867 |
plot_interval = cfg.get("plot_interval", 25)
|
| 868 |
|
| 869 |
# ---- Training loop ----
|
|
@@ -878,7 +843,6 @@ def train(cfg: Dict[str, Any]) -> None:
|
|
| 878 |
print(f" Max steps: {max_steps}")
|
| 879 |
print(f" Learning rate: {lr}")
|
| 880 |
print(f" Hub model: {hub_model_repo or '(not configured)'}")
|
| 881 |
-
print(f" Hub metrics: {hub_metrics_dataset or '(not configured)'}")
|
| 882 |
print(f" Output dir: {output_dir}")
|
| 883 |
print(f"{'='*70}\n")
|
| 884 |
|
|
@@ -1017,12 +981,7 @@ def train(cfg: Dict[str, Any]) -> None:
|
|
| 1017 |
if len(recent_episodes_data) > 200: # Keep last ~200 episodes
|
| 1018 |
recent_episodes_data = recent_episodes_data[-200:]
|
| 1019 |
|
| 1020 |
-
# ----
|
| 1021 |
-
if (iteration + 1) % push_interval == 0 and hub_metrics_dataset:
|
| 1022 |
-
# Push step_metrics.jsonl, iter_metrics.jsonl, training.log, run_info.json
|
| 1023 |
-
push_run_files_to_hub(run_id, output_dir, hub_metrics_dataset, iteration + 1)
|
| 1024 |
-
|
| 1025 |
-
# ---- Checkpoint ----
|
| 1026 |
if (iteration + 1) % checkpoint_interval == 0:
|
| 1027 |
# Pad iteration number so ls sorts correctly: checkpoint-0010, checkpoint-0050, ...
|
| 1028 |
ckpt_name = f"checkpoint-{iteration + 1:04d}"
|
|
@@ -1041,7 +1000,7 @@ def train(cfg: Dict[str, Any]) -> None:
|
|
| 1041 |
(ckpt_dir / "checkpoint_meta.json").write_text(
|
| 1042 |
_json.dumps(ckpt_meta, indent=2)
|
| 1043 |
)
|
| 1044 |
-
print(f" [ckpt] Saved
|
| 1045 |
f"(reward={avg_reward:.4f} loss={loss.item():.4f})", flush=True)
|
| 1046 |
if push_to_hub_flag and hub_model_repo:
|
| 1047 |
push_to_hub(
|
|
@@ -1050,6 +1009,8 @@ def train(cfg: Dict[str, Any]) -> None:
|
|
| 1050 |
commit_message=f"[{run_id}] {ckpt_name}",
|
| 1051 |
path_in_repo=f"{run_id}/{ckpt_name}",
|
| 1052 |
)
|
|
|
|
|
|
|
| 1053 |
|
| 1054 |
# ---- Evaluation ----
|
| 1055 |
if (iteration + 1) % eval_interval == 0:
|
|
@@ -1071,10 +1032,6 @@ def train(cfg: Dict[str, Any]) -> None:
|
|
| 1071 |
eval_row[f"eval_{tid}_{mk}"] = mv
|
| 1072 |
eval_metrics_history.append(eval_row)
|
| 1073 |
|
| 1074 |
-
if hub_metrics_dataset:
|
| 1075 |
-
push_eval_results(
|
| 1076 |
-
eval_results, hub_metrics_dataset, run_id, iteration
|
| 1077 |
-
)
|
| 1078 |
# Re-enable training mode
|
| 1079 |
model.train()
|
| 1080 |
|
|
@@ -1089,7 +1046,7 @@ def train(cfg: Dict[str, Any]) -> None:
|
|
| 1089 |
cfg=cfg,
|
| 1090 |
)
|
| 1091 |
if push_to_hub_flag and hub_model_repo:
|
| 1092 |
-
push_plots_to_hub(plot_paths, hub_model_repo, iteration)
|
| 1093 |
except Exception as e:
|
| 1094 |
print(f" [iter {iteration}] Plotting failed: {e}")
|
| 1095 |
|
|
@@ -1123,12 +1080,6 @@ def train(cfg: Dict[str, Any]) -> None:
|
|
| 1123 |
client, model, tokenizer, cfg,
|
| 1124 |
output_dir=str(output_dir / "final_eval"),
|
| 1125 |
)
|
| 1126 |
-
|
| 1127 |
-
if hub_metrics_dataset:
|
| 1128 |
-
push_eval_results(
|
| 1129 |
-
final_eval, hub_metrics_dataset, run_id, num_iterations
|
| 1130 |
-
)
|
| 1131 |
-
|
| 1132 |
# Final plots (full training history)
|
| 1133 |
try:
|
| 1134 |
final_eval_row = {
|
|
@@ -1152,19 +1103,17 @@ def train(cfg: Dict[str, Any]) -> None:
|
|
| 1152 |
cfg=cfg,
|
| 1153 |
)
|
| 1154 |
if push_to_hub_flag and hub_model_repo:
|
| 1155 |
-
push_plots_to_hub(plot_paths, hub_model_repo, num_iterations)
|
| 1156 |
except Exception as e:
|
| 1157 |
print(f"[train] Final plotting failed: {e}")
|
| 1158 |
|
| 1159 |
print(f"\n[train] All done. Final adapter: {final_dir}")
|
| 1160 |
if hub_model_repo:
|
| 1161 |
print(f"[train] Hub repo: https://huggingface.co/{hub_model_repo}")
|
| 1162 |
-
|
| 1163 |
-
|
| 1164 |
-
|
| 1165 |
-
|
| 1166 |
-
if hub_metrics_dataset:
|
| 1167 |
-
push_run_files_to_hub(run_id, output_dir, hub_metrics_dataset, num_iterations)
|
| 1168 |
|
| 1169 |
# ββ Flush and close the TeeLogger ββββββββββββββββββββββββββββββββββββββββ
|
| 1170 |
# Restore original stdout/stderr so any code after train() works normally.
|
|
@@ -1265,7 +1214,6 @@ def main():
|
|
| 1265 |
if args.no_push:
|
| 1266 |
cfg["push_to_hub"] = False
|
| 1267 |
cfg["hub_model_repo"] = ""
|
| 1268 |
-
cfg["hub_metrics_dataset"] = ""
|
| 1269 |
|
| 1270 |
# Allow HF_TOKEN from env
|
| 1271 |
hf_token = os.getenv("HF_TOKEN") or os.getenv("HUGGING_FACE_HUB_TOKEN")
|
|
|
|
| 66 |
rollout_episode,
|
| 67 |
rollout_heuristic_episode,
|
| 68 |
)
|
| 69 |
+
from eval import evaluate
|
| 70 |
from plotting import (
|
| 71 |
generate_all_plots,
|
| 72 |
push_plots_to_hub,
|
|
|
|
| 516 |
|
| 517 |
|
| 518 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 519 |
+
# Run Files Push (to hub_model_repo/<run_id>/)
|
| 520 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 521 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 522 |
|
| 523 |
def push_run_files_to_hub(
|
| 524 |
run_id: str,
|
| 525 |
output_dir: Path,
|
| 526 |
+
hub_model_repo: str,
|
| 527 |
iteration: int,
|
| 528 |
) -> None:
|
| 529 |
+
"""Upload step_metrics.jsonl, iter_metrics.jsonl, training.log, and eval results.
|
| 530 |
|
| 531 |
+
Files are uploaded under <run_id>/ in the model repo alongside checkpoints.
|
| 532 |
+
Called every checkpoint_interval iterations and at the end of training.
|
|
|
|
|
|
|
| 533 |
"""
|
| 534 |
+
if not hub_model_repo:
|
| 535 |
return
|
| 536 |
|
| 537 |
files_to_push = [
|
|
|
|
| 541 |
("run_info.json", f"{run_id}/run_info.json"),
|
| 542 |
]
|
| 543 |
|
| 544 |
+
# Also push eval results if they exist
|
| 545 |
+
eval_path = output_dir / "eval" / "eval_results.json"
|
| 546 |
+
if eval_path.exists():
|
| 547 |
+
files_to_push.append(("eval/eval_results.json", f"{run_id}/eval_results.json"))
|
| 548 |
+
final_eval_path = output_dir / "final_eval" / "eval_results.json"
|
| 549 |
+
if final_eval_path.exists():
|
| 550 |
+
files_to_push.append(("final_eval/eval_results.json", f"{run_id}/final_eval_results.json"))
|
| 551 |
+
|
| 552 |
try:
|
| 553 |
from huggingface_hub import HfApi
|
| 554 |
api = HfApi()
|
|
|
|
| 561 |
api.upload_file(
|
| 562 |
path_or_fileobj=str(local_path),
|
| 563 |
path_in_repo=hub_path,
|
| 564 |
+
repo_id=hub_model_repo,
|
| 565 |
+
repo_type="model",
|
| 566 |
commit_message=f"[{run_id}] iter {iteration}: {local_name}",
|
| 567 |
)
|
| 568 |
pushed.append(local_name)
|
| 569 |
except Exception as e:
|
| 570 |
print(f" [push] Failed to push {local_name}: {e}")
|
| 571 |
if pushed:
|
| 572 |
+
print(f" [push] \u2192 HF model {hub_model_repo}/{run_id}/: {', '.join(pushed)}",
|
| 573 |
flush=True)
|
| 574 |
except Exception as e:
|
| 575 |
print(f"[train] Hub file push failed: {e}")
|
|
|
|
| 769 |
print(f"[train] Run manifest: {run_info_path}")
|
| 770 |
|
| 771 |
hub_model_repo = cfg.get("hub_model_repo", "")
|
|
|
|
| 772 |
push_to_hub_flag = cfg.get("push_to_hub", True)
|
| 773 |
|
| 774 |
# ---- Verify environment ----
|
|
|
|
| 829 |
max_grad_norm = cfg.get("max_grad_norm", 1.0)
|
| 830 |
checkpoint_interval = cfg.get("checkpoint_interval", 10) # default: every 10 iters
|
| 831 |
eval_interval = cfg.get("eval_interval", 50)
|
|
|
|
| 832 |
plot_interval = cfg.get("plot_interval", 25)
|
| 833 |
|
| 834 |
# ---- Training loop ----
|
|
|
|
| 843 |
print(f" Max steps: {max_steps}")
|
| 844 |
print(f" Learning rate: {lr}")
|
| 845 |
print(f" Hub model: {hub_model_repo or '(not configured)'}")
|
|
|
|
| 846 |
print(f" Output dir: {output_dir}")
|
| 847 |
print(f"{'='*70}\n")
|
| 848 |
|
|
|
|
| 981 |
if len(recent_episodes_data) > 200: # Keep last ~200 episodes
|
| 982 |
recent_episodes_data = recent_episodes_data[-200:]
|
| 983 |
|
| 984 |
+
# ---- Checkpoint + push run files ----
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 985 |
if (iteration + 1) % checkpoint_interval == 0:
|
| 986 |
# Pad iteration number so ls sorts correctly: checkpoint-0010, checkpoint-0050, ...
|
| 987 |
ckpt_name = f"checkpoint-{iteration + 1:04d}"
|
|
|
|
| 1000 |
(ckpt_dir / "checkpoint_meta.json").write_text(
|
| 1001 |
_json.dumps(ckpt_meta, indent=2)
|
| 1002 |
)
|
| 1003 |
+
print(f" [ckpt] Saved \u2192 {ckpt_dir} "
|
| 1004 |
f"(reward={avg_reward:.4f} loss={loss.item():.4f})", flush=True)
|
| 1005 |
if push_to_hub_flag and hub_model_repo:
|
| 1006 |
push_to_hub(
|
|
|
|
| 1009 |
commit_message=f"[{run_id}] {ckpt_name}",
|
| 1010 |
path_in_repo=f"{run_id}/{ckpt_name}",
|
| 1011 |
)
|
| 1012 |
+
# Push run files (metrics, logs) alongside checkpoint
|
| 1013 |
+
push_run_files_to_hub(run_id, output_dir, hub_model_repo, iteration + 1)
|
| 1014 |
|
| 1015 |
# ---- Evaluation ----
|
| 1016 |
if (iteration + 1) % eval_interval == 0:
|
|
|
|
| 1032 |
eval_row[f"eval_{tid}_{mk}"] = mv
|
| 1033 |
eval_metrics_history.append(eval_row)
|
| 1034 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1035 |
# Re-enable training mode
|
| 1036 |
model.train()
|
| 1037 |
|
|
|
|
| 1046 |
cfg=cfg,
|
| 1047 |
)
|
| 1048 |
if push_to_hub_flag and hub_model_repo:
|
| 1049 |
+
push_plots_to_hub(plot_paths, hub_model_repo, iteration, run_id=run_id)
|
| 1050 |
except Exception as e:
|
| 1051 |
print(f" [iter {iteration}] Plotting failed: {e}")
|
| 1052 |
|
|
|
|
| 1080 |
client, model, tokenizer, cfg,
|
| 1081 |
output_dir=str(output_dir / "final_eval"),
|
| 1082 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1083 |
# Final plots (full training history)
|
| 1084 |
try:
|
| 1085 |
final_eval_row = {
|
|
|
|
| 1103 |
cfg=cfg,
|
| 1104 |
)
|
| 1105 |
if push_to_hub_flag and hub_model_repo:
|
| 1106 |
+
push_plots_to_hub(plot_paths, hub_model_repo, num_iterations, run_id=run_id)
|
| 1107 |
except Exception as e:
|
| 1108 |
print(f"[train] Final plotting failed: {e}")
|
| 1109 |
|
| 1110 |
print(f"\n[train] All done. Final adapter: {final_dir}")
|
| 1111 |
if hub_model_repo:
|
| 1112 |
print(f"[train] Hub repo: https://huggingface.co/{hub_model_repo}")
|
| 1113 |
+
|
| 1114 |
+
# \u2500\u2500 Final push of all run files
|
| 1115 |
+
if hub_model_repo:
|
| 1116 |
+
push_run_files_to_hub(run_id, output_dir, hub_model_repo, num_iterations)
|
|
|
|
|
|
|
| 1117 |
|
| 1118 |
# ββ Flush and close the TeeLogger ββββββββββββββββββββββββββββββββββββββββ
|
| 1119 |
# Restore original stdout/stderr so any code after train() works normally.
|
|
|
|
| 1214 |
if args.no_push:
|
| 1215 |
cfg["push_to_hub"] = False
|
| 1216 |
cfg["hub_model_repo"] = ""
|
|
|
|
| 1217 |
|
| 1218 |
# Allow HF_TOKEN from env
|
| 1219 |
hf_token = os.getenv("HF_TOKEN") or os.getenv("HUGGING_FACE_HUB_TOKEN")
|