refactor: restructure project - scripts at root level

This commit is contained in:
Christian Medina
2026-07-01 16:39:54 -04:00
parent 293f9caf65
commit cc353b3dea
5 changed files with 5 additions and 16 deletions

View File

@@ -1,103 +0,0 @@
#!/usr/bin/env python3
"""
Inference script for trained LoRA adapter.
Loads the trained model and generates Cyron summaries.
"""
import argparse
from pathlib import Path
def load_model(model_path):
"""Load trained LoRA model."""
from peft import PeftModel
from transformers import AutoModelForCausalLM, AutoTokenizer
print(f"Loading base model from {model_path}...")
base_model = AutoModelForCausalLM.from_pretrained(
model_path,
device_map="auto",
torch_dtype="auto",
)
print(f"Loading LoRA weights from {model_path}...")
model = PeftModel.from_pretrained(base_model, model_path)
tokenizer = AutoTokenizer.from_pretrained(model_path)
return model, tokenizer
def generate_summary(model, tokenizer, task, files_changed=None, tests_run=False, test_count=0, commit=False, push=False, errors_seen=False):
"""Generate a Cyron summary for a task."""
# Build prompt
prompt = f"Task: {task}"
if files_changed:
prompt += f"\nFiles: {', '.join(files_changed[:3])}"
if tests_run:
prompt += f"\nTests run: {test_count}"
if commit:
prompt += "\nCommit: yes"
if push:
prompt += "\nPush: yes"
if errors_seen:
prompt += "\nErrors seen: yes"
prompt += "\n\nGenerate a Cyron summary:"
# Tokenize
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
# Generate
outputs = model.generate(
**inputs,
max_new_tokens=500,
do_sample=True,
temperature=0.7,
top_p=0.9,
repetition_penalty=1.1,
)
# Decode
generated = tokenizer.decode(outputs[0][inputs["input_ids"].shape[1]:], skip_special_tokens=True)
return generated
def main():
parser = argparse.ArgumentParser(description="Generate Cyron summaries with LoRA")
parser.add_argument("--model", type=str, default="output/ornith-35b-lora-cyron",
help="Path to trained LoRA model")
parser.add_argument("--task", type=str, required=True, help="Task description")
parser.add_argument("--files", type=str, nargs="*", default=[], help="Files changed")
parser.add_argument("--tests-run", action="store_true", help="Tests were run")
parser.add_argument("--test-count", type=int, default=0, help="Number of tests")
parser.add_argument("--commit", action="store_true", help="Commit was made")
parser.add_argument("--push", action="store_true", help="Code was pushed")
parser.add_argument("--errors", action="store_true", help="Errors were seen")
args = parser.parse_args()
model, tokenizer = load_model(args.model)
summary = generate_summary(
model,
tokenizer,
task=args.task,
files_changed=args.files,
tests_run=args.tests_run,
test_count=args.test_count,
commit=args.commit,
push=args.push,
errors_seen=args.errors,
)
print("\nGenerated Summary:")
print("=" * 70)
print(summary)
print("=" * 70)
if __name__ == "__main__":
main()

View File

@@ -1,99 +0,0 @@
#!/usr/bin/env python3
"""
Prepare Cyron summary dataset for LoRA training.
Reads combined_20k.jsonl and formats it for Hugging Face TRL training.
"""
import json
import argparse
from pathlib import Path
def prepare_dataset(input_file, output_file, test_size=0.05):
"""Prepare dataset for training."""
with open(input_file) as f:
examples = [json.loads(line) for line in f]
print(f"Loaded {len(examples)} examples")
# Format for training
formatted = []
for ex in examples:
# Create instruction-input-output format
instruction = f"Task: {ex['task']}"
if ex['files_changed']:
instruction += f"\nFiles: {', '.join(ex['files_changed'][:3])}"
input_text = ""
if ex['tests_run']:
input_text += f"Tests run: {ex['test_count']}"
if ex['commit']:
input_text += f"\nCommit: {ex['git']['commit'] if ex.get('git') else 'yes'}"
if ex['push']:
input_text += "\nPush: yes"
output_text = ex['output']
# Create chat format for SFTTrainer
conversation = {
"messages": [
{
"role": "system",
"content": "You are a helpful coding assistant that generates project summaries."
},
{
"role": "user",
"content": f"Generate a summary for this task:\n\n{instruction}\n\n{input_text}"
},
{
"role": "assistant",
"content": output_text
}
]
}
formatted.append(conversation)
# Split into train/test
import random
random.seed(42)
random.shuffle(formatted)
split_point = int(len(formatted) * (1 - test_size))
train_data = formatted[:split_point]
test_data = formatted[split_point:]
# Save
with open(output_file / "train.jsonl", "w") as f:
for item in train_data:
f.write(json.dumps(item) + "\n")
with open(output_file / "test.jsonl", "w") as f:
for item in test_data:
f.write(json.dumps(item) + "\n")
print(f"Train: {len(train_data)} examples")
print(f"Test: {len(test_data)} examples")
print(f"Saved to {output_file}")
def main():
parser = argparse.ArgumentParser(description="Prepare LoRA training dataset")
parser.add_argument("--input", type=str, default="../combined_20k.jsonl",
help="Input combined dataset")
parser.add_argument("--output", type=str, default="data",
help="Output directory")
parser.add_argument("--test-size", type=float, default=0.05,
help="Test set percentage")
args = parser.parse_args()
output_dir = Path(args.output)
output_dir.mkdir(parents=True, exist_ok=True)
prepare_dataset(args.input, output_dir, args.test_size)
if __name__ == "__main__":
main()

