CoolFace
Modelpublic

Sravanigunnu/gemma-3-4b-macd-hindi-spotcheck-lora

sourceHugging Facegemmaupdated 1mo agoView on Hugging Face
0likes13downloads
Model Card

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?"

Training NTest NMacro F1
Original (all labels)26,9113,0000.9467
Spot-check (this adapter)22,0432,7850.9461
Δ-0.0006

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

ParameterValue
r16
lora_alpha32
lora_dropout0.05
target_modulesqproj, kproj, vproj, oproj
Epochs3
Learning rate2 × 10⁻⁴
Precisionbfloat16

Quick start

python
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