refactor: restructure project - scripts at root level
This commit is contained in:
@@ -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()
|
||||
@@ -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()
|
||||
@@ -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"
|
||||
@@ -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()
|
||||
Reference in New Issue
Block a user