View File

@@ -1,11 +0,0 @@
#!/bin/bash
# Run training with distributed setup
set -e
# Install accelerate if not present
pip install -q accelerate
# Launch with accelerate
# Note: Use the dedicated train-on-this-server.sh instead
echo "See train-on-this-server.sh for full setup"

View File

@@ -1,261 +0,0 @@
#!/usr/bin/env python3
"""
Train LoRA adapter on Cyron summary dataset.
Uses Hugging Face TRL for SFT training.
"""
import argparse
import os
import yaml
from pathlib import Path
import torch
def train(config_path):
"""Train LoRA adapter using TRL."""
with open(config_path) as f:
config = yaml.safe_load(f)
from transformers import (
AutoModelForCausalLM,
AutoTokenizer,
TrainingArguments,
)
from peft import (
LoraConfig,
get_peft_model,
)
from trl import SFTTrainer
print(f"Loading model: {config['base_model']}")
# Load model - try multiple strategies
print(f"\n[INFO] Loading {config['base_model']}...")
# Strategy 1: 4-bit AS-IS (already quantized)
print("\n[1/4] Trying: 4-bit AS-IS...")
try:
model = AutoModelForCausalLM.from_pretrained(
config["base_model"],
torch_dtype=torch.float16,
device_map="auto",
trust_remote_code=True,
)
print("✓ Success: 4-bit AS-IS")
except Exception as e:
print(f"✗ Failed: {e}")
# Strategy 2: 4-bit to CPU
print("\n[2/4] Trying: 4-bit to CPU...")
try:
model = AutoModelForCausalLM.from_pretrained(
config["base_model"],
torch_dtype=torch.float16,
device_map="cpu",
trust_remote_code=True,
)
print("✓ Success: 4-bit to CPU")
except Exception as e:
print(f"✗ Failed: {e}")
# Strategy 3: bf16 to CPU
print("\n[3/4] Trying: bf16 to CPU...")
try:
model = AutoModelForCausalLM.from_pretrained(
config["base_model"],
torch_dtype=torch.bfloat16,
device_map="cpu",
low_cpu_mem_usage=True,
trust_remote_code=True,
)
print("✓ Success: bf16 to CPU")
except Exception as e:
print(f"✗ Failed: {e}")
# Strategy 4: bf16 auto
print("\n[4/4] Trying: bf16 auto...")
try:
model = AutoModelForCausalLM.from_pretrained(
config["base_model"],
torch_dtype=torch.bfloat16,
device_map="auto",
low_cpu_mem_usage=True,
trust_remote_code=True,
)
print("✓ Success: bf16 auto")
except Exception as e:
print(f"✗ Failed: {e}")
raise RuntimeError("All loading strategies failed!")
# Add LoRA
lora_config = LoraConfig(
r=config["lora_r"],
lora_alpha=config["lora_alpha"],
lora_dropout=config["lora_dropout"],
target_modules=config["target_modules"],
task_type=config.get("lora_task_type", "CAUSAL_LM"),
)
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
# Load tokenizer
tokenizer = AutoTokenizer.from_pretrained(config["base_model"])
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"
# Load dataset
from datasets import load_dataset
import os
# Get dataset paths - go up to project root
repo_root = Path(__file__).parent.parent.parent
train_path = str(repo_root / "training" / "data" / "train.jsonl")
test_path = str(repo_root / "training" / "data" / "test.jsonl")
print(f"Looking for dataset at: {train_path}")
dataset = load_dataset(
"json",
data_files={
"train": train_path,
"test": test_path,
},
)
# Training arguments (max_seq_length removed - passed to SFTTrainer instead)
training_args = TrainingArguments(
output_dir=config["train_params"]["output_dir"],
num_train_epochs=config["train_params"]["num_train_epochs"],
per_device_train_batch_size=config["train_params"]["per_device_train_batch_size"],
gradient_accumulation_steps=config["train_params"]["gradient_accumulation_steps"],
learning_rate=float(config["train_params"]["learning_rate"]),
lr_scheduler_type=config["train_params"]["lr_scheduler_type"],
weight_decay=config["train_params"]["weight_decay"],
warmup_steps=int(config["train_params"]["warmup_ratio"] * config["train_params"]["num_train_epochs"] * len(dataset["train"]) // config["train_params"]["per_device_train_batch_size"]),
logging_steps=config["train_params"]["logging_steps"],
save_steps=config["train_params"]["save_steps"],
save_total_limit=config["train_params"]["save_total_limit"],
eval_strategy=config.get("eval_strategy", "steps"),
eval_steps=config.get("eval_steps", 100),
bf16=config.get("mixed_precision", "bf16") == "bf16",
fp16=config.get("mixed_precision", "bf16") == "fp16",
gradient_checkpointing=config.get("gradient_checkpointing", True),
)
# SFT Trainer (DeepSpeed handles distributed training via config)
from trl import SFTTrainer
trainer = SFTTrainer(
model=model,
processing_class=tokenizer,
train_dataset=dataset["train"],
eval_dataset=dataset["test"],
args=training_args,
)
# Train
print("Starting training...")
trainer.train()
# Save
trainer.save_model(config["train_params"]["output_dir"])
tokenizer.save_pretrained(config["train_params"]["output_dir"])
print(f"Training complete! Model saved to {config['train_params']['output_dir']}")
def main():
parser = argparse.ArgumentParser(description="Train LoRA adapter")
parser.add_argument("--config", type=str, default="training/configs/ornith-35b-lora.yaml",
help="Training configuration file")
parser.add_argument("--check-only", action="store_true",
help="Validate config and dependencies without training")
args = parser.parse_args()
if args.check_only:
check_setup(args.config)
else:
train(args.config)
def check_setup(config_path):
"""Validate config and dependencies without loading model."""
print("=== Checking Setup ===")
# Check config file
print(f"\n1. Config file: {config_path}")
if not Path(config_path).exists():
print(f" ERROR: Config file not found: {config_path}")
return False
print(" ✓ Config file exists")
# Load and validate config
with open(config_path) as f:
config = yaml.safe_load(f)
print(" ✓ Config file is valid YAML")
# Check model path
print(f"\n2. Model path: {config['base_model']}")
if Path(config['base_model']).exists():
print(f" ✓ Model path exists: {config['base_model']}")
else:
print(f" ⚠ Model path not found: {config['base_model']}")
print(" (Will download from HuggingFace during training)")
# Check dataset files
print("\n3. Dataset files:")
repo_root = Path(__file__).parent.parent.parent # Go up to project root
train_path = repo_root / "training" / "data" / "train.jsonl"
test_path = repo_root / "training" / "data" / "test.jsonl"
if train_path.exists():
print(f" ✓ Train data: {train_path}")
else:
print(f" ✗ Train data missing: {train_path}")
if test_path.exists():
print(f" ✓ Test data: {test_path}")
else:
print(f" ✗ Test data missing: {test_path}")
# Check GPU
print("\n4. GPU:")
import torch
if torch.cuda.is_available():
print(f" ✓ GPU available: {torch.cuda.get_device_name(0)}")
print(f" ✓ VRAM: {torch.cuda.get_device_properties(0).total_memory / 1e9:.1f} GB")
print(f" ✓ GPU count: {torch.cuda.device_count()}")
else:
print(" ✗ No GPU detected!")
return False
# Check required packages
print("\n5. Required packages:")
packages = ['transformers', 'datasets', 'trl', 'peft', 'accelerate', 'deepspeed']
for pkg in packages:
try:
__import__(pkg)
print(f"{pkg}")
except ImportError:
print(f"{pkg} not installed")
# Check DeepSpeed config
print("\n6. DeepSpeed config:")
if 'deepspeed_config' in config:
print(" ✓ DeepSpeed config present")
ds_config = config['deepspeed_config']
if 'zero_optimization' in ds_config:
stage = ds_config['zero_optimization'].get('stage', 'N/A')
print(f" ✓ ZeRO stage: {stage}")
else:
print(" ✗ No DeepSpeed config found")
print("\n=== Check Complete ===")
print("If all checks pass, you can run training with:")
print(f" bash train-on-this-server.sh")
if __name__ == "__main__":
main()