Stack-2-9-finetuned / stack /training /together_finetune.py
walidsobhie-code
feat: Add free deployment support for Stack 2.9
239da7a
"""
Together AI Fine-tuning Script for Stack 2.9
Free fine-tuning on Together AI platform.
https://docs.together.ai/docs/fine-tuning
"""
import os
import json
import requests
from typing import Optional
TOGETHER_API = "https://api.together.xyz/v1"
class TogetherFineTuner:
def __init__(self, api_key: str = None):
self.api_key = api_key or os.environ.get("TOGETHER_API_KEY")
if not self.api_key:
raise ValueError("TOGETHER_API_KEY required")
def upload_dataset(self, file_path: str) -> str:
"""Upload training data to Together AI"""
url = f"{TOGETHER_API}/files"
with open(file_path, 'rb') as f:
response = requests.post(
url,
headers={"Authorization": f"Bearer {self.api_key}"},
files={"file": f}
)
if response.status_code == 200:
return response.json()['id']
raise Exception(f"Upload failed: {response.text}")
def create_finetune_job(
self,
model: str,
training_file: str,
epochs: int = 3,
batch_size: int = 4,
learning_rate: float = 1e-5,
) -> dict:
"""
Create fine-tuning job on Together AI
Free tier: Up to 7B models, limited training minutes
"""
url = f"{TOGETHER_API}/fine_tuning/jobs"
payload = {
"model": model, # e.g., "Qwen/Qwen2.5-Coder-7B"
"training_file": training_file,
"epochs": epochs,
"batch_size": batch_size,
"learning_rate": learning_rate,
"lora": True, # Enable LoRA for efficiency
"lora_r": 64,
"lora_alpha": 128,
}
response = requests.post(
url,
headers={
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json"
},
json=payload
)
if response.status_code == 200:
return response.json()
raise Exception(f"Job creation failed: {response.text}")
def get_job_status(self, job_id: str) -> dict:
"""Check fine-tuning job status"""
url = f"{TOGETHER_API}/fine_tuning/jobs/{job_id}"
response = requests.get(
url,
headers={"Authorization": f"Bearer {self.api_key}"}
)
return response.json()
def list_fine_tuned_models(self) -> list:
"""List your fine-tuned models"""
url = f"{TOGETHER_API}/fine_tuning/models"
response = requests.get(
url,
headers={"Authorization": f"Bearer {self.api_key}"}
)
return response.json().get('models', [])
# Recommended models for free tier
FREE_TIER_MODELS = {
"7b": "Qwen/Qwen2.5-Coder-7B",
"3b": "Qwen/Qwen2.5-Coder-3B",
"1.5b": "Qwen/Qwen2.5-Coder-1.5B",
}
def main():
import argparse
parser = argparse.ArgumentParser(description="Fine-tune on Together AI")
parser.add_argument("--api-key", type=str, help="Together AI API key")
parser.add_argument("--model", default="7b", choices=["7b", "3b", "1.5b"],
help="Model size")
parser.add_argument("--data", required=True, help="Training data file (JSONL)")
parser.add_argument("--epochs", type=int, default=3)
args = parser.parse_args()
tuner = TogetherFineTuner(args.api_key)
# Upload data
print("Uploading dataset...")
file_id = tuner.upload_dataset(args.data)
print(f"Uploaded: {file_id}")
# Start job
model_name = FREE_TIER_MODELS[args.model]
print(f"Starting fine-tune on {model_name}...")
job = tuner.create_finetune_job(
model=model_name,
training_file=file_id,
epochs=args.epochs,
)
print(f"Job created: {job['id']}")
print(f"Status: {job['status']}")
if __name__ == "__main__":
main()