Grio43 commited on
Commit
a7d780c
·
verified ·
1 Parent(s): 48792af

Release V1.1 (448x448 fine-tune, bf16 safetensors + ONNX)

Browse files

Adds V1.1_safetensors/ and V1.1_onnx/ for the 448x448 fine-tune of V1 (epoch 7, step 85517 from experiments/run1_vit/checkpoints/last.pt). Updates top-level README.md and config.json to list both V1 and V1.1 variants.

README.md CHANGED
@@ -24,7 +24,7 @@ tags:
24
 
25
  A multi-label anime tagger trained from scratch on a \~5.9M image dataset that received a targeted cleaning and vocabulary-expansion pass before training. The corrections touched roughly **1.3M tags** — large in absolute terms, but only on the order of **\~3% of all tags** in the corpus, so this is best described as a *targeted* cleaning rather than a heavy one. The pass was deliberately weighted toward **low-frequency tags**, which is where mislabels and missing labels hurt a tagger the most. On my evaluation set the model achieves the best precision-equals-recall point and a good mAP relative to comparable open tagger checkpoints, but the underlying training data still contains category-level noise that no amount of training would have erased. **All predictions should be human-reviewed before they are trusted.**
26
 
27
- **V1** (the from-scratch 320×320 model) is shipping now. **V1.1** (a 448×448 fine-tune of V1) is **planned for release the week of 2026-05-15** and is expected to outperform V1 on this evaluation set; final numbers will be filled in once training and eval are complete. Pick the checkpoint whose native resolution matches the resolution you intend to feed it (see *Variants* below).
28
 
