CoolFace
Modelpublic

contemmcm/gemma-3-4b-full-bluesky-moderation

sourceHugging Facegemmaupdated 6d agoView on Hugging Face
0likes53downloads
Model Card

gemma-3-4b-full-bluesky-moderation

This model is a fine-tuned version of google/gemma-3-4b-it on the ModerationBenchV2 dataset. It achieves the following results on the evaluation set:

  • —Loss: 0.2356
  • —Micro F1: 0.7142
  • —Macro F1: 0.3023
  • —Macro F1 Seen: 0.3500
  • —Macro Ap: 0.4773
  • —Exact Match: 0.8218
  • —Safe Accuracy: 0.9007

Model description

A multi-label content-moderation classifier for Bluesky posts (text and images). It is a full fine-tune of Gemma 3 4B with the language-model head replaced by a classification head: one forward pass returns 22 independent sigmoid scores, one per moderation label, trained with binary cross-entropy. A post can carry several labels at once, and no label reaching its threshold means "safe". There is no generated text to parse.

The 22 labels, in output order (also in label_space.json):

pornsexualnuditysexual-figurative
graphic-mediaself-harmsensitiveextremist
intolerantthreatrudeillicit
securityunsafe-linkimpersonationmisinformation
rumormisleadingscamengagement-farming
spaminauthentic

How to use

No custom code is needed: the checkpoint loads into transformers' stock Gemma3ForSequenceClassification (requires transformers>=5).

python
import torch

from transformers import AutoProcessor, Gemma3ForSequenceClassification

MODEL = "contemmcm/gemma-3-4b-full-bluesky-moderation"

# must be exactly this text: the model was trained with it
SYSTEM_PROMPT = (
    "You are a content moderation classifier for social media posts. "
    "Read the post and assess which moderation labels apply."
)

processor = AutoProcessor.from_pretrained(MODEL)
model = Gemma3ForSequenceClassification.from_pretrained(
    MODEL, dtype=torch.bfloat16, device_map="cuda:0"
).eval()

# A real post: https://bsky.app/profile/did:plc:3htuuatm2fchjvon7tpc2jge/post/3mtd2ffcsvk22
text = (
    "Get Your Summer Tees Here & Please FOLLOW & SHARE. Tees Starting At Just $16. (Wait for "
    "the 35-40% off sales, 2-3 times a month.) I, Also, Have Mugs, Tote Bags, Magnets, "
    "Stickers, Etc., Available. Over 250 Designs! If You DO Make A Purchase, Thanks In "
    "Advance! www.teepublic.com/user/roszelle-art"
)
image = (
    "https://cdn.bsky.app/img/feed_fullsize/plain/did:plc:3htuuatm2fchjvon7tpc2jge/"
    "bafkreigp5m25icqkxlrm6pvbpzvey2g5bchrqonlyaypo7cs6ahqsekaey"
)
messages = [
    {"role": "system", "content": [{"type": "text", "text": SYSTEM_PROMPT}]},
    {"role": "user", "content": [{"type": "image", "url": image},
                                 {"type": "text", "text": text}]},
]

inputs = processor.apply_chat_template(
    messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt"
).to(model.device)

with torch.no_grad():
    probs = torch.sigmoid(model(**inputs).logits[0].float()).tolist()

# a label applies when its probability reaches that label's threshold; none means "safe"
import json

from huggingface_hub import hf_hub_download

labels = json.load(open(hf_hub_download(MODEL, "label_space.json")))["labels"]
thresholds = json.load(open(hf_hub_download(MODEL, "thresholds.json")))["thresholds"]

for name, p, cut in zip(labels, probs, thresholds):
    if p >= cut:
        print(f"{name}: {p:.3f}")

Output:

spam: 0.898

Pass every image of the post, in order, as its own {"type": "image", ...} entry before the text ("url", or "path" for a local file). A text-only post simply has no image entries.

Training procedure

Training hyperparameters

The following hyperparameters were used during training:

  • —learning_rate: 1e-05
  • —trainbatchsize: 2
  • —evalbatchsize: 8
  • —seed: 42
  • —distributed_type: multi-GPU
  • —num_devices: 8
  • —gradientaccumulationsteps: 2
  • —totaltrainbatch_size: 32
  • —totalevalbatch_size: 64
  • —optimizer: Use OptimizerNames.ADAMWTORCH with betas=(0.9,0.999) and epsilon=1e-08 and optimizerargs=No additional optimizer arguments
  • —lrschedulertype: cosine
  • —lrschedulerwarmup_steps: 0.03
  • —num_epochs: 4.0

Training results

Training LossEpochStepValidation LossMicro F1Macro F1Macro F1 SeenMacro ApExact MatchSafe Accuracy
0.62850.28452000.35110.56210.15440.17870.26420.76330.8524
0.55620.56904000.29210.65200.20360.23570.35760.77300.8742
0.56470.85356000.25430.63700.21710.25140.40520.79690.8713
0.40411.13808000.25530.69090.25630.29680.39930.80770.8881
0.34621.422510000.25240.67790.28040.32460.42330.81230.8891
0.44891.707012000.22750.70010.26770.30990.47150.82120.8918
0.40561.991514000.22160.70.28400.32890.47810.81710.8914
0.33662.276016000.23400.70120.28740.33270.47720.82020.8966
0.27672.560518000.23320.70940.30890.35760.48010.82020.8985
0.33642.845020000.23490.71150.30390.35180.47680.82290.9012
0.29613.129422000.23500.71640.30320.35100.47590.82270.9012
0.26173.413924000.23640.71520.30250.35020.47610.82270.9001
0.25773.698426000.23540.71220.30100.34860.47740.82140.9005
0.24283.982928000.23570.71360.30210.34980.47730.82140.9005
0.24284.028120.23560.71420.30230.35000.47730.82180.9007

Framework versions

  • —Transformers 5.12.1
  • —Pytorch 2.6.0+cu124
  • —Datasets 5.0.1
  • —Tokenizers 0.22.2