# Install necessary packages
!pip install unsloth
# Get the latest nightly Unsloth
!pip uninstall unsloth -y && pip install --upgrade --no-cache-dir "unsloth[colab-new] @ git+https://github.com/unslothai/unsloth.git"

# Install Flash Attention 2 for softcapping support
import torch
if torch.cuda.get_device_capability()[0] >= 8:
    !pip install --no-deps packaging ninja einops "flash-attn>=2.6.3"

from unsloth import FastLanguageModel
import torch

# Configuration parameters
max_seq_length = 2048  # Adjust if necessary
dtype = None  # Auto-detection
load_in_4bit = True  # 4-bit quantization

# List of 4-bit pre-quantized models
fourbit_models = [
    "unsloth/Meta-Llama-3.1-8B-bnb-4bit",
    "unsloth/Meta-Llama-3.1-8B-Instruct-bnb-4bit",
    "unsloth/Meta-Llama-3.1-70B-bnb-4bit",
    "unsloth/Meta-Llama-3.1-405B-bnb-4bit",
    "unsloth/Mistral-Nemo-Base-2407-bnb-4bit",
    "unsloth/Mistral-Nemo-Instruct-2407-bnb-4bit",
    "unsloth/mistral-7b-v0.3-bnb-4bit",
    "unsloth/mistral-7b-instruct-v0.3-bnb-4bit",
    "unsloth/Phi-3-mini-4k-instruct",
    "unsloth/Phi-3-medium-4k-instruct",
    "unsloth/gemma-2-9b-bnb-4bit",
    "unsloth/gemma-2-27b-bnb-4bit",
    "unsloth/gemma-2-2b-bnb-4bit",
]  # More models available at https://huggingface.co/unsloth

# Load the model and tokenizer
model, tokenizer = FastLanguageModel.from_pretrained(
    model_name="unsloth/gemma-2-2b",
    max_seq_length=max_seq_length,
    dtype=dtype,
    load_in_4bit=load_in_4bit,
)

# Apply PEFT (Parameter-Efficient Fine-Tuning) with LoRA
model = FastLanguageModel.get_peft_model(
    model,
    r=16,  # LoRA rank
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
                    "gate_proj", "up_proj", "down_proj"],
    lora_alpha=16,
    lora_dropout=0,  # Optimized for performance
    bias="none",  # Optimized setting
    use_gradient_checkpointing="unsloth",  # Reduces memory usage
    random_state=3407,
    use_rslora=False,  # Disable if not using rank stabilized LoRA
    loftq_config=None,  # Disable LoftQ if not used
)

# Prepare the Alpaca prompt formatting
alpaca_prompt = """Below is an instruction that describes a task, paired with an input that provides further context. Write a response that appropriately completes the request.

### Instruction:
{}

### Input:
{}

### Response:
{}"""

EOS_TOKEN = tokenizer.eos_token  # Essential for stopping generation

def formatting_prompts_func(examples):
    instructions = examples["instruction"]
    inputs = examples["input"]
    outputs = examples["output"]
    texts = []
    for instruction, input_text, output in zip(instructions, inputs, outputs):
        # Append EOS_TOKEN to prevent infinite generation
        text = alpaca_prompt.format(instruction, input_text, output) + EOS_TOKEN
        texts.append(text)
    return {"text": texts}

# Load and preprocess the dataset
from datasets import load_dataset
dataset = load_dataset("yahma/alpaca-cleaned", split="train")
dataset = dataset.map(formatting_prompts_func, batched=True)

# Bayesian Optimization for Hyperparameter Tuning
import optuna
from trl import SFTTrainer
from transformers import TrainingArguments
from unsloth import is_bfloat16_supported

# Define the objective function for Optuna
def objective(trial):
    # Define hyperparameters to tune
    per_device_train_batch_size = trial.suggest_categorical('per_device_train_batch_size', [1, 2, 4])
    gradient_accumulation_steps = trial.suggest_categorical('gradient_accumulation_steps', [2, 4, 8])
    learning_rate = trial.suggest_loguniform('learning_rate', 1e-5, 1e-3)
    lora_alpha = trial.suggest_categorical('lora_alpha', [8, 16, 32])
    
    # Initialize TrainingArguments with trial parameters
    training_args = TrainingArguments(
        per_device_train_batch_size=per_device_train_batch_size,
        gradient_accumulation_steps=gradient_accumulation_steps,
        warmup_steps=5,
        num_train_epochs=1,  # For full training, adjust as needed
        max_steps=60,
        learning_rate=learning_rate,
        fp16=not is_bfloat16_supported(),
        bf16=is_bfloat16_supported(),
        logging_steps=1,
        optim="adamw_8bit",
        weight_decay=0.01,
        lr_scheduler_type="linear",
        seed=3407,
        output_dir="outputs",
    )
    
    # Initialize the trainer with trial hyperparameters
    trainer = SFTTrainer(
        model=model,
        tokenizer=tokenizer,
        train_dataset=dataset,
        dataset_text_field="text",
        max_seq_length=max_seq_length,
        dataset_num_proc=2,
        packing=False,
        args=training_args,
    )
    
    # Train the model
    trainer.train()
    
    # Evaluate the model (you can define a validation metric)
    # For simplicity, we'll return the loss
    eval_results = trainer.evaluate()
    return eval_results["eval_loss"]

# Create and run the Optuna study
study = optuna.create_study(direction='minimize')
study.optimize(objective, n_trials=10)  # Adjust n_trials as needed

# Retrieve the best hyperparameters
best_params = study.best_params
print("Best Hyperparameters:", best_params)

# Train the final model with the best hyperparameters
final_training_args = TrainingArguments(
    per_device_train_batch_size=best_params['per_device_train_batch_size'],
    gradient_accumulation_steps=best_params['gradient_accumulation_steps'],
    warmup_steps=5,
    num_train_epochs=1,  # Adjust for full training
    max_steps=60,
    learning_rate=best_params['learning_rate'],
    fp16=not is_bfloat16_supported(),
    bf16=is_bfloat16_supported(),
    logging_steps=1,
    optim="adamw_8bit",
    weight_decay=0.01,
    lr_scheduler_type="linear",
    seed=3407,
    output_dir="outputs_final",
)

final_trainer = SFTTrainer(
    model=model,
    tokenizer=tokenizer,
    train_dataset=dataset,
    dataset_text_field="text",
    max_seq_length=max_seq_length,
    dataset_num_proc=2,
    packing=False,
    args=final_training_args,
)

# Start the final training
final_trainer.train()


lütfen sana verdiğim bu kodu CoT yapısına uygun bir mimari haline getir ve onu T4 15GB VRAM GPU'da fine tune edilebilecek hale getir. 
CoT yapısına uygun olsun.