Sravanigunnu/gemma-3-4b-macd-hindi-spotcheck-lora
013
Gemma-3-4B-it — Hindi Hate Speech LoRA (Spot-check)
LoRA adapter fine-tuned on the label-verified subset of MACD Hindi training data (rows where ground-truth, GPT-5.4, and Claude Opus 4.5 all agreed on the label). Part of the project "Are Multilingual LLMs Reliable Content Moderators of Indic Hate Speech?"
The spot-check adapter uses ~22% fewer samples but achieves similar macro F1, demonstrating that label quality outweighs dataset size for this task.
LoRA configuration
Quick start
from transformers import AutoTokenizer, AutoModelForCausalLM
from peft import PeftModel
import torch
BASE_MODEL = "google/gemma-3-4b-it"
ADAPTER = "Sravanigunnu/gemma-3-4b-macd-hindi-spotcheck-lora"
tokenizer = AutoTokenizer.from_pretrained(ADAPTER, use_fast=True)
base = AutoModelForCausalLM.from_pretrained(BASE_MODEL, torch_dtype=torch.bfloat16, device_map="auto")
model = PeftModel.from_pretrained(base, ADAPTER)
model.eval()
SYSTEM = (
"You are a hate speech classifier for social media content. "
"Classify the given text as abusive or non-abusive. "
"Reply with only '1' if the text contains hate speech or abuse, "
"or '0' if it is non-abusive. Do not explain your answer."
)
def classify(text: str) -> int:
messages = [{"role": "system", "content": SYSTEM},
{"role": "user", "content": text}]
prompt = tokenizer.apply_chat_template(
messages, tokenize=False, add_generation_prompt=True
) + "Label: "
base_ids = tokenizer.encode(prompt, add_special_tokens=False)
id0 = tokenizer.encode(prompt + "0", add_special_tokens=False)[len(base_ids)]
id1 = tokenizer.encode(prompt + "1", add_special_tokens=False)[len(base_ids)]
ids = tokenizer(prompt, return_tensors="pt").input_ids.to(model.device)
with torch.no_grad():
logits = model(ids).logits[0, -1, :]
probs = torch.softmax(torch.stack([logits[id0], logits[id1]]), dim=-1)
return int(probs.argmax().item()) # 0 = non-abusive, 1 = abusive