29
  A live demo is available on the companion Space: [Grio43/OppaiOracle](https://huggingface.co/spaces/Grio43/OppaiOracle).
30
 
@@ -34,19 +34,20 @@ A live demo is available on the companion Space: [Grio43/OppaiOracle](https://hu
34
 
35
  | Checkpoint | Native resolution | How it was produced | When to use |
36
  |---|---|---|---|
37
- | **V1** *(available now)* | 320×320 | Trained **from scratch** at 320×320. This is the model's native resolution. | Use this today. Also the right pick if you are running inference at 320×320 or if throughput matters. |
38
- | **V1.1** *(coming \~2026-05-15)* | 448×448 | A **fine-tune of V1** at 448×448. Position embeddings were interpolated from the 20×20 grid to 28×28, optimizer state was reset, and training continued at the new resolution following the FixRes / DeiT III progressive-resolution recipe. | Use when you specifically want 448×448 inference for finer spatial detail (small accessories, eye details). Internal expectation is that V1.1 will outperform V1 on the same eval set, but final numbers will only be published after V1.1 training completesuntil then, treat V1 as the reference checkpoint. |
39
 
40
  Two practical notes:
41
 
42
- - **Match input resolution to the checkpoint.** Feeding 448×448 images to V1, or 320×320 images to V1.1 once it ships, will give worse results than matching them. The position-embedding grid is fixed at load time.
43
- - **V1 is not deprecated by V1.1.** They are siblings with different operating points, not generations of the same model.
44
- - **Until V1.1 ships, V1 is the only released checkpoint.** Numbers and recommendations in this card refer to V1 unless explicitly labeled V1.1.
45
 
46
  ### Files in this repo
47
 
48
  - `V1_safetensors/` — V1 in `safetensors` format with `config.json` and `preprocessing.json`. Use this for PyTorch / custom inference.
49
  - `V1_onnx/` — V1 exported to ONNX. Use this for ONNX Runtime inference (CPU, DirectML, CUDA EP).
 
 
50
  - Each variant directory ships `vocabulary.json`, `selected_tags.csv`, `pr_thresholds.json`, and a copy of this README.
51
 
52
  ---
@@ -162,9 +163,29 @@ On my evaluation set this model achieves:
162
 
163
  Note the inversion: rare/mid tags out-score head/very-common tags on mAP. This is consistent with the missing-tag bias described above — high-frequency concepts are the ones most often present-but-unlabeled in the source data, which depresses their measured precision against a noisy reference.
164
 
165
- ### V1.1 headline numbers (pending)
166
 
167
- V1.1 has not finished training yet. Final Macro F1 / Micro F1 / mAP and the per-bucket mAP breakdown will be added here once V1.1 is released (planned for the week of 2026-05-15). Internal expectation is that V1.1 will exceed V1 on this eval set at its native 448×448 input resolution, but no measured numbers are claimed in this document until they exist.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
 
169
  I want to be honest about *why* I think it performs well: **it is almost certainly not because of a special training regimen.** The training recipe is grounded in standard ViT-from-scratch literature (DeiT / DeiT III / FixRes / ASL / AugReg) without exotic tricks. The most likely explanation is simply that the **input dataset is cleaner** than what most comparable taggers were trained on. If you are trying to reproduce or beat this result, I would put your effort into data curation before you put it into training-recipe tuning.
170
 
@@ -174,7 +195,7 @@ I want to be honest about *why* I think it performs well: **it is almost certain
174
 
175
  For reproducibility, here are the exact augmentation pipelines used for each checkpoint. V1.1 is a fine-tune of V1, so its augmentation is a *reduced* version of V1's — narrower ranges and lower probabilities at the higher 448×448 resolution. The reductions follow EfficientNetV2 / FixRes guidance for progressive-resolution training, but only partially (\~¼ reduction rather than ½), because Phase 1 stopped at 33/40 epochs and the V1 base was under-converged when V1.1 began.
176
 
177
- | Augmentation | V1 (320×320, from scratch, 40 epochs planned) | V1.1 (448×448, fine-tune of V1, 15 epochs) |
178
  |---|---|---|
179
  | Horizontal flip | p = 0.5 | p = 0.5 |
180
  | Color jitter — brightness | 0.30 (p = 0.5) | 0.22 (p = 0.5) |
 
24
 
25
  A multi-label anime tagger trained from scratch on a \~5.9M image dataset that received a targeted cleaning and vocabulary-expansion pass before training. The corrections touched roughly **1.3M tags** — large in absolute terms, but only on the order of **\~3% of all tags** in the corpus, so this is best described as a *targeted* cleaning rather than a heavy one. The pass was deliberately weighted toward **low-frequency tags**, which is where mislabels and missing labels hurt a tagger the most. On my evaluation set the model achieves the best precision-equals-recall point and a good mAP relative to comparable open tagger checkpoints, but the underlying training data still contains category-level noise that no amount of training would have erased. **All predictions should be human-reviewed before they are trusted.**
26
 
27
+ Two checkpoints are released here. **V1** is the from-scratch 320×320 model. **V1.1** is a 448×448 fine-tune of V1 and on this evaluation set posts a modest mAP gain over V1 (overall val/mAP 0.674 vs. 0.614, ~+6 points absolute, ~+10% relative). The fine-tune helps across every frequency bucket but does not transform results — both checkpoints inherit the same source-data label noise. Pick the checkpoint whose native resolution matches the resolution you intend to feed it (see *Variants* below).
28
 
29
  A live demo is available on the companion Space: [Grio43/OppaiOracle](https://huggingface.co/spaces/Grio43/OppaiOracle).
30
 
 
34
 
35
  | Checkpoint | Native resolution | How it was produced | When to use |
36
  |---|---|---|---|
37
+ | **V1** | 320×320 | Trained **from scratch** at 320×320. This is the model's native resolution. | The right pick if you are running inference at 320×320 or if throughput matters. |
38
+ | **V1.1** | 448×448 | A **fine-tune of V1** at 448×448. Position embeddings were interpolated from the 20×20 grid to 28×28, optimizer state was reset, and training continued at the new resolution following the FixRes / DeiT III progressive-resolution recipe. Trained for 6 of 15 planned epochs and stopped early — see *Performance notes / V1.1 headline numbers* below for the rationale. | Use when you specifically want 448×448 inference for finer spatial detail (small accessories, eye details). V1.1 outperforms V1 on every frequency bucket of this eval set (numbers in the *Performance notes* section), but the gain is modestV1 remains a fully reasonable choice if you are running at 320×320. |
39
 
40
  Two practical notes:
41
 
42
+ - **Match input resolution to the checkpoint.** Feeding 448×448 images to V1, or 320×320 images to V1.1, will give worse results than matching them. The position-embedding grid is fixed at load time.
43
+ - **V1 is not deprecated by V1.1.** They are siblings with different operating points, not generations of the same model. The V1.1 mAP gain over V1 is real but small (~+6 points overall) — pick on resolution, not on the assumption that V1.1 is strictly better.
 
44
 
45
  ### Files in this repo
46
 
47
  - `V1_safetensors/` — V1 in `safetensors` format with `config.json` and `preprocessing.json`. Use this for PyTorch / custom inference.
48
  - `V1_onnx/` — V1 exported to ONNX. Use this for ONNX Runtime inference (CPU, DirectML, CUDA EP).
49
+ - `V1.1_safetensors/` — V1.1 in `safetensors` format with `config.json` and `preprocessing.json`.
50
+ - `V1.1_onnx/` — V1.1 exported to ONNX.
51
  - Each variant directory ships `vocabulary.json`, `selected_tags.csv`, `pr_thresholds.json`, and a copy of this README.
52
 
53
  ---
 
163
 
164
  Note the inversion: rare/mid tags out-score head/very-common tags on mAP. This is consistent with the missing-tag bias described above — high-frequency concepts are the ones most often present-but-unlabeled in the source data, which depresses their measured precision against a noisy reference.
165
 
166
+ ### V1.1 headline numbers (e6/15, Phase 2, 448×448, 19,292 tags)
167
 
168
+ | Metric | Value |
169
+ |---|---|
170
+ | Overall val/mAP | 0.674 |
171
+
172
+ F1 / P=R numbers are intentionally not reported alongside this row — see the *Why F1 numbers are not reported for V1.1* paragraph below for the calibration reason.
173
+
174
+ **mAP broken out by tag frequency bucket — V1 vs. V1.1 on the same eval set:**
175
+
176
+ | Frequency bucket | V1 mAP | V1.1 mAP | Δ |
177
+ |---|---|---|---|
178
+ | 500–999 (rare) | 0.589 | 0.645 | +0.056 |
179
+ | 1K–5K (mid) | 0.598 | 0.656 | +0.058 |
180
+ | 5K–10K (head) | 0.535 | 0.595 | +0.060 |
181
+ | 10K+ (very common) | 0.542 | 0.606 | +0.064 |
182
+ | **Overall** | **0.614** | **0.674** | **+0.060** |
183
+
184
+ The same rare-vs-head inversion noted for V1 (rare/mid > head/very-common on mAP) is still present in V1.1, and for the same reason — high-frequency tags are the ones most often present-but-unlabeled in the source data, which depresses their measured precision against a noisy reference.
185
+
186
+ **Why V1.1 stopped at 6 of 15 planned epochs.** Per-epoch mAP growth decelerated from ~+0.7%/epoch in early Phase 2 to ~+0.3%/epoch by epoch 5, while validation loss continued to fall and per-tag calibration shifted (mean activations per image dropped from ~4500 at epoch 0 to ~4200 at epoch 5, but the auto-stop F1 metric is calibration-floored at a fixed threshold of 0.2653 and therefore unreliable as a stop signal — see [TRAINING_HEALTH_TRACKER.md](../TRAINING_HEALTH_TRACKER.md)). At that growth rate, the remaining 9 epochs would have been operating in the regime where it is no longer cleanly distinguishable whether mAP gains are *real ranking improvement* or *memorization of the labeled subset of a noisy multi-label corpus* (the missing-positive bias documented earlier in this card sets a soft ceiling somewhere in this neighbourhood). Continuing was unlikely to buy enough real gain to justify the extra training time, so V1.1 ships at the epoch-5 / step-81822 checkpoint.
187
+
188
+ **Why F1 numbers are not reported for V1.1.** V1.1's loss configuration (`gamma_neg=7.0`, `clip=0.2`) shifts the logit distribution relative to V1's (`gamma_neg=4.0`, `clip=0.05`). The in-training F1 metric uses a fixed threshold (0.2653) calibrated against V1's distribution, so V1.1's in-training F1 values are calibration-floored and not comparable to V1's reported F1. Reporting them alongside V1's would invite the wrong comparison. mAP, on the other hand, is threshold-independent and the V1 vs. V1.1 mAP comparison above is apples-to-apples — that is the comparison this card stands behind.
189
 
190
  I want to be honest about *why* I think it performs well: **it is almost certainly not because of a special training regimen.** The training recipe is grounded in standard ViT-from-scratch literature (DeiT / DeiT III / FixRes / ASL / AugReg) without exotic tricks. The most likely explanation is simply that the **input dataset is cleaner** than what most comparable taggers were trained on. If you are trying to reproduce or beat this result, I would put your effort into data curation before you put it into training-recipe tuning.
191
 
 
195
 
196
  For reproducibility, here are the exact augmentation pipelines used for each checkpoint. V1.1 is a fine-tune of V1, so its augmentation is a *reduced* version of V1's — narrower ranges and lower probabilities at the higher 448×448 resolution. The reductions follow EfficientNetV2 / FixRes guidance for progressive-resolution training, but only partially (\~¼ reduction rather than ½), because Phase 1 stopped at 33/40 epochs and the V1 base was under-converged when V1.1 began.
197
 
198
+ | Augmentation | V1 (320×320, from scratch, 40 epochs planned, 33 trained) | V1.1 (448×448, fine-tune of V1, 15 epochs planned, 6 trained) |
199
  |---|---|---|
200
  | Horizontal flip | p = 0.5 | p = 0.5 |
201
  | Color jitter — brightness | 0.30 (p = 0.5) | 0.22 (p = 0.5) |
V1.1_onnx/README.md ADDED
@@ -0,0 +1,259 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ pipeline_tag: image-classification
4
+ language:
5
+ - en
6
+ tags:
7
+ - anime
8
+ - anime-tagger
9
+ - tagger
10
+ - image-tagging
11
+ - multi-label
12
+ - multi-label-classification
13
+ - vision-transformer
14
+ - vit
15
+ - illustration
16
+ - danbooru
17
+ - safetensors
18
+ - onnx
19
+ ---
20
+
21
+
22
+
23
+ ## TL;DR
24
+
25
+ A multi-label anime tagger trained from scratch on a \~5.9M image dataset that received a targeted cleaning and vocabulary-expansion pass before training. The corrections touched roughly **1.3M tags** — large in absolute terms, but only on the order of **\~3% of all tags** in the corpus, so this is best described as a *targeted* cleaning rather than a heavy one. The pass was deliberately weighted toward **low-frequency tags**, which is where mislabels and missing labels hurt a tagger the most. On my evaluation set the model achieves the best precision-equals-recall point and a good mAP relative to comparable open tagger checkpoints, but the underlying training data still contains category-level noise that no amount of training would have erased. **All predictions should be human-reviewed before they are trusted.**
26
+
27
+ Two checkpoints are released here. **V1** is the from-scratch 320×320 model. **V1.1** is a 448×448 fine-tune of V1 and on this evaluation set posts a modest mAP gain over V1 (overall val/mAP 0.674 vs. 0.614, ~+6 points absolute, ~+10% relative). The fine-tune helps across every frequency bucket but does not transform results — both checkpoints inherit the same source-data label noise. Pick the checkpoint whose native resolution matches the resolution you intend to feed it (see *Variants* below).
28
+
29
+ A live demo is available on the companion Space: [Grio43/OppaiOracle](https://huggingface.co/spaces/Grio43/OppaiOracle).
30
+
31
+ ---
32
+
33
+ ## Variants — which checkpoint should I use?
34
+
35
+ | Checkpoint | Native resolution | How it was produced | When to use |
36
+ |---|---|---|---|
37
+ | **V1** | 320×320 | Trained **from scratch** at 320×320. This is the model's native resolution. | The right pick if you are running inference at 320×320 or if throughput matters. |
38
+ | **V1.1** | 448×448 | A **fine-tune of V1** at 448×448. Position embeddings were interpolated from the 20×20 grid to 28×28, optimizer state was reset, and training continued at the new resolution following the FixRes / DeiT III progressive-resolution recipe. Trained for 6 of 15 planned epochs and stopped early — see *Performance notes / V1.1 headline numbers* below for the rationale. | Use when you specifically want 448×448 inference for finer spatial detail (small accessories, eye details). V1.1 outperforms V1 on every frequency bucket of this eval set (numbers in the *Performance notes* section), but the gain is modest — V1 remains a fully reasonable choice if you are running at 320×320. |
39
+
40
+ Two practical notes:
41
+
42
+ - **Match input resolution to the checkpoint.** Feeding 448×448 images to V1, or 320×320 images to V1.1, will give worse results than matching them. The position-embedding grid is fixed at load time.
43
+ - **V1 is not deprecated by V1.1.** They are siblings with different operating points, not generations of the same model. The V1.1 mAP gain over V1 is real but small (~+6 points overall) — pick on resolution, not on the assumption that V1.1 is strictly better.
44
+
45
+ ### Files in this repo
46
+
47
+ - `V1_safetensors/` — V1 in `safetensors` format with `config.json` and `preprocessing.json`. Use this for PyTorch / custom inference.
48
+ - `V1_onnx/` — V1 exported to ONNX. Use this for ONNX Runtime inference (CPU, DirectML, CUDA EP).
49
+ - `V1.1_safetensors/` — V1.1 in `safetensors` format with `config.json` and `preprocessing.json`.
50
+ - `V1.1_onnx/` — V1.1 exported to ONNX.
51
+ - Each variant directory ships `vocabulary.json`, `selected_tags.csv`, `pr_thresholds.json`, and a copy of this README.
52
+
53
+ ---
54
+
55
+ ## How this model came to be
56
+
57
+ I started with a corpus of roughly **5.9 million images** with publicly-sourced tags. Before training anything of my own, I used **SmilingWolf's ViT v3 tagger** to help clean the dataset. With that pipeline I:
58
+
59
+ - **Removed \~300k incorrect tags** from images where the public labels disagreed with the AI tagger and a human spot-check confirmed the public labels were wrong.
60
+ - **Added \~1,000,000 missing tags** in the same fashion — places where the AI tagger surfaced a label the public tag set had simply omitted, and human review agreed.
61
+
62
+ That is \~1.3M corrections in total, which is only on the order of **\~3% of the tags in the corpus**. This was a *targeted* pass, not a top-to-bottom relabel. Effort was deliberately concentrated on **low-frequency tags**, on the assumption that mislabels and missing labels do disproportionate damage in the long tail — a missing label on a tag with 800 positives in the entire dataset matters far more than a missing label on a tag with 800k positives.
63
+
64
+ I then trained a small "light" model on this cleaned dataset, primarily as a vehicle to **expand the tag vocabulary by \~20,000 additional low-frequency tags** that the original tag set under-represented. That expanded vocabulary is what the released model was trained against.
65
+
66
+ The released checkpoint is the main training run on the cleaned dataset with the expanded vocabulary.
67
+
68
+ ---
69
+
70
+ ## What "cleaned" actually means (and what it does not)
71
+
72
+ This is the most important section of this release. The cleaning was real work, but it was not omniscient, and the dataset still has structured, category-level label noise that you will see in the model's outputs. Most of these issues are inherited directly from the **publicly-sourced source datasets** — they are not new noise introduced during cleaning; they are pre-existing patterns that the cleaning pass touched but did not resolve at the category level.
73
+
74
+ The categories below are **illustrative, not exhaustive.** Many other tag families show similarly deep-rooted issues. Two failure modes show up across most of them, but they are not equal in size:
75
+
76
+ - **Missing tags (by far the dominant problem)** — concepts that are clearly present in an image but were never tagged at the source. This is the single biggest source of noise in the entire dataset. See the dedicated subsection below for the empirical scale.
77
+ - **Wrong tags (not uncommon, but secondary)** — visually similar concepts confused with each other in the source data (the bow / bowtie / ribbon / ascot / necktie cluster, color buckets, length and size buckets). These are real and plentiful, just not the dominant failure mode.
78
+
79
+ ### Missing tags (the dominant noise mode)
80
+
81
+ If you only remember one thing from this section, remember this: **the biggest single problem in the source data is not wrong tags, it is missing tags.** Wrong tags are not uncommon either, but they are dwarfed in volume by labels that should be present and simply aren't.
82
+
83
+ A rough empirical sense of the gap, from manual review:
84
+
85
+ - A typical image in this dataset arrives with roughly **\~28 tags** from the source.
86
+ - A reasonably-tagged image — judged by what is actually visible, sticking to common in-vocabulary concepts and not reaching for rare tags — should have **50+ tags**, often more.
87
+ - During spot-checks I have routinely taken images that arrived with **\~40 tags up past 60 tags** just by adding common, obviously-present concepts. That is without making any effort to surface rare tags; including those would push the number higher still.
88
+
89
+ So the source tag count is on the order of **half** of what a careful tagger would emit on the same image, and the gap is concentrated in concepts that are not subjective — they are simply omissions. The cleaning pass added \~1M missing tags back, but with the gap this large there are many millions still missing across the corpus.
90
+
91
+ The training-time consequence is that for every missing-but-present tag, the model receives **no positive gradient at all** for that concept on that image — only an implicit negative through the loss. This systematically biases the model toward under-predicting any tag with a high source-data omission rate, and the effect is uneven across tags: some tag families are well-tagged at the source and some are very sparsely tagged. Practically, this means **low predicted scores are less informative than they look** — a tag scoring below threshold may be genuinely absent, or it may be a concept the model has learned is "usually unlabeled even when present."
92
+
93
+ ### Color tags
94
+
95
+ Color-named tags (eye color, hair color, general color tags) are **poorly tagged at the source**, and the noise that survived cleaning is dataset-wide. Every color tag in the vocabulary has some version of this problem; some are worse than others.
96
+
97
+ - **Obvious failures were cleanable.** A bright, unambiguous yellow mislabeled as `blue_eyes` is exactly the kind of disagreement the AI-assisted pass catches, and those got fixed. The residual noise is not the obvious-failure kind.
98
+ - **The deep-rooted issue is perceptual, not technical.** The category boundaries between color tags are drawn by *human viewers*, not by RGB codes. Different taggers carve up the spectrum differently, and any single color tag in this dataset covers a fairly wide perceptual band of that color. There is no clean RGB threshold I could have used to mechanically separate the categories, which is exactly why manual cleaning at the category level is intractable.
99
+ - **Adjacent / overlapping colors leak into each other in predictable patterns.** Some examples I have observed:
100
+ - `aqua_*` tags heavily pollute both **blue** and **green** based tags — aqua sits perceptually between them and gets sorted into all three buckets across the corpus.
101
+ - `yellow_*` tags overlap meaningfully with **red** and **orange** tags — warm-spectrum boundaries are inconsistent in the source data.
102
+ - Similar patterns exist for purple/blue/pink, brown/orange/red, and black/very-dark-anything.
103
+ - Color tags are also **high frequency**, so the noise is spread across millions of images rather than concentrated where it could be hand-fixed.
104
+ - When I sampled live in-the-wild images and compared the model's predictions to a careful human reading, the same source-data confusion patterns were still present in the predictions. The model is faithfully reproducing the source-data label distribution, which is itself noisy along the color axis.
105
+
106
+ ### Hair length
107
+
108
+ The hair length tags — `very_short_hair`, `short_hair`, `medium_hair`, `long_hair`, `very_long_hair` — all have major boundary issues. `long_hair` and `very_long_hair` are the worst offenders; the source labels routinely disagree with each other across visually similar images. The model inherits this confusion.
109
+
110
+ ### Other "objective size" body-part tags
111
+
112
+ The same problem applies to tags that sound objective but are really continuous and judgement-dependent: `flat_chest`, `small_breasts`, `medium_breasts`, `large_breasts`, `huge_breasts`. These are inherently noisy supervision targets for a classifier — adjacent buckets are not crisply separable in the source data, and the model cannot do better than the labels it was given.
113
+
114
+ ### Neckwear and small accessories (bows, bowties, ribbons, ascots, neckties)
115
+
116
+ This cluster of tags has systemic issues at the source. `bow`, `bowtie`, `ribbon`, `ascot`, and `necktie` are visually similar but distinct accessories, and the public source data routinely confuses them — the same physical object will be tagged differently across images, and adjacent categories leak into each other in both directions. The cleaning pass touched obvious mistakes here but did not normalize the category boundaries; the model learns the same fuzzy boundaries the source data has.
117
+
118
+ These five are the cluster I happened to look at closely. Many other small-accessory and clothing-detail tags show the same pattern — visually similar items, fuzzy source-data boundaries, residual confusion in the model. Treat any prediction in this category as a *suggestion* to inspect, not a final answer.
119
+
120
+ ### Character-vs-concept leakage
121
+
122
+ For some tags, the data is dominated by a small number of characters. When that happens, the model tends to learn **the character** rather than **the concept** the tag was meant to represent. Without a curated golden-standard set that deliberately decouples the concept from those characters, this is very hard to fix at training time.
123
+
124
+ ### My estimate of cleaning quality
125
+
126
+ The 300k removals and \~1M additions were **AI-assisted and then human-reviewed by me**. My honest estimate is that the corrections themselves are **<5% error**. That is a statement about the *changes I made*, not about the *underlying dataset* — the underlying dataset still contains the structured noise described above, because cleaning was driven by AI-flagged disagreements and the AI shares the same color/length/size confusion as the source data does.
127
+
128
+ ---
129
+
130
+ ## How to use this model responsibly
131
+
132
+ - **Human review every output.** This applies most strongly to color, hair length, and size-bucket tags. The model is a fast first pass, not an authoritative labeler.
133
+ - **Treat sibling tags as a group, not a hard pick.** If the model emits `blue_eyes` with high confidence, also check the `purple_eyes` / `aqua_eyes` / `black_eyes` scores before you commit.
134
+ - **Do not use the raw output as ground-truth for downstream training** without manual review. The very confusion patterns that this model can't resolve will get baked into your downstream model.
135
+ - **For thresholding, prefer per-tag thresholds over a single global threshold.** Different tag families have very different precision/recall behavior on this dataset.
136
+
137
+ ---
138
+
139
+ ## Performance notes
140
+
141
+ On my evaluation set this model achieves:
142
+
143
+ - The best **precision-equals-recall** point I have measured among comparable open anime taggers.
144
+ - A solid **mAP** relative to the same comparison set.
145
+
146
+ ### V1 headline numbers (e27/40, Phase 1, 320×320, 19,292 tags)
147
+
148
+ | Metric | Value |
149
+ |---|---|
150
+ | Macro F1 | 0.588 |
151
+ | Micro F1 | 0.659 |
152
+ | P=R threshold (macro / micro) | 0.614 / 0.670 |
153
+ | Overall val/mAP | 0.614 |
154
+
155
+ **mAP broken out by tag frequency bucket:**
156
+
157
+ | Frequency bucket | mAP |
158
+ |---|---|
159
+ | 500–999 (rare) | 0.589 |
160
+ | 1K–5K (mid) | 0.598 |
161
+ | 5K–10K (head) | 0.535 |
162
+ | 10K+ (very common) | 0.542 |
163
+
164
+ Note the inversion: rare/mid tags out-score head/very-common tags on mAP. This is consistent with the missing-tag bias described above — high-frequency concepts are the ones most often present-but-unlabeled in the source data, which depresses their measured precision against a noisy reference.
165
+
166
+ ### V1.1 headline numbers (e6/15, Phase 2, 448×448, 19,292 tags)
167
+
168
+ | Metric | Value |
169
+ |---|---|
170
+ | Overall val/mAP | 0.674 |
171
+
172
+ F1 / P=R numbers are intentionally not reported alongside this row — see the *Why F1 numbers are not reported for V1.1* paragraph below for the calibration reason.
173
+
174
+ **mAP broken out by tag frequency bucket — V1 vs. V1.1 on the same eval set:**
175
+
176
+ | Frequency bucket | V1 mAP | V1.1 mAP | Δ |
177
+ |---|---|---|---|
178
+ | 500–999 (rare) | 0.589 | 0.645 | +0.056 |
179
+ | 1K–5K (mid) | 0.598 | 0.656 | +0.058 |
180
+ | 5K–10K (head) | 0.535 | 0.595 | +0.060 |
181
+ | 10K+ (very common) | 0.542 | 0.606 | +0.064 |
182
+ | **Overall** | **0.614** | **0.674** | **+0.060** |
183
+
184
+ The same rare-vs-head inversion noted for V1 (rare/mid > head/very-common on mAP) is still present in V1.1, and for the same reason — high-frequency tags are the ones most often present-but-unlabeled in the source data, which depresses their measured precision against a noisy reference.
185
+
186
+ **Why V1.1 stopped at 6 of 15 planned epochs.** Per-epoch mAP growth decelerated from ~+0.7%/epoch in early Phase 2 to ~+0.3%/epoch by epoch 5, while validation loss continued to fall and per-tag calibration shifted (mean activations per image dropped from ~4500 at epoch 0 to ~4200 at epoch 5, but the auto-stop F1 metric is calibration-floored at a fixed threshold of 0.2653 and therefore unreliable as a stop signal — see [TRAINING_HEALTH_TRACKER.md](../TRAINING_HEALTH_TRACKER.md)). At that growth rate, the remaining 9 epochs would have been operating in the regime where it is no longer cleanly distinguishable whether mAP gains are *real ranking improvement* or *memorization of the labeled subset of a noisy multi-label corpus* (the missing-positive bias documented earlier in this card sets a soft ceiling somewhere in this neighbourhood). Continuing was unlikely to buy enough real gain to justify the extra training time, so V1.1 ships at the epoch-5 / step-81822 checkpoint.
187
+
188
+ **Why F1 numbers are not reported for V1.1.** V1.1's loss configuration (`gamma_neg=7.0`, `clip=0.2`) shifts the logit distribution relative to V1's (`gamma_neg=4.0`, `clip=0.05`). The in-training F1 metric uses a fixed threshold (0.2653) calibrated against V1's distribution, so V1.1's in-training F1 values are calibration-floored and not comparable to V1's reported F1. Reporting them alongside V1's would invite the wrong comparison. mAP, on the other hand, is threshold-independent and the V1 vs. V1.1 mAP comparison above is apples-to-apples — that is the comparison this card stands behind.
189
+
190
+ I want to be honest about *why* I think it performs well: **it is almost certainly not because of a special training regimen.** The training recipe is grounded in standard ViT-from-scratch literature (DeiT / DeiT III / FixRes / ASL / AugReg) without exotic tricks. The most likely explanation is simply that the **input dataset is cleaner** than what most comparable taggers were trained on. If you are trying to reproduce or beat this result, I would put your effort into data curation before you put it into training-recipe tuning.
191
+
192
+ ---
193
+
194
+ ## Image augmentation settings (V1 and V1.1)
195
+
196
+ For reproducibility, here are the exact augmentation pipelines used for each checkpoint. V1.1 is a fine-tune of V1, so its augmentation is a *reduced* version of V1's — narrower ranges and lower probabilities at the higher 448×448 resolution. The reductions follow EfficientNetV2 / FixRes guidance for progressive-resolution training, but only partially (\~¼ reduction rather than ½), because Phase 1 stopped at 33/40 epochs and the V1 base was under-converged when V1.1 began.
197
+
198
+ | Augmentation | V1 (320×320, from scratch, 40 epochs planned, 33 trained) | V1.1 (448×448, fine-tune of V1, 15 epochs planned, 6 trained) |
199
+ |---|---|---|
200
+ | Horizontal flip | p = 0.5 | p = 0.5 |
201
+ | Color jitter — brightness | 0.30 (p = 0.5) | 0.22 (p = 0.5) |
202
+ | Color jitter — contrast | 0.20 (p = 0.5) | 0.15 (p = 0.5) |
203
+ | Color jitter — saturation | 0.08 (p = 0.5) | 0.06 (p = 0.5) |
204
+ | Random rotation | p = 0.50, ±[2°, 8°], bicubic | p = 0.30, ±[2°, 5°], bicubic |
205
+ | Gaussian blur | p = 0.30, kernel = 3, σ ∈ [0.1, 1.5] | p = 0.15, kernel = 3, σ ∈ [0.1, 1.0] |
206
+ | Random erasing | disabled | disabled |
207
+ | Normalization (mean / std) | [0.5, 0.5, 0.5] / [0.5, 0.5, 0.5] | [0.5, 0.5, 0.5] / [0.5, 0.5, 0.5] |
208
+ | Letterbox pad color | [114, 114, 114] | [114, 114, 114] |
209
+
210
+ Notes on a few of these choices:
211
+
212
+ - **Saturation is held well below brightness/contrast** in both phases. Saturation is the only color-jitter axis that directly attacks color-named tag identity (`blue_eyes`, `pink_skin`, etc.); brightness and contrast are luminance-driven and largely chroma-safe. The ratio (\~¼ of brightness) is taken from BYOL's asymmetric augmentation.
213
+ - **Rotation is kept on at V1.1**, against the plain FixRes recommendation. The original plan was to disable it at 448 for spatial precision, but with V1 under-converged it was safer to keep a residual rotational-invariance signal. The compromise was a tighter angle band (±5° vs. ±8°) and a lower fire rate (0.30 vs. 0.50).
214
+ - **Gaussian blur is also kept on at V1.1** for the same reason (under-converged base + reduced color/rotation aug → strips too much input variability if blur is dropped entirely). Frequency was halved and the σ ceiling pulled in from 1.5 to 1.0.
215
+ - **No mixup, no cutmix, no RandAugment, no random erasing** in either phase. The recipe is intentionally close to DeiT III's "3-Augment" regime (flip + color jitter + blur) plus a small rotation, not a heavy AugReg/RandAugment stack.
216
+
217
+ ---
218
+
219
+ ## Limitations summary
220
+
221
+ | Area | Severity | Notes |
222
+ |---|---|---|
223
+ | Color tags (eye/hair/general) | **High** | Source-data noise survives; sibling colors leak into each other |
224
+ | Hair length (especially `long_hair`, `very_long_hair`) | **High** | Boundary tags inherently noisy in source |
225
+ | Size-bucket body-part tags | **High** | Continuous quantity discretized into noisy buckets |
226
+ | Neckwear (`bow`, `bowtie`, `ribbon`, `ascot`, `necktie`) | **High** | Visually similar accessories routinely confused at source; representative of a broader small-accessory pattern |
227
+ | Missing tags (concept present, no label) | **Dominant** | The single biggest source of noise in the corpus. Typical \~28 tags/image vs. 50+ that should be present. \~1M added back during cleaning; many millions remain. Hurts performance broadly and biases the model toward under-prediction. |
228
+ | Character-overwhelmed tags | **Medium** | Some tags are learned as proxies for specific characters |
229
+ | Rare / low-frequency tags | **Medium** | The +20k vocabulary expansion helps, but tail tags still see fewer examples |
230
+ | Anything not on the above list | Use with normal caution | The above are illustrative, not exhaustive — many tag families show similar source-data issues |
231
+
232
+ ---
233
+
234
+ ## What's next (V2)
235
+
236
+ Once a refreshed 2026-vintage source dataset becomes available, I plan to start work on V2. The biggest single change between V1 and V2 will not be the model — it will be **substantially more time spent on data cleaning before training begins**, with a particular focus on:
237
+
238
+ - Building a curated **golden-standard slice** for color tags, hair-length tags, and size-bucket tags so those categories can be supervised against deliberately disambiguated examples.
239
+ - Deeper character/concept decoupling so character-overwhelmed tags learn the actual concept.
240
+ - Better measurement of "true" performance on a hand-relabeled validation slice, so the headline metrics are not silently inflated by the same missing-positive bias that affects the training data.
241
+
242
+ V1 ships with the noise it ships with. V2 is where I plan to do something about it.
243
+
244
+ ---
245
+
246
+ ## Acknowledgments
247
+
248
+ - **SmilingWolf** for the ViT v3 tagger, which made the initial cleaning pass tractable. None of this would have been feasible without an existing strong tagger to use as a second opinion.
249
+ - The broader anime-tagger open-source community for the public tag corpora and prior model checkpoints I compared against.
250
+
251
+ ---
252
+
253
+ ## License / usage
254
+
255
+ Released under the **Apache License 2.0**. You may use, modify, and redistribute the model and accompanying files for personal, research, or commercial purposes, provided you retain the license notice and attribution.
256
+
257
+ **Intended use.** Research and downstream tooling for multi-label tagging of anime / illustration imagery.
258
+
259
+ **Out-of-scope use.** Decisions about real people; safety-critical pipelines that depend on label correctness without human review; training a downstream model on raw outputs without manual review (the missing-tag bias described above will propagate).
V1.1_onnx/config.json ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "format": "onnx",
3
+ "architecture_type": "vit",
4
+ "num_labels": 19294,
5
+ "num_channels": 3,
6
+ "image_size": 448,
7
+ "patch_size": 16,
8
+ "hidden_size": 1024,
9
+ "num_hidden_layers": 18,
10
+ "num_attention_heads": 16,
11
+ "intermediate_size": 4096,
12
+ "num_groups": 20,
13
+ "tags_per_group": 10000,
14
+ "training_epoch": 7,
15
+ "training_step": 85517,
16
+ "vocab_format_version": 1,
17
+ "vocab_sha256": "ad3c33d3b760bd0d15bd4631f441d47fcb136c7a6e53473b5588d760907b0316",
18
+ "onnx_opset_version": 20,
19
+ "onnx_inputs": [
20
+ "pixel_values",
21
+ "padding_mask"
22
+ ],
23
+ "onnx_outputs": [
24
+ "probabilities"
25
+ ],
26
+ "dynamic_batch": true,
27
+ "preprocessing_file": "preprocessing.json",
28
+ "thresholds_file": "pr_thresholds.json",
29
+ "vocabulary_file": "vocabulary.json",
30
+ "checkpoint_source": "experiments/run1_vit/checkpoints/last.pt (epoch 7, step 85517), exported to ONNX"
31
+ }
V1.1_onnx/model.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8567852deb135eccfe4b8445d48e4476ee8846436486679adc0642cfeda07d13
3
+ size 993246982
V1.1_onnx/pr_thresholds.json ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "checkpoint": "L:\\Dab\\OppaiOracle\\experiments\\run1_vit\\checkpoints\\last.pt",
3
+ "checkpoint_epoch": 7,
4
+ "checkpoint_step": 85517,
5
+ "val_samples": 30000,
6
+ "num_tags_evaluated": 19292,
7
+ "skip_indices": [
8
+ 0,
9
+ 1
10
+ ],
11
+ "sweep": {
12
+ "min": 0.001,
13
+ "max": 0.999,
14
+ "step": 0.001,
15
+ "count": 999
16
+ },
17
+ "micro": {
18
+ "pr_breakeven": {
19
+ "threshold": 0.7926946841478348,
20
+ "precision": 0.6989787817001343,
21
+ "recall": 0.6989787817001343,
22
+ "f1": 0.6989787816996342,
23
+ "interpolated": true
24
+ },
25
+ "f1_optimal": {
26
+ "threshold": 0.805,
27
+ "precision": 0.7304752469062805,
28
+ "recall": 0.6735844016075134,
29
+ "f1": 0.7008772492408752
30
+ }
31
+ },
32
+ "macro_single_threshold": {
33
+ "support_ge_0": {
34
+ "tags_evaluated": 19292,
35
+ "tags_total": 19292,
36
+ "pr_breakeven": {
37
+ "threshold": 0.7596096462607383,
38
+ "precision": 0.5969547033309937,
39
+ "recall": 0.5969547033309937,
40
+ "f1": 0.5969547033304936,
41
+ "interpolated": true
42
+ },
43
+ "f1_optimal": {
44
+ "threshold": 0.757,
45
+ "precision": 0.5935518145561218,
46
+ "recall": 0.6006690859794617,
47
+ "f1": 0.5715920925140381
48
+ }
49
+ },
50
+ "support_ge_1": {
51
+ "tags_evaluated": 18334,
52
+ "tags_total": 19292,
53
+ "pr_breakeven": {
54
+ "threshold": 0.7596096495985984,
55
+ "precision": 0.6281471848487854,
56
+ "recall": 0.6281471848487854,
57
+ "f1": 0.6281471848482854,
58
+ "interpolated": true
59
+ },
60
+ "f1_optimal": {
61
+ "threshold": 0.757,
62
+ "precision": 0.6245664358139038,
63
+ "recall": 0.6320556402206421,
64
+ "f1": 0.601459264755249
65
+ }
66
+ },
67
+ "support_ge_5": {
68
+ "tags_evaluated": 10406,
69
+ "tags_total": 19292,
70
+ "pr_breakeven": {
71
+ "threshold": 0.7532626820802688,
72
+ "precision": 0.5863859057426453,
73
+ "recall": 0.5863859057426453,
74
+ "f1": 0.5863859057421452,
75
+ "interpolated": true
76
+ },
77
+ "f1_optimal": {
78
+ "threshold": 0.754,
79
+ "precision": 0.5886526703834534,
80
+ "recall": 0.5845012068748474,
81
+ "f1": 0.5600905418395996
82
+ }
83
+ }
84
+ },
85
+ "per_tag": {
86
+ "min_support": 5,
87
+ "pr_summary": {
88
+ "tags_with_support": 10406,
89
+ "mean_threshold": 0.7503859471750784,
90
+ "median_threshold": 0.751,
91
+ "p25_threshold": 0.714,
92
+ "p75_threshold": 0.7883596608266235,
93
+ "mean_precision": 0.5908225646441903,
94
+ "mean_recall": 0.5908225646241425
95
+ },
96
+ "f1_summary": {
97
+ "mean_threshold": 0.7558264462809917,
98
+ "median_threshold": 0.759,
99
+ "mean_f1": 0.6410075075736091
100
+ }
101
+ }
102
+ }
V1.1_onnx/preprocessing.json ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "image_size": 448,
3
+ "patch_size": 16,
4
+ "num_channels": 3,
5
+ "color_order": "RGB",
6
+ "resize_mode": "letterbox",
7
+ "pad_color_rgb": [
8
+ 114,
9
+ 114,
10
+ 114
11
+ ],
12
+ "normalize_mean": [
13
+ 0.5,
14
+ 0.5,
15
+ 0.5
16
+ ],
17
+ "normalize_std": [
18
+ 0.5,
19
+ 0.5,
20
+ 0.5
21
+ ],
22
+ "input_dtype": "float32",
23
+ "input_layout": "BCHW",
24
+ "onnx_inputs": {
25
+ "pixel_values": {
26
+ "shape": "(batch_size, 3, 448, 448)",
27
+ "dtype": "float32",
28
+ "description": "Letterboxed and normalized image tensor. Preprocessing is NOT in the graph; do it externally."
29
+ },
30
+ "padding_mask": {
31
+ "shape": "(batch_size, 448, 448)",
32
+ "dtype": "bool",
33
+ "description": "True = padded pixel, False = valid pixel. Pass an all-False mask if your image fills the frame."
34
+ }
35
+ },
36
+ "onnx_outputs": {
37
+ "probabilities": {
38
+ "shape": "(batch_size, 19294)",
39
+ "dtype": "float32",
40
+ "activation": "sigmoid (already applied inside the graph)"
41
+ }
42
+ },
43
+ "opset_version": 20,
44
+ "dynamic_batch": true,
45
+ "embedded_metadata": {
46
+ "vocabulary": "Embedded as gzip+base64 in the ONNX metadata_props (key: vocab_b64_gzip).",
47
+ "tags_csv": "selected_tags.csv mirrors index_to_tag for SmilingWolf-style tagger UIs."
48
+ },
49
+ "notes": [
50
+ "Letterbox resize keeps aspect ratio; pad with the RGB color above to reach 448x448.",
51
+ "Normalize per-channel: (x/255 - mean) / std after letterboxing.",
52
+ "Recommended thresholds are in pr_thresholds.json (per-tag and global)."
53
+ ]
54
+ }
V1.1_onnx/selected_tags.csv ADDED
The diff for this file is too large to render. See raw diff
 
V1.1_onnx/vocabulary.json ADDED
The diff for this file is too large to render. See raw diff
 
V1.1_safetensors/README.md ADDED
@@ -0,0 +1,259 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ pipeline_tag: image-classification
4
+ language:
5
+ - en
6
+ tags:
7
+ - anime
8
+ - anime-tagger
9
+ - tagger
10
+ - image-tagging
11
+ - multi-label
12
+ - multi-label-classification
13
+ - vision-transformer
14
+ - vit
15
+ - illustration
16
+ - danbooru
17
+ - safetensors
18
+ - onnx
19
+ ---
20
+
21
+
22
+
23
+ ## TL;DR
24
+
25
+ A multi-label anime tagger trained from scratch on a \~5.9M image dataset that received a targeted cleaning and vocabulary-expansion pass before training. The corrections touched roughly **1.3M tags** — large in absolute terms, but only on the order of **\~3% of all tags** in the corpus, so this is best described as a *targeted* cleaning rather than a heavy one. The pass was deliberately weighted toward **low-frequency tags**, which is where mislabels and missing labels hurt a tagger the most. On my evaluation set the model achieves the best precision-equals-recall point and a good mAP relative to comparable open tagger checkpoints, but the underlying training data still contains category-level noise that no amount of training would have erased. **All predictions should be human-reviewed before they are trusted.**
26
+
27
+ Two checkpoints are released here. **V1** is the from-scratch 320×320 model. **V1.1** is a 448×448 fine-tune of V1 and on this evaluation set posts a modest mAP gain over V1 (overall val/mAP 0.674 vs. 0.614, ~+6 points absolute, ~+10% relative). The fine-tune helps across every frequency bucket but does not transform results — both checkpoints inherit the same source-data label noise. Pick the checkpoint whose native resolution matches the resolution you intend to feed it (see *Variants* below).
28
+
29
+ A live demo is available on the companion Space: [Grio43/OppaiOracle](https://huggingface.co/spaces/Grio43/OppaiOracle).
30
+
31
+ ---
32
+
33
+ ## Variants — which checkpoint should I use?
34
+
35
+ | Checkpoint | Native resolution | How it was produced | When to use |
36
+ |---|---|---|---|
37
+ | **V1** | 320×320 | Trained **from scratch** at 320×320. This is the model's native resolution. | The right pick if you are running inference at 320×320 or if throughput matters. |
38
+ | **V1.1** | 448×448 | A **fine-tune of V1** at 448×448. Position embeddings were interpolated from the 20×20 grid to 28×28, optimizer state was reset, and training continued at the new resolution following the FixRes / DeiT III progressive-resolution recipe. Trained for 6 of 15 planned epochs and stopped early — see *Performance notes / V1.1 headline numbers* below for the rationale. | Use when you specifically want 448×448 inference for finer spatial detail (small accessories, eye details). V1.1 outperforms V1 on every frequency bucket of this eval set (numbers in the *Performance notes* section), but the gain is modest — V1 remains a fully reasonable choice if you are running at 320×320. |
39
+
40
+ Two practical notes:
41
+
42
+ - **Match input resolution to the checkpoint.** Feeding 448×448 images to V1, or 320×320 images to V1.1, will give worse results than matching them. The position-embedding grid is fixed at load time.
43
+ - **V1 is not deprecated by V1.1.** They are siblings with different operating points, not generations of the same model. The V1.1 mAP gain over V1 is real but small (~+6 points overall) — pick on resolution, not on the assumption that V1.1 is strictly better.
44
+
45
+ ### Files in this repo
46
+
47
+ - `V1_safetensors/` — V1 in `safetensors` format with `config.json` and `preprocessing.json`. Use this for PyTorch / custom inference.
48
+ - `V1_onnx/` — V1 exported to ONNX. Use this for ONNX Runtime inference (CPU, DirectML, CUDA EP).
49
+ - `V1.1_safetensors/` — V1.1 in `safetensors` format with `config.json` and `preprocessing.json`.
50
+ - `V1.1_onnx/` — V1.1 exported to ONNX.
51
+ - Each variant directory ships `vocabulary.json`, `selected_tags.csv`, `pr_thresholds.json`, and a copy of this README.
52
+
53
+ ---
54
+
55
+ ## How this model came to be
56
+
57
+ I started with a corpus of roughly **5.9 million images** with publicly-sourced tags. Before training anything of my own, I used **SmilingWolf's ViT v3 tagger** to help clean the dataset. With that pipeline I:
58
+
59
+ - **Removed \~300k incorrect tags** from images where the public labels disagreed with the AI tagger and a human spot-check confirmed the public labels were wrong.
60
+ - **Added \~1,000,000 missing tags** in the same fashion — places where the AI tagger surfaced a label the public tag set had simply omitted, and human review agreed.
61
+
62
+ That is \~1.3M corrections in total, which is only on the order of **\~3% of the tags in the corpus**. This was a *targeted* pass, not a top-to-bottom relabel. Effort was deliberately concentrated on **low-frequency tags**, on the assumption that mislabels and missing labels do disproportionate damage in the long tail — a missing label on a tag with 800 positives in the entire dataset matters far more than a missing label on a tag with 800k positives.
63
+
64
+ I then trained a small "light" model on this cleaned dataset, primarily as a vehicle to **expand the tag vocabulary by \~20,000 additional low-frequency tags** that the original tag set under-represented. That expanded vocabulary is what the released model was trained against.
65
+
66
+ The released checkpoint is the main training run on the cleaned dataset with the expanded vocabulary.
67
+
68
+ ---
69
+
70
+ ## What "cleaned" actually means (and what it does not)
71
+
72
+ This is the most important section of this release. The cleaning was real work, but it was not omniscient, and the dataset still has structured, category-level label noise that you will see in the model's outputs. Most of these issues are inherited directly from the **publicly-sourced source datasets** — they are not new noise introduced during cleaning; they are pre-existing patterns that the cleaning pass touched but did not resolve at the category level.
73
+
74
+ The categories below are **illustrative, not exhaustive.** Many other tag families show similarly deep-rooted issues. Two failure modes show up across most of them, but they are not equal in size:
75
+
76
+ - **Missing tags (by far the dominant problem)** — concepts that are clearly present in an image but were never tagged at the source. This is the single biggest source of noise in the entire dataset. See the dedicated subsection below for the empirical scale.
77
+ - **Wrong tags (not uncommon, but secondary)** — visually similar concepts confused with each other in the source data (the bow / bowtie / ribbon / ascot / necktie cluster, color buckets, length and size buckets). These are real and plentiful, just not the dominant failure mode.
78
+
79
+ ### Missing tags (the dominant noise mode)
80
+
81
+ If you only remember one thing from this section, remember this: **the biggest single problem in the source data is not wrong tags, it is missing tags.** Wrong tags are not uncommon either, but they are dwarfed in volume by labels that should be present and simply aren't.
82
+
83
+ A rough empirical sense of the gap, from manual review:
84
+
85
+ - A typical image in this dataset arrives with roughly **\~28 tags** from the source.
86
+ - A reasonably-tagged image — judged by what is actually visible, sticking to common in-vocabulary concepts and not reaching for rare tags — should have **50+ tags**, often more.
87
+ - During spot-checks I have routinely taken images that arrived with **\~40 tags up past 60 tags** just by adding common, obviously-present concepts. That is without making any effort to surface rare tags; including those would push the number higher still.
88
+
89
+ So the source tag count is on the order of **half** of what a careful tagger would emit on the same image, and the gap is concentrated in concepts that are not subjective — they are simply omissions. The cleaning pass added \~1M missing tags back, but with the gap this large there are many millions still missing across the corpus.
90
+
91
+ The training-time consequence is that for every missing-but-present tag, the model receives **no positive gradient at all** for that concept on that image — only an implicit negative through the loss. This systematically biases the model toward under-predicting any tag with a high source-data omission rate, and the effect is uneven across tags: some tag families are well-tagged at the source and some are very sparsely tagged. Practically, this means **low predicted scores are less informative than they look** — a tag scoring below threshold may be genuinely absent, or it may be a concept the model has learned is "usually unlabeled even when present."
92
+
93
+ ### Color tags
94
+
95
+ Color-named tags (eye color, hair color, general color tags) are **poorly tagged at the source**, and the noise that survived cleaning is dataset-wide. Every color tag in the vocabulary has some version of this problem; some are worse than others.
96
+
97
+ - **Obvious failures were cleanable.** A bright, unambiguous yellow mislabeled as `blue_eyes` is exactly the kind of disagreement the AI-assisted pass catches, and those got fixed. The residual noise is not the obvious-failure kind.
98
+ - **The deep-rooted issue is perceptual, not technical.** The category boundaries between color tags are drawn by *human viewers*, not by RGB codes. Different taggers carve up the spectrum differently, and any single color tag in this dataset covers a fairly wide perceptual band of that color. There is no clean RGB threshold I could have used to mechanically separate the categories, which is exactly why manual cleaning at the category level is intractable.
99
+ - **Adjacent / overlapping colors leak into each other in predictable patterns.** Some examples I have observed:
100
+ - `aqua_*` tags heavily pollute both **blue** and **green** based tags — aqua sits perceptually between them and gets sorted into all three buckets across the corpus.
101
+ - `yellow_*` tags overlap meaningfully with **red** and **orange** tags — warm-spectrum boundaries are inconsistent in the source data.
102
+ - Similar patterns exist for purple/blue/pink, brown/orange/red, and black/very-dark-anything.
103
+ - Color tags are also **high frequency**, so the noise is spread across millions of images rather than concentrated where it could be hand-fixed.
104
+ - When I sampled live in-the-wild images and compared the model's predictions to a careful human reading, the same source-data confusion patterns were still present in the predictions. The model is faithfully reproducing the source-data label distribution, which is itself noisy along the color axis.
105
+
106
+ ### Hair length
107
+
108
+ The hair length tags — `very_short_hair`, `short_hair`, `medium_hair`, `long_hair`, `very_long_hair` — all have major boundary issues. `long_hair` and `very_long_hair` are the worst offenders; the source labels routinely disagree with each other across visually similar images. The model inherits this confusion.
109
+
110
+ ### Other "objective size" body-part tags
111
+
112
+ The same problem applies to tags that sound objective but are really continuous and judgement-dependent: `flat_chest`, `small_breasts`, `medium_breasts`, `large_breasts`, `huge_breasts`. These are inherently noisy supervision targets for a classifier — adjacent buckets are not crisply separable in the source data, and the model cannot do better than the labels it was given.
113
+
114
+ ### Neckwear and small accessories (bows, bowties, ribbons, ascots, neckties)
115
+
116
+ This cluster of tags has systemic issues at the source. `bow`, `bowtie`, `ribbon`, `ascot`, and `necktie` are visually similar but distinct accessories, and the public source data routinely confuses them — the same physical object will be tagged differently across images, and adjacent categories leak into each other in both directions. The cleaning pass touched obvious mistakes here but did not normalize the category boundaries; the model learns the same fuzzy boundaries the source data has.
117
+
118
+ These five are the cluster I happened to look at closely. Many other small-accessory and clothing-detail tags show the same pattern — visually similar items, fuzzy source-data boundaries, residual confusion in the model. Treat any prediction in this category as a *suggestion* to inspect, not a final answer.
119
+
120
+ ### Character-vs-concept leakage
121
+
122
+ For some tags, the data is dominated by a small number of characters. When that happens, the model tends to learn **the character** rather than **the concept** the tag was meant to represent. Without a curated golden-standard set that deliberately decouples the concept from those characters, this is very hard to fix at training time.
123
+
124
+ ### My estimate of cleaning quality
125
+
126
+ The 300k removals and \~1M additions were **AI-assisted and then human-reviewed by me**. My honest estimate is that the corrections themselves are **<5% error**. That is a statement about the *changes I made*, not about the *underlying dataset* — the underlying dataset still contains the structured noise described above, because cleaning was driven by AI-flagged disagreements and the AI shares the same color/length/size confusion as the source data does.
127
+
128
+ ---
129
+
130
+ ## How to use this model responsibly
131
+
132
+ - **Human review every output.** This applies most strongly to color, hair length, and size-bucket tags. The model is a fast first pass, not an authoritative labeler.
133
+ - **Treat sibling tags as a group, not a hard pick.** If the model emits `blue_eyes` with high confidence, also check the `purple_eyes` / `aqua_eyes` / `black_eyes` scores before you commit.
134
+ - **Do not use the raw output as ground-truth for downstream training** without manual review. The very confusion patterns that this model can't resolve will get baked into your downstream model.
135
+ - **For thresholding, prefer per-tag thresholds over a single global threshold.** Different tag families have very different precision/recall behavior on this dataset.
136
+
137
+ ---
138
+
139
+ ## Performance notes
140
+
141
+ On my evaluation set this model achieves:
142
+
143
+ - The best **precision-equals-recall** point I have measured among comparable open anime taggers.
144
+ - A solid **mAP** relative to the same comparison set.
145
+
146
+ ### V1 headline numbers (e27/40, Phase 1, 320×320, 19,292 tags)
147
+
148
+ | Metric | Value |
149
+ |---|---|
150
+ | Macro F1 | 0.588 |
151
+ | Micro F1 | 0.659 |
152
+ | P=R threshold (macro / micro) | 0.614 / 0.670 |
153
+ | Overall val/mAP | 0.614 |
154
+
155
+ **mAP broken out by tag frequency bucket:**
156
+
157
+ | Frequency bucket | mAP |
158
+ |---|---|
159
+ | 500–999 (rare) | 0.589 |
160
+ | 1K–5K (mid) | 0.598 |
161
+ | 5K–10K (head) | 0.535 |
162
+ | 10K+ (very common) | 0.542 |
163
+
164
+ Note the inversion: rare/mid tags out-score head/very-common tags on mAP. This is consistent with the missing-tag bias described above — high-frequency concepts are the ones most often present-but-unlabeled in the source data, which depresses their measured precision against a noisy reference.
165
+
166
+ ### V1.1 headline numbers (e6/15, Phase 2, 448×448, 19,292 tags)
167
+
168
+ | Metric | Value |
169
+ |---|---|
170
+ | Overall val/mAP | 0.674 |
171
+
172
+ F1 / P=R numbers are intentionally not reported alongside this row — see the *Why F1 numbers are not reported for V1.1* paragraph below for the calibration reason.
173
+
174
+ **mAP broken out by tag frequency bucket — V1 vs. V1.1 on the same eval set:**
175
+
176
+ | Frequency bucket | V1 mAP | V1.1 mAP | Δ |
177
+ |---|---|---|---|
178
+ | 500–999 (rare) | 0.589 | 0.645 | +0.056 |
179
+ | 1K–5K (mid) | 0.598 | 0.656 | +0.058 |
180
+ | 5K–10K (head) | 0.535 | 0.595 | +0.060 |
181
+ | 10K+ (very common) | 0.542 | 0.606 | +0.064 |
182
+ | **Overall** | **0.614** | **0.674** | **+0.060** |
183
+
184
+ The same rare-vs-head inversion noted for V1 (rare/mid > head/very-common on mAP) is still present in V1.1, and for the same reason — high-frequency tags are the ones most often present-but-unlabeled in the source data, which depresses their measured precision against a noisy reference.
185
+
186
+ **Why V1.1 stopped at 6 of 15 planned epochs.** Per-epoch mAP growth decelerated from ~+0.7%/epoch in early Phase 2 to ~+0.3%/epoch by epoch 5, while validation loss continued to fall and per-tag calibration shifted (mean activations per image dropped from ~4500 at epoch 0 to ~4200 at epoch 5, but the auto-stop F1 metric is calibration-floored at a fixed threshold of 0.2653 and therefore unreliable as a stop signal — see [TRAINING_HEALTH_TRACKER.md](../TRAINING_HEALTH_TRACKER.md)). At that growth rate, the remaining 9 epochs would have been operating in the regime where it is no longer cleanly distinguishable whether mAP gains are *real ranking improvement* or *memorization of the labeled subset of a noisy multi-label corpus* (the missing-positive bias documented earlier in this card sets a soft ceiling somewhere in this neighbourhood). Continuing was unlikely to buy enough real gain to justify the extra training time, so V1.1 ships at the epoch-5 / step-81822 checkpoint.
187
+
188
+ **Why F1 numbers are not reported for V1.1.** V1.1's loss configuration (`gamma_neg=7.0`, `clip=0.2`) shifts the logit distribution relative to V1's (`gamma_neg=4.0`, `clip=0.05`). The in-training F1 metric uses a fixed threshold (0.2653) calibrated against V1's distribution, so V1.1's in-training F1 values are calibration-floored and not comparable to V1's reported F1. Reporting them alongside V1's would invite the wrong comparison. mAP, on the other hand, is threshold-independent and the V1 vs. V1.1 mAP comparison above is apples-to-apples — that is the comparison this card stands behind.
189
+
190
+ I want to be honest about *why* I think it performs well: **it is almost certainly not because of a special training regimen.** The training recipe is grounded in standard ViT-from-scratch literature (DeiT / DeiT III / FixRes / ASL / AugReg) without exotic tricks. The most likely explanation is simply that the **input dataset is cleaner** than what most comparable taggers were trained on. If you are trying to reproduce or beat this result, I would put your effort into data curation before you put it into training-recipe tuning.
191
+
192
+ ---
193
+
194
+ ## Image augmentation settings (V1 and V1.1)
195
+
196
+ For reproducibility, here are the exact augmentation pipelines used for each checkpoint. V1.1 is a fine-tune of V1, so its augmentation is a *reduced* version of V1's — narrower ranges and lower probabilities at the higher 448×448 resolution. The reductions follow EfficientNetV2 / FixRes guidance for progressive-resolution training, but only partially (\~¼ reduction rather than ½), because Phase 1 stopped at 33/40 epochs and the V1 base was under-converged when V1.1 began.
197
+
198
+ | Augmentation | V1 (320×320, from scratch, 40 epochs planned, 33 trained) | V1.1 (448×448, fine-tune of V1, 15 epochs planned, 6 trained) |
199
+ |---|---|---|
200
+ | Horizontal flip | p = 0.5 | p = 0.5 |
201
+ | Color jitter — brightness | 0.30 (p = 0.5) | 0.22 (p = 0.5) |
202
+ | Color jitter — contrast | 0.20 (p = 0.5) | 0.15 (p = 0.5) |
203
+ | Color jitter — saturation | 0.08 (p = 0.5) | 0.06 (p = 0.5) |
204
+ | Random rotation | p = 0.50, ±[2°, 8°], bicubic | p = 0.30, ±[2°, 5°], bicubic |
205
+ | Gaussian blur | p = 0.30, kernel = 3, σ ∈ [0.1, 1.5] | p = 0.15, kernel = 3, σ ∈ [0.1, 1.0] |
206
+ | Random erasing | disabled | disabled |
207
+ | Normalization (mean / std) | [0.5, 0.5, 0.5] / [0.5, 0.5, 0.5] | [0.5, 0.5, 0.5] / [0.5, 0.5, 0.5] |
208
+ | Letterbox pad color | [114, 114, 114] | [114, 114, 114] |
209
+
210
+ Notes on a few of these choices:
211
+
212
+ - **Saturation is held well below brightness/contrast** in both phases. Saturation is the only color-jitter axis that directly attacks color-named tag identity (`blue_eyes`, `pink_skin`, etc.); brightness and contrast are luminance-driven and largely chroma-safe. The ratio (\~¼ of brightness) is taken from BYOL's asymmetric augmentation.
213
+ - **Rotation is kept on at V1.1**, against the plain FixRes recommendation. The original plan was to disable it at 448 for spatial precision, but with V1 under-converged it was safer to keep a residual rotational-invariance signal. The compromise was a tighter angle band (±5° vs. ±8°) and a lower fire rate (0.30 vs. 0.50).
214
+ - **Gaussian blur is also kept on at V1.1** for the same reason (under-converged base + reduced color/rotation aug → strips too much input variability if blur is dropped entirely). Frequency was halved and the σ ceiling pulled in from 1.5 to 1.0.
215
+ - **No mixup, no cutmix, no RandAugment, no random erasing** in either phase. The recipe is intentionally close to DeiT III's "3-Augment" regime (flip + color jitter + blur) plus a small rotation, not a heavy AugReg/RandAugment stack.
216
+
217
+ ---
218
+
219
+ ## Limitations summary
220
+
221
+ | Area | Severity | Notes |
222
+ |---|---|---|
223
+ | Color tags (eye/hair/general) | **High** | Source-data noise survives; sibling colors leak into each other |
224
+ | Hair length (especially `long_hair`, `very_long_hair`) | **High** | Boundary tags inherently noisy in source |
225
+ | Size-bucket body-part tags | **High** | Continuous quantity discretized into noisy buckets |
226
+ | Neckwear (`bow`, `bowtie`, `ribbon`, `ascot`, `necktie`) | **High** | Visually similar accessories routinely confused at source; representative of a broader small-accessory pattern |
227
+ | Missing tags (concept present, no label) | **Dominant** | The single biggest source of noise in the corpus. Typical \~28 tags/image vs. 50+ that should be present. \~1M added back during cleaning; many millions remain. Hurts performance broadly and biases the model toward under-prediction. |
228
+ | Character-overwhelmed tags | **Medium** | Some tags are learned as proxies for specific characters |
229
+ | Rare / low-frequency tags | **Medium** | The +20k vocabulary expansion helps, but tail tags still see fewer examples |
230
+ | Anything not on the above list | Use with normal caution | The above are illustrative, not exhaustive — many tag families show similar source-data issues |
231
+
232
+ ---
233
+
234
+ ## What's next (V2)
235
+
236
+ Once a refreshed 2026-vintage source dataset becomes available, I plan to start work on V2. The biggest single change between V1 and V2 will not be the model — it will be **substantially more time spent on data cleaning before training begins**, with a particular focus on:
237
+
238
+ - Building a curated **golden-standard slice** for color tags, hair-length tags, and size-bucket tags so those categories can be supervised against deliberately disambiguated examples.
239
+ - Deeper character/concept decoupling so character-overwhelmed tags learn the actual concept.
240
+ - Better measurement of "true" performance on a hand-relabeled validation slice, so the headline metrics are not silently inflated by the same missing-positive bias that affects the training data.
241
+
242
+ V1 ships with the noise it ships with. V2 is where I plan to do something about it.
243
+
244
+ ---
245
+
246
+ ## Acknowledgments
247
+
248
+ - **SmilingWolf** for the ViT v3 tagger, which made the initial cleaning pass tractable. None of this would have been feasible without an existing strong tagger to use as a second opinion.
249
+ - The broader anime-tagger open-source community for the public tag corpora and prior model checkpoints I compared against.
250
+
251
+ ---
252
+
253
+ ## License / usage
254
+
255
+ Released under the **Apache License 2.0**. You may use, modify, and redistribute the model and accompanying files for personal, research, or commercial purposes, provided you retain the license notice and attribution.
256
+
257
+ **Intended use.** Research and downstream tooling for multi-label tagging of anime / illustration imagery.
258
+
259
+ **Out-of-scope use.** Decisions about real people; safety-critical pipelines that depend on label correctness without human review; training a downstream model on raw outputs without manual review (the missing-tag bias described above will propagate).
V1.1_safetensors/config.json ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architecture_type": "vit",
3
+ "num_labels": 19294,
4
+ "num_channels": 3,
5
+ "image_size": 448,
6
+ "patch_size": 16,
7
+ "hidden_size": 1024,
8
+ "num_hidden_layers": 18,
9
+ "num_attention_heads": 16,
10
+ "intermediate_size": 4096,
11
+ "hidden_dropout_prob": 0.1,
12
+ "pos_dropout": 0.0,
13
+ "attention_dropout": 0.05,
14
+ "drop_path_rate": 0.2,
15
+ "initializer_range": 0.02,
16
+ "layer_norm_eps": 1e-06,
17
+ "use_fp32_layernorm": false,
18
+ "attention_bias": true,
19
+ "num_groups": 20,
20
+ "tags_per_group": 10000,
21
+ "training_epoch": 7,
22
+ "training_step": 85517,
23
+ "vocab_format_version": 1,
24
+ "vocab_sha256": "ad3c33d3b760bd0d15bd4631f441d47fcb136c7a6e53473b5588d760907b0316",
25
+ "state_dict_keys_format": "plain (no _orig_mod./module. prefixes)",
26
+ "state_dict_dtype": "bfloat16",
27
+ "checkpoint_source": "experiments/run1_vit/checkpoints/last.pt (epoch 7, step 85517)"
28
+ }
V1.1_safetensors/model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ced687b2e866997c572987371d9733d9f0d7b7e1e5771d23e692e74788bf4226
3
+ size 496226548
V1.1_safetensors/pr_thresholds.json ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "checkpoint": "L:\\Dab\\OppaiOracle\\experiments\\run1_vit\\checkpoints\\last.pt",
3
+ "checkpoint_epoch": 7,
4
+ "checkpoint_step": 85517,
5
+ "val_samples": 30000,
6
+ "num_tags_evaluated": 19292,
7
+ "skip_indices": [
8
+ 0,
9
+ 1
10
+ ],
11
+ "sweep": {
12
+ "min": 0.001,
13
+ "max": 0.999,
14
+ "step": 0.001,
15
+ "count": 999
16
+ },
17
+ "micro": {
18
+ "pr_breakeven": {
19
+ "threshold": 0.7926946841478348,
20
+ "precision": 0.6989787817001343,
21
+ "recall": 0.6989787817001343,
22
+ "f1": 0.6989787816996342,
23
+ "interpolated": true
24
+ },
25
+ "f1_optimal": {
26
+ "threshold": 0.805,
27
+ "precision": 0.7304752469062805,
28
+ "recall": 0.6735844016075134,
29
+ "f1": 0.7008772492408752
30
+ }
31
+ },
32
+ "macro_single_threshold": {
33
+ "support_ge_0": {
34
+ "tags_evaluated": 19292,
35
+ "tags_total": 19292,
36
+ "pr_breakeven": {
37
+ "threshold": 0.7596096462607383,
38
+ "precision": 0.5969547033309937,
39
+ "recall": 0.5969547033309937,
40
+ "f1": 0.5969547033304936,
41
+ "interpolated": true
42
+ },
43
+ "f1_optimal": {
44
+ "threshold": 0.757,
45
+ "precision": 0.5935518145561218,
46
+ "recall": 0.6006690859794617,
47
+ "f1": 0.5715920925140381
48
+ }
49
+ },
50
+ "support_ge_1": {
51
+ "tags_evaluated": 18334,
52
+ "tags_total": 19292,
53
+ "pr_breakeven": {
54
+ "threshold": 0.7596096495985984,
55
+ "precision": 0.6281471848487854,
56
+ "recall": 0.6281471848487854,
57
+ "f1": 0.6281471848482854,
58
+ "interpolated": true
59
+ },
60
+ "f1_optimal": {
61
+ "threshold": 0.757,
62
+ "precision": 0.6245664358139038,
63
+ "recall": 0.6320556402206421,
64
+ "f1": 0.601459264755249
65
+ }
66
+ },
67
+ "support_ge_5": {
68
+ "tags_evaluated": 10406,
69
+ "tags_total": 19292,
70
+ "pr_breakeven": {
71
+ "threshold": 0.7532626820802688,
72
+ "precision": 0.5863859057426453,
73
+ "recall": 0.5863859057426453,
74
+ "f1": 0.5863859057421452,
75
+ "interpolated": true
76
+ },
77
+ "f1_optimal": {
78
+ "threshold": 0.754,
79
+ "precision": 0.5886526703834534,
80
+ "recall": 0.5845012068748474,
81
+ "f1": 0.5600905418395996
82
+ }
83
+ }
84
+ },
85
+ "per_tag": {
86
+ "min_support": 5,
87
+ "pr_summary": {
88
+ "tags_with_support": 10406,
89
+ "mean_threshold": 0.7503859471750784,
90
+ "median_threshold": 0.751,
91
+ "p25_threshold": 0.714,
92
+ "p75_threshold": 0.7883596608266235,
93
+ "mean_precision": 0.5908225646441903,
94
+ "mean_recall": 0.5908225646241425
95
+ },
96
+ "f1_summary": {
97
+ "mean_threshold": 0.7558264462809917,
98
+ "median_threshold": 0.759,
99
+ "mean_f1": 0.6410075075736091
100
+ }
101
+ }
102
+ }
V1.1_safetensors/preprocessing.json ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "image_size": 448,
3
+ "patch_size": 16,
4
+ "num_channels": 3,
5
+ "color_order": "RGB",
6
+ "resize_mode": "letterbox",
7
+ "pad_color_rgb": [
8
+ 114,
9
+ 114,
10
+ 114
11
+ ],
12
+ "normalize_mean": [
13
+ 0.5,
14
+ 0.5,
15
+ 0.5
16
+ ],
17
+ "normalize_std": [
18
+ 0.5,
19
+ 0.5,
20
+ 0.5
21
+ ],
22
+ "input_dtype": "float32",
23
+ "input_layout": "BCHW",
24
+ "padding_mask": {
25
+ "required_for_pytorch_forward": true,
26
+ "shape": "(B, H, W)",
27
+ "dtype": "bool",
28
+ "convention": "True = padded pixel, False = valid pixel",
29
+ "all_false_equivalent_to": "no masking"
30
+ },
31
+ "output": {
32
+ "name": "tag_logits",
33
+ "shape": "(B, 19294)",
34
+ "activation": "apply sigmoid for probabilities"
35
+ },
36
+ "notes": [
37
+ "Letterbox resize keeps aspect ratio; pad with the RGB color above to reach 448x448.",
38
+ "Normalize per-channel: (x/255 - mean) / std after letterboxing.",
39
+ "Built-in recommended thresholds are in pr_thresholds.json (per-tag and global)."
40
+ ]
41
+ }
V1.1_safetensors/selected_tags.csv ADDED
The diff for this file is too large to render. See raw diff
 
