route96 NSFW detector (ViT 224)
Fine-tune of Falconsai/nsfw_image_detection (ViT-B/16, 224px) for the route96 media server. Labels: normal, nsfw.
Training data
About 12.7k images from nostr.download, labeled by a vision LLM (Qwen 3.5) and then corrected by hand.
- Positives: images where the LLM tags include an explicit term (nudity, genitals, sex acts, bondage and so on), plus images I confirmed by eye.
- Negatives: ordinary photos and art, plus screenshots, UI captures, documents and memes as hard negatives.
- Images where the LLM only used suggestive tags (lingerie, underwear, bikini) were left out, so the boundary for those is undefined.
- Any negative that this model, Falconsai or nostrbuild scored 0.5 or higher was reviewed by hand, and the explicit ones were relabeled.
Training: 5 epochs, AdamW, lr 2e-5, class-balanced sampling, bf16, 224px. The weights from epoch 4 are published.
Evaluation
Scores are at the default threshold of 0.5. Models with more than two classes count the sexual classes as NSFW. AP is average precision, so it does not depend on the threshold.
nostr.download held-out set (1,908 images, 209 NSFW)
Images from the same source as the training data, held out of training.
| Model | AP | Precision | Recall | F1 | False positives | Misses |
|---|---|---|---|---|---|---|
| route96-nsfw-vit224 (this model) | 0.984 | 0.917 | 0.957 | 0.937 | 18 | 9 |
Falconsai/nsfw_image_detection |
0.921 | 0.850 | 0.871 | 0.861 | 32 | 27 |
nostrbuild/nsfw-image-detection-large |
0.973 | 0.735 | 0.981 | 0.840 | 74 | 4 |
carbon225/vit-base-patch16-224-hentai |
0.963 | 0.773 | 0.947 | 0.852 | 58 | 11 |
umairrkhn/fine-tuned-nsfw-classification |
0.913 | 0.958 | 0.756 | 0.845 | 7 | 51 |
giacomoarienti/nsfw-classifier |
0.865 | 0.791 | 0.871 | 0.829 | 48 | 27 |
AdamCodd/vit-base-nsfw-detector |
0.922 | 0.690 | 0.957 | 0.802 | 90 | 9 |
LukeJacob2023/nsfw-image-detector |
0.815 | 0.635 | 0.914 | 0.749 | 110 | 18 |
Parveshiiii/SafeScan |
0.855 | 0.674 | 0.900 | 0.770 | 91 | 21 |
JanadaSroor/vit-nsfw-classifier |
0.775 | 0.271 | 0.995 | 0.426 | 559 | 1 |
Public mix (6,592 images, 3,592 NSFW)
Not seen in training: markandey14/nsfw_detection_xl (sfw and nsfw), jiangchengchengNLP/cashbox-nsfw-image-level (L3 and L4 as NSFW, L1 as normal) and DarkyMan/nsfw-image-classification. These sets define NSFW differently from the training data, so read this table loosely.
| Model | AP | Precision | Recall | F1 | False positives | Misses |
|---|---|---|---|---|---|---|
| route96-nsfw-vit224 (this model) | 0.976 | 0.938 | 0.927 | 0.932 | 222 | 261 |
Falconsai/nsfw_image_detection |
0.972 | 0.922 | 0.905 | 0.913 | 275 | 343 |
nostrbuild/nsfw-image-detection-large |
0.979 | 0.809 | 0.978 | 0.886 | 827 | 78 |
carbon225/vit-base-patch16-224-hentai |
0.968 | 0.855 | 0.941 | 0.896 | 573 | 211 |
umairrkhn/fine-tuned-nsfw-classification |
0.963 | 0.976 | 0.743 | 0.843 | 67 | 924 |
giacomoarienti/nsfw-classifier |
0.951 | 0.888 | 0.882 | 0.885 | 398 | 423 |
AdamCodd/vit-base-nsfw-detector |
0.952 | 0.834 | 0.954 | 0.890 | 681 | 165 |
LukeJacob2023/nsfw-image-detector |
0.890 | 0.827 | 0.923 | 0.872 | 694 | 278 |
Parveshiiii/SafeScan |
0.940 | 0.829 | 0.946 | 0.884 | 700 | 193 |
JanadaSroor/vit-nsfw-classifier |
0.869 | 0.652 | 0.995 | 0.788 | 1909 | 19 |
nostrbuild/nsfw-image-detection-large has the best AP on the public mix and catches more NSFW images, but it needs a threshold near 0.95 to avoid flagging many safe ones. It is a FocalNet with a non-commercial license (CC BY-NC-SA 4.0).
Training and evaluation scripts: https://github.com/v0l/route96/tree/main/training