Sexual Elements Detection — YOLO11 (Nano / Small / Medium)
A fine-tuned Ultralytics YOLO11 detector that recognizes 28 fine-grained categories of sexually-explicit visual content. It is intended as a content-moderation building block — feed it images and it returns bounding boxes for the adult-content categories present in the frame, which downstream systems can use to flag, blur, or block the content.
Use case: automated tagging / pre-filtering for adult content. Not a safety system on its own. The reported precision/recall are modest (see Performance); always pair with a second-line classifier or human review for production moderation.
Model variants
| File | Variant | Size | Best epoch metrics (val) | Use when |
|---|---|---|---|---|
sexual_elements_yolo11n.pt | YOLO11 Nano | 5.5 MB | P 0.567 · R 0.335 · mAP@50 0.360 · mAP@50-95 0.195 | Edge / mobile / real-time, you can tolerate lower recall |
sexual_elements_yolo11s.pt | YOLO11 Small | 19 MB | P 0.580 · R 0.357 · mAP@50 0.361 · mAP@50-95 0.209 | General-purpose — best mAP/size trade-off (recommended default) |
sexual_elements_yolo11m.pt | YOLO11 Medium | 40 MB | P 0.565 · R 0.355 · mAP@50 0.368 · mAP@50-95 0.204 | Server-side, you need every fraction of a point |
For each variant, last.pt is the final-epoch checkpoint (used to resume training) and
best.pt is the highest mAP@50 checkpoint observed during training.
Classes (28)
names:
- Ass
- Asshole
- Bikini
- Blowjob
- Booty
- Bush
- Chains
- Chocker
- Clothed
- Cum
- Dildo
- Dress
- Feet
- Flashing Tits
- From Behind
- Heels
- Leather Lingerie
- Lesbian
- Lingerie
- Penis
- Pussy
- Rope
- Sex
- Shower
- Stockings
- Tits
- Tounge Out
- Underwear
How to use
With the ultralytics Python package (recommended)
from ultralytics import YOLO
from huggingface_hub import hf_hub_download
# Pick a variant
REPO = "your-hf-username/sexual-elements-yolo11"
VARIANT = "yolo11s-sexual-elements" # or nano / medium
weights = hf_hub_download(repo_id=REPO, filename=f"{VARIANT}/best.pt")
model = YOLO(weights)
# Image
results = model.predict(source="image.jpg", conf=0.25, iou=0.7)
for r in results:
r.show() # display
r.save("out.jpg") # write annotated image
for box in r.boxes:
cls_id = int(box.cls[0])
conf = float(box.conf[0])
xyxy = box.xyxy[0].tolist()
print(model.names[cls_id], conf, xyxy)
# Folder
model.predict(source="images_folder/", save=True, conf=0.25)
# Video
model.predict(source="video.mp4", save=True, conf=0.25)
With the Hugging Face pipeline API
from transformers import pipeline
detector = pipeline(
task="object-detection",
model="your-hf-username/sexual-elements-yolo11",
model_variant="yolo11s-sexual-elements", # picks subfolder
)
detector("image.jpg", threshold=0.25)
Inference defaults (from args.yaml)
| Parameter | Value |
|---|---|
| imgsz | 640 |
| conf (recommended) | 0.25 |
| iou (NMS) | 0.7 |
| max_det | 300 |
| device | auto (cpu / cuda / mps) |
Tune conf upward to reduce false positives, downward to catch more recall.
Training
- Base model: YOLO11 (Ultralytics), pre-trained on COCO.
- Dataset: michaels-workspace-18cet/main-hsqfp (https://universe.roboflow.com/michaels-workspace-18cet/main-hsqfp) version 5 — 3,649 images in YOLOv11 format, CC BY 4.0. Pre-processing: auto-orient + resize to 512×512 (stretch). Augmentation (×3 per source): random rotation ±12°, Gaussian blur 0–1.3 px, salt-and-pepper noise on 0.83% of pixels.
- Splits: Roboflow's default train/valid/test (counts visible in data.yaml).
- Hyperparameters: 100 epochs, batch 32 (Nano/Small) / 16 (Medium), imgsz=640, lr0=0.01, lrf=0.01, cos_lr=False, close_mosaic=10, patience=100, optimizer=auto, amp=True, mosaic/mixup/copy-paste defaults, erasing=0.4, auto_augment=randaugment. See args.yaml in each variant folder for the full list.
- Hardware: Apple M-series (MPS).
- Determinism: seed=0, deterministic=True, cache=False.
To reproduce locally:
pip install ultralytics roboflow
# download the Roboflow v5 dataset
python -c "from roboflow import Roboflow; rf=Roboflow(api_key='...'); \
rf.workspace('michaels-workspace-18cet').project('main-hsqfp').version(5).download('yolov11')"
yolo detect train model=yolo11s.pt data=main-5/data.yaml epochs=100 imgsz=640 \
batch=32 device=mps project=sexual_elements name=sexual_small
Performance
All metrics are computed on the Roboflow validation split (the standard valid/images folder shipped with the dataset) and reported by Ultralytics at the end of training (results.csv, last row = epoch 100, i.e. the model has converged — no early stopping triggered because patience=100).
| Metric | Nano (n) | Small (s) | Medium (m) |
|---|---|---|---|
| Precision (B) | 0.567 | 0.580 | 0.565 |
| Recall (B) | 0.335 | 0.357 | 0.355 |
| mAP@50 (B) | 0.360 | 0.361 | 0.368 |
| mAP@50-95 (B) | 0.195 | 0.209 | 0.204 |
| Train time (100 ep) | ~0.45 h | ~20.3 h | ~9.4 h* |
- Medium used batch 16; Nano/Small used batch 32, on the same MPS device. The runtimes are informational only — they are sensitive to background load.
Best-epoch mAP@50 observed during training (peak value of the metrics/mAP50(B) column in results.csv):
| Variant | Best mAP@50 | Best mAP@50-95 |
|---|---|---|
| Nano | 0.3665 | 0.2145 |
| Small | 0.3912 | 0.2269 |
| Medium | 0.3720 | 0.2145 |
The best.pt artifact in each variant folder is the checkpoint corresponding to the highest mAP@50 reached during training, not the final epoch. Curves and confusion matrices for that checkpoint are in the variant's subfolder.
Per-class breakdown is visible in confusion_matrix_normalized.png inside each variant folder.
How to read the reliability of this model
- Precision ≈ 0.57 — when the model draws a box, it is right about 57% of the time. The remaining ~43% are false positives: most often, underwear / bikini / lingerie getting confused with each other, or non-sexual skin/body regions being flagged. Lowering conf (e.g. 0.10) increases recall but multiplies false positives.
- Recall ≈ 0.35 — the model only finds about a third of the relevant objects in an image. Many small / occluded / partial instances are missed.
- mAP@50-95 ≈ 0.20 — strict localization is the model's weakest point; boxes often drift from the ground-truth rectangle. Prefer iou=0.5 (mAP@50) when comparing downstream.
- Class imbalance is high. The dataset has 28 classes spanning "Dress" to "Blowjob" to "Penis". Performance on the rarer, more specific classes (e.g. Dildo, Rope, Chains) is markedly worse than on the well-represented ones (e.g. Bikini, Tits, Lingerie). Check the normalized confusion matrix to see per-class accuracy.
- Domain shift is real. Training images were resized to 512×512 and rotated/blurred/noised. Real-world photos (high-res, sharp, varied lighting) may produce different numbers — usually a few points lower. Re-validate on a sample of your own data before deploying.
In short: treat this model as a triage signal, not a decision-maker. Use it to surface candidate regions, then route to a more accurate classifier or a human reviewer.
Intended use & limitations
Intended:
- Pre-filtering for NSFW pipelines; flagging bounding boxes around adult-content categories in user-uploaded images.
- Research baselines for fine-grained sexual-content detection.
- Educational reference for fine-tuning YOLO11 on multi-label adult content.
Out of scope / not suitable for:
- Detecting minors, CSAM, or illegal content — this model was trained on a generic consent-implied dataset and has no age estimation. Use a dedicated, audited system.
- Replacing human moderation.
- Medical, legal, or identity-verification decisions.
- Use as the sole gate for content takedown (too many false negatives at recall ≈ 0.35).
Bias, ethics, and responsible use
- The training data is sourced from a single Roboflow project and reflects that project's labelling conventions. Some labels (e.g. Bikini vs Underwear vs Lingerie) are culturally subjective and may not align with your product's policy.
- The model can misclassify non-sexual imagery (e.g. swimwear, art, medical content) as sexual — always provide users with a review/appeal path.
- Do not deploy in jurisdictions where automated adult-content detection is regulated without legal review.
License
- Dataset: CC BY 4.0 (michaels-workspace-18cet/main-hsqfp (https://universe.roboflow.com/michaels-workspace-18cet/main-hsqfp)).
- Base architecture (YOLO11): AGPL-3.0. If you intend to use these weights in a closed-source / commercial product, you must obtain a commercial YOLO11 license from Ultralytics, or convert the weights to a permissive format (e.g. ONNX — see model.export(format="onnx")).
- Trained weights (this repo): Inherited from the above; treat as CC BY 4.0 for the dataset-derived content and AGPL-3.0 for the YOLO11 component.
Citation
If you use this model, please cite both the dataset and the base architecture:
bibtex
@dataset{main-hsqfp,
author = {Roboflow user workspace (michaels-workspace-18cet)},
title = {main-hsqfp (version 5)},
year = {2026},
url = {https://universe.roboflow.com/michaels-workspace-18cet/main-hsqfp}
}
@software{ultralytics_yolo11,
title = {Ultralytics YOLO11},
author = {Jocher, Glenn and Chaurasia, Ayush and Qiu, Jing},
year = {2024},
url = {https://github.com/ultralytics/ultralytics}
}
Acknowledgements
- Trained on Apple Silicon using the MPS backend.
- Dataset and labelling tool: Roboflow (https://roboflow.com/).
- Base detector: Ultralytics YOLO11 (https://github.com/ultralytics/ultralytics).