File size: 3,187 Bytes
43ede4d
3fe3362
43ede4d
 
 
8380fa7
3fe3362
43ede4d
 
 
a9279c3
43ede4d
 
 
3fe3362
6a9d02e
 
 
3fe3362
43ede4d
 
 
 
 
 
 
8380fa7
43ede4d
 
 
6a9d02e
43ede4d
 
8380fa7
43ede4d
 
8380fa7
43ede4d
 
 
 
 
 
 
 
 
 
8380fa7
6a9d02e
 
8380fa7
39b48c7
43ede4d
6a9d02e
 
39b48c7
43ede4d
 
 
 
 
 
39b48c7
43ede4d
39b48c7
 
 
 
 
 
 
 
6a9d02e
 
39b48c7
43ede4d
 
 
 
 
 
 
 
8380fa7
43ede4d
 
3fe3362
43ede4d
 
 
3fe3362
43ede4d
3fe3362
43ede4d
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
import torch
import streamlit as st
from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments, Trainer, DataCollatorForSeq2Seq
from datasets import load_dataset
from peft import LoraConfig, get_peft_model
import os

# UI
st.title("AI Tutor (Fine-tuned LLM)")
st.write("This AI tutor is fine-tuned on Python-related questions.")

# Load base model and tokenizer
model_name = "microsoft/phi-2"
tokenizer = AutoTokenizer.from_pretrained(model_name)

# πŸ”₯ Fix: Add padding token if missing
if tokenizer.pad_token is None:
    tokenizer.add_special_tokens({'pad_token': '[PAD]'})

# Check if fine-tuned model exists
model_path = "./models"
if os.path.exists(model_path):
    st.write("βœ… Loading fine-tuned model...")
    model = AutoModelForCausalLM.from_pretrained(model_path)
else:
    st.write("⚑ Fine-tuning the model (this will take time)...")

    # Load model on CPU
    model = AutoModelForCausalLM.from_pretrained(
        model_name,
        torch_dtype=torch.float32,  # Use float32 for CPU compatibility
        device_map={"": "cpu"}  # Force CPU usage
    )

    # Resize model embeddings
    model.resize_token_embeddings(len(tokenizer))

    # Apply LoRA
    lora_config = LoraConfig(
        r=8,
        lora_alpha=32,
        target_modules=["q_proj", "v_proj", "k_proj", "o_proj"],
        lora_dropout=0.05,
        bias="none",
        task_type="CAUSAL_LM",
    )
    model = get_peft_model(model, lora_config)

    # Load dataset (Choose any one)
    dataset = load_dataset("lvwerra/codeparrot-clean", split="train")  # βœ… Free dataset

    # πŸ”₯ Fix: Set `labels` properly
    def tokenize_function(examples):
        inputs = tokenizer(examples["content"], padding="max_length", truncation=True, max_length=512)
        inputs["labels"] = inputs["input_ids"].copy()  # βœ… Ensure labels exist
        return inputs

    tokenized_dataset = dataset.map(tokenize_function, batched=True)

    # Data collator
    data_collator = DataCollatorForSeq2Seq(tokenizer, return_tensors="pt")

    # Training arguments
    training_args = TrainingArguments(
        per_device_train_batch_size=1,
        num_train_epochs=1,  # Reduce epochs for quick training
        learning_rate=3e-4,
        output_dir=model_path,
        save_strategy="epoch",
        logging_dir="./logs",
        logging_steps=10,
        save_total_limit=2,
        evaluation_strategy="no",  # βœ… No eval dataset needed
        load_best_model_at_end=False  # βœ… Prevents conflicts
    )

    # Trainer
    trainer = Trainer(
        model=model,
        args=training_args,
        train_dataset=tokenized_dataset,
        data_collator=data_collator,
    )

    # Train
    trainer.train()

    # Save model
    model.save_pretrained(model_path)
    tokenizer.save_pretrained("./tokenizer")

    st.write("πŸŽ‰ Fine-tuning complete! Model saved.")

# Chat Interface
user_input = st.text_input("Ask a coding question:")
if user_input:
    inputs = tokenizer(user_input, return_tensors="pt").to("cpu")
    outputs = model.generate(**inputs, max_length=150)
    response = tokenizer.decode(outputs[0], skip_special_tokens=True)
    st.write("πŸ€– AI Tutor:", response)