V1.1_safetensors/vocabulary.json ADDED
The diff for this file is too large to render. See raw diff
 
config.json CHANGED
@@ -1,9 +1,9 @@
1
  {
2
  "model_name": "OppaiOracle",
3
- "version": "V1",
 
4
  "architecture_type": "vit",
5
  "num_labels": 19294,
6
- "image_size": 320,
7
  "patch_size": 16,
8
  "hidden_size": 1024,
9
  "num_hidden_layers": 18,
@@ -12,16 +12,34 @@
12
  "variants": {
13
  "V1_safetensors": {
14
  "format": "safetensors",
 
15
  "config": "V1_safetensors/config.json",
16
  "weights": "V1_safetensors/model.safetensors"
17
  },
18
  "V1_onnx": {
19
  "format": "onnx",
 
20
  "config": "V1_onnx/config.json",
21
  "weights": "V1_onnx/model.onnx"
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  }
23
  },
24
  "vocab_format_version": 1,
25
- "vocab_sha256": "b9f95e88fb7e30669077bb761e9a66642ec526c1e10d65336a2a2b628141199d",
26
- "checkpoint_source": "experiments/run1_vit/checkpoints/last.pt (epoch 33)"
 
 
 
27
  }
 
1
  {
2
  "model_name": "OppaiOracle",
3
+ "version": "V1.1",
4
+ "released_versions": ["V1", "V1.1"],
5
  "architecture_type": "vit",
6
  "num_labels": 19294,
 
7
  "patch_size": 16,
8
  "hidden_size": 1024,
9
  "num_hidden_layers": 18,
 
12
  "variants": {
13
  "V1_safetensors": {
14
  "format": "safetensors",
15
+ "image_size": 320,
16
  "config": "V1_safetensors/config.json",
17
  "weights": "V1_safetensors/model.safetensors"
18
  },
19
  "V1_onnx": {
20
  "format": "onnx",
21
+ "image_size": 320,
22
  "config": "V1_onnx/config.json",
23
  "weights": "V1_onnx/model.onnx"
24
+ },
25
+ "V1.1_safetensors": {
26
+ "format": "safetensors",
27
+ "image_size": 448,
28
+ "dtype": "bfloat16",
29
+ "config": "V1.1_safetensors/config.json",
30
+ "weights": "V1.1_safetensors/model.safetensors"
31
+ },
32
+ "V1.1_onnx": {
33
+ "format": "onnx",
34
+ "image_size": 448,
35
+ "config": "V1.1_onnx/config.json",
36
+ "weights": "V1.1_onnx/model.onnx"
37
  }
38
  },
39
  "vocab_format_version": 1,
40
+ "vocab_sha256": "ad3c33d3b760bd0d15bd4631f441d47fcb136c7a6e53473b5588d760907b0316",
41
+ "checkpoint_sources": {
42
+ "V1": "experiments/run1_vit/checkpoints/last.pt (epoch 33)",
43
+ "V1.1": "experiments/run1_vit/checkpoints/last.pt (epoch 7, step 85517)"
44
+ }
45
  }