Views
No views yet
| Macro F1 | |
|---|---|
| Zero-shot baseline | 0.7863 |
| This adapter | 0.9201 |
| Parameter | Value |
|---|---|
r | 16 |
lora_alpha | 32 |
lora_dropout | 0.05 |
target_modules | q_proj, k_proj, v_proj, o_proj |
| Epochs | 3 |
| Learning rate | 2 × 10⁻⁴ |
| Precision | bfloat16 |
| Training samples | ~26,911 |
1from transformers import AutoTokenizer, AutoModelForCausalLM
2from peft import PeftModel
3import torch
4
5BASE_MODEL = "google/gemma-3-4b-it"
6ADAPTER = "Sravanigunnu/gemma-3-4b-macd-hindi-hate-speech-lora"
7
8tokenizer = AutoTokenizer.from_pretrained(ADAPTER, use_fast=True)
9base = AutoModelForCausalLM.from_pretrained(BASE_MODEL, torch_dtype=torch.bfloat16, device_map="auto")
10model = PeftModel.from_pretrained(base, ADAPTER)
11model.eval()
12
13SYSTEM = (
14 "You are a hate speech classifier for social media content. "
15 "Classify the given text as abusive or non-abusive. "
16 "Reply with only '1' if the text contains hate speech or abuse, "
17 "or '0' if it is non-abusive. Do not explain your answer."
18)
19
20def classify(text: str) -> int:
21 messages = [{"role": "system", "content": SYSTEM},
22 {"role": "user", "content": text}]
23 prompt = tokenizer.apply_chat_template(
24 messages, tokenize=False, add_generation_prompt=True
25 ) + "Label: "
26
27 ids = tokenizer(prompt, return_tensors="pt").input_ids.to(model.device)
28
29 # Resolve token IDs for "0" and "1" in generation context
30 base_ids = tokenizer.encode(prompt, add_special_tokens=False)
31 id0 = tokenizer.encode(prompt + "0", add_special_tokens=False)[len(base_ids)]
32 id1 = tokenizer.encode(prompt + "1", add_special_tokens=False)[len(base_ids)]
33
34 with torch.no_grad():
35 logits = model(ids).logits[0, -1, :]
36
37 pair = torch.stack([logits[id0], logits[id1]])
38 probs = torch.softmax(pair, dim=-1)
39 return int(probs.argmax().item()) # 0 = non-abusive, 1 = abusive
40
41# Example
42print(classify("This is a neutral message.")) # → 01import pandas as pd
2from tqdm import tqdm
3
4def classify_batch(texts: list[str], batch_size: int = 16) -> list[int]:
5 tokenizer.padding_side = "left"
6 base_ids = tokenizer.encode(
7 tokenizer.apply_chat_template(
8 [{"role": "system", "content": SYSTEM}, {"role": "user", "content": "x"}],
9 tokenize=False, add_generation_prompt=True
10 ) + "Label: ",
11 add_special_tokens=False,
12 )
13 sample_prompt = tokenizer.apply_chat_template(
14 [{"role": "system", "content": SYSTEM}, {"role": "user", "content": texts[0]}],
15 tokenize=False, add_generation_prompt=True
16 ) + "Label: "
17 id0 = tokenizer.encode(sample_prompt + "0", add_special_tokens=False)[len(base_ids)]
18 id1 = tokenizer.encode(sample_prompt + "1", add_special_tokens=False)[len(base_ids)]
19
20 all_preds = []
21 for start in tqdm(range(0, len(texts), batch_size)):
22 batch = texts[start : start + batch_size]
23 prompts = [
24 tokenizer.apply_chat_template(
25 [{"role": "system", "content": SYSTEM}, {"role": "user", "content": t}],
26 tokenize=False, add_generation_prompt=True
27 ) + "Label: "
28 for t in batch
29 ]
30 enc = tokenizer(prompts, return_tensors="pt", padding=True,
31 truncation=True, max_length=512).to(model.device)
32 with torch.no_grad():
33 logits = model(**enc).logits[:, -1, :]
34 pair = torch.stack([logits[:, id0], logits[:, id1]], dim=-1)
35 probs = torch.softmax(pair, dim=-1)
36 all_preds.extend(probs.argmax(dim=-1).cpu().tolist())
37 return all_preds