File size: 4,411 Bytes
8fccbea
 
 
 
 
 
 
7280553
8fccbea
7280553
 
8fccbea
 
7280553
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8fccbea
 
7280553
 
 
 
8fccbea
 
7280553
8fccbea
 
7280553
8fccbea
7280553
8fccbea
 
 
7280553
8fccbea
 
7280553
8fccbea
 
 
 
 
 
7280553
8fccbea
 
 
 
 
 
 
 
 
 
7280553
 
 
8fccbea
 
 
 
 
 
 
 
 
 
7280553
 
 
8fccbea
 
 
7280553
8fccbea
7280553
8fccbea
 
7280553
8fccbea
 
7280553
8fccbea
7280553
 
 
 
 
 
 
 
8fccbea
 
 
7280553
8fccbea
 
7280553
8fccbea
7280553
 
8fccbea
7280553
8fccbea
7280553
8fccbea
 
 
7280553
8fccbea
 
 
 
 
7280553
8fccbea
7280553
8fccbea
 
7280553
8fccbea
 
7280553
 
 
 
 
 
 
8fccbea
7280553
8fccbea
 
 
7280553
8fccbea
 
 
 
 
 
 
 
 
7280553
8fccbea
 
7280553
 
 
 
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# ==============================
# IMPORTS
# ==============================
import torch
import re
import time
import gradio as gr
from transformers import AutoTokenizer, AutoModelForCausalLM
from peft import PeftModel
import zipfile
import os

# ==============================
# UNZIP MODEL
# ==============================
zip_path = "./1epoch-cds-mistral4bit-training.zip"
extract_path = "./1epoch-cds-mistral4bit-training"

if not os.path.exists(extract_path):
    print("πŸ“¦ Extracting model...")
    with zipfile.ZipFile(zip_path, 'r') as zip_ref:
        zip_ref.extractall(extract_path)
    print("βœ… Done")
else:
    print("βœ… Model already extracted")

# ==============================
# GPU STATUS FUNCTION (SAFE)
# ==============================
def print_gpu():
    try:
        os.system("nvidia-smi")
    except:
        print("No GPU (running on CPU)")

# ==============================
# LOAD MODEL
# ==============================
BASE_MODEL = "mistralai/Mistral-7B-v0.1"
MODEL_PATH = "./1epoch-cds-mistral4bit-training/mistral7b_fast/checkpoint-7125"

print("πŸš€ Loading model...")

tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL)

# CPU SAFE LOADING
base_model = AutoModelForCausalLM.from_pretrained(
    BASE_MODEL,
    device_map={"": "cpu"}
)

model = PeftModel.from_pretrained(base_model, MODEL_PATH)
model.eval()

# ==============================
# CLEAN OUTPUT
# ==============================
def clean_output(text):
    text = text.strip()
    text = re.sub(r"\n+", "\n", text)
    if "Final Decision:" in text:
        before, after = text.split("Final Decision:", 1)
        decision_line = after.split("\n")[0]
        return before.strip() + "\n\nFinal Decision: " + decision_line.strip()
    return text

# ==============================
# LABEL EXTRACTION
# ==============================
def extract_label(text):
    text = text.lower()
    if "final decision" in text:
        decision_part = text.split("final decision")[-1]
        if "not hate" in decision_part:
            return "non_hate"
        elif "hate" in decision_part:
            return "hate"
    return "unknown"

# ==============================
# METRICS
# ==============================
def compute_metrics(output, post):
    out = output.lower()
    post = post.lower()

    htc = 1 if "final decision" in out else 0

    post_words = post.split()
    qf = 1 if any(word in out for word in post_words[:5]) else 0

    tgi_keywords = ["muslim","black","white","asian","women","men","jews","christian","pakistan","indian"]
    tgi = 1 if any(word in out for word in tgi_keywords) else 0

    pred = extract_label(out)

    if pred == "hate" and "hate" in out:
        cons = 1
    elif pred == "non_hate" and "not hate" in out:
        cons = 1
    else:
        cons = 0

    return htc, qf, tgi, cons

# ==============================
# INFERENCE FUNCTION
# ==============================
def infer(post):
    print("\nπŸ“Š STATUS BEFORE:")
    print_gpu()

    inputs = tokenizer(post, return_tensors="pt")
    token_count = inputs.input_ids.shape[1]

    start = time.time()

    with torch.no_grad():
        outputs = model.generate(
            **inputs,
            max_new_tokens=300,   # SAME as your original
            min_new_tokens=150,
            do_sample=False,
            repetition_penalty=1.15,
            pad_token_id=tokenizer.eos_token_id
        )

    end = time.time()

    output = tokenizer.decode(outputs[0], skip_special_tokens=True)
    response = clean_output(output.replace(post, "").strip())

    pred = extract_label(response)
    htc, qf, tgi, cons = compute_metrics(response, post)

    metrics = f"""Prediction: {pred}
HTC={htc}, QF={qf}, TGI={tgi}, Consistency={cons}
Tokens processed: {token_count}
Time: {end-start:.2f} sec"""

    print("\nπŸ“Š STATUS AFTER:")
    print_gpu()

    return response, metrics

# ==============================
# GRADIO UI
# ==============================
iface = gr.Interface(
    fn=infer,
    inputs=gr.Textbox(lines=3, placeholder="Enter a post here..."),
    outputs=[
        gr.Textbox(label="Model Output (Rationales + Decision)", lines=15),
        gr.Textbox(label="Metrics", lines=5)
    ],
    title="Hate Speech Rationales + Decision",
    description="Enter a post to get step-by-step reasoning + final decision"
)

# ==============================
# LAUNCH
# ==============================
iface.launch()