ij commited on
Commit
aa3d7f9
·
verified ·
1 Parent(s): 8e11a25

Release Anima Style Embedding v1.0

Browse files
.gitattributes CHANGED
@@ -33,3 +33,7 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ assets/generalization_and_gallery_size.png filter=lfs diff=lfs merge=lfs -text
37
+ assets/learned_vs_frozen_baseline.png filter=lfs diff=lfs merge=lfs -text
38
+ assets/reference_count_curve.png filter=lfs diff=lfs merge=lfs -text
39
+ assets/training_validation_curves.png filter=lfs diff=lfs merge=lfs -text
README.md ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ library_name: pytorch
3
+ pipeline_tag: feature-extraction
4
+ tags:
5
+ - anime
6
+ - style-embedding
7
+ - image-retrieval
8
+ - reference-image
9
+ - siglip2
10
+ - anima
11
+ - pytorch
12
+ ---
13
+
14
+ # Anima Style Embedding v1.0
15
+
16
+ **A multi-reference style encoder for person-centric anime and illustration images.**
17
+
18
+ Anima Style Embedding converts one to eight reference images into a normalized 512-dimensional style vector. It combines multi-level SigLIP2 features from the full image and face with internal Anima features, then grounds the result across the complete reference set. The embedding is designed for open-set style retrieval and reference-driven style transfer systems rather than a fixed bank of known artists.
19
+
20
+ | Model size | References | Embedding | Modalities |
21
+ |---:|---:|---:|---|
22
+ | 17.49M parameters | 1–8 images | 512-D, L2-normalized | Full image + face + Anima internals |
23
+
24
+ ![Learned encoder versus frozen backbone](assets/learned_vs_frozen_baseline.png)
25
+
26
+ ## Highlights
27
+
28
+ - **Open-set style representation:** unseen artists can be embedded directly from reference images.
29
+ - **Native multi-reference grounding:** Reference Consensus Re-reading lets each image be interpreted in the context of the complete 1–8 image set.
30
+ - **Full-image and face awareness:** the encoder combines global composition and rendering cues with face-specific style information.
31
+ - **Anima-aware features:** three internal Anima blocks complement SigLIP2 visual features with representations aligned to the target generator.
32
+ - **Strong retrieval gains:** unseen synthetic-style MRR improves from 32.0% with the frozen SigLIP2 Full+Face baseline to 60.8% with the learned encoder on the 4,500-way validation gallery.
33
+
34
+ ## Performance
35
+
36
+ Retrieval uses cosine similarity between normalized query embeddings and five-image style prototypes.
37
+
38
+ ### 4,500-way validation — unseen identities
39
+
40
+ The unseen subset contains 500 identities retrieved against a gallery of 4,500 styles.
41
+
42
+ | Source | Top-1 | Top-5 | MRR |
43
+ |---|---:|---:|---:|
44
+ | Synthetic | 51.8% | 71.7% | 60.8% |
45
+ | Human | 56.4% | 75.3% | 65.0% |
46
+
47
+ ### 500-way sealed test — unseen identities
48
+
49
+ | Source | Top-1 | Top-5 | MRR |
50
+ |---|---:|---:|---:|
51
+ | Synthetic | 73.8% | 90.3% | 81.1% |
52
+ | Human | 76.1% | 92.0% | 83.0% |
53
+
54
+ The sealed test uses a smaller gallery than validation, so its absolute scores should be read independently.
55
+
56
+ ![Generalization and gallery-size sensitivity](assets/generalization_and_gallery_size.png)
57
+
58
+ ### Reference count
59
+
60
+ More references consistently improve human-style grounding. Synthetic K=5 uses the locked controlled/matched/cross-content protocol and is shown separately from the generic K diagnostics.
61
+
62
+ ![Reference count evaluation](assets/reference_count_curve.png)
63
+
64
+ ## Architecture
65
+
66
+ The encoder projects full-image, face, and Anima tokens into a shared 512-wide space and reads them with four eight-head mixer blocks. Functional Style Factorization introduces four auxiliary style queries during training. Reference Consensus Re-reading computes a consensus across the reference set, re-reads every image under that context, and forms an agreement-weighted prototype.
67
+
68
+ | Input | Shape per batch |
69
+ |---|---|
70
+ | Full-image SigLIP2 features | `[B, R, 30, 1152]` |
71
+ | Face SigLIP2 features | `[B, R, 30, 1152]` |
72
+ | Face validity mask | `[B, R]` |
73
+ | Anima internal features | `[B, R, 3, 4096]` |
74
+ | Reference mask | `[B, R]` |
75
+
76
+ SigLIP2 features use [`timm/vit_so400m_patch16_siglip_gap_512.v2_webli`](https://huggingface.co/timm/vit_so400m_patch16_siglip_gap_512.v2_webli) at 512×512 and three backbone depths. Anima features use 768×768 inputs and blocks 8, 18, and 26 at sigma 0.1.
77
+
78
+ ## Quick start
79
+
80
+ ```python
81
+ import json
82
+
83
+ import torch
84
+ from huggingface_hub import hf_hub_download
85
+ from safetensors.torch import load_file
86
+
87
+ from modeling_anima_style_embedding import UnifiedStyleEncoder
88
+
89
+ repo_id = "Baragi-AI/Anima-Style-Embedding"
90
+ config = json.load(open(hf_hub_download(repo_id, "config.json"), encoding="utf-8"))
91
+ cfg = config["architecture"]
92
+
93
+ encoder = UnifiedStyleEncoder(
94
+ width=cfg["width"],
95
+ blocks=cfg["blocks"],
96
+ heads=cfg["heads"],
97
+ embedding_dim=cfg["embedding_dim"],
98
+ dropout=cfg["dropout"],
99
+ use_anima=True,
100
+ reference_grounding=cfg["reference_grounding"],
101
+ functional_factors=cfg["functional_factors"],
102
+ )
103
+ encoder.load_state_dict(
104
+ load_file(hf_hub_download(repo_id, "model.safetensors")),
105
+ strict=True,
106
+ )
107
+ encoder.eval()
108
+ ```
109
+
110
+ ```python
111
+ with torch.inference_mode():
112
+ style_embedding, per_image_embeddings = encoder(
113
+ full_features,
114
+ reference_mask,
115
+ face_features=face_features,
116
+ face_mask=face_mask,
117
+ anima_features=anima_features,
118
+ )
119
+
120
+ assert style_embedding.shape == (full_features.shape[0], 512)
121
+ ```
122
+
123
+ `modeling_anima_style_embedding.py` contains the matching encoder definition. The checkpoint expects precomputed SigLIP2 and Anima features; RGB and Anima feature extraction are supplied by downstream integrations.
124
+
125
+ ## Training
126
+
127
+ The model was trained on 320,000 person-centric style records: 160,000 Anima-generated images and 160,000 human-created illustrations across 8,000 training identities. Synthetic and human examples are mixed within each batch. Training uses four RTX 5090 GPUs, BF16 DistributedDataParallel, 16-way episodes, two queries per prototype, variable 1–8 image support, global negatives, and weak hard-negative sampling. The 4,500-step checkpoint produced the best full-validation score.
128
+
129
+ ![Training dynamics](assets/training_validation_curves.png)
130
+
131
+ The training record is available in [Weights & Biases](https://wandb.ai/1wndrla17-kyung-hee-university/anima-style-embedding/runs/5c9ae843a14f46529fe9aaa604a78d3b). Machine-readable evaluation results are included under `metrics/`.
132
+
133
+ ## Applications
134
+
135
+ - reference-driven style transfer for Anima;
136
+ - artist-style retrieval and clustering;
137
+ - aggregation of multiple references into a single style prototype;
138
+ - open-set style recognition for previously unseen artists;
139
+ - similarity scoring and reference-set curation.
140
+
141
+ ## Files
142
+
143
+ | File | Contents |
144
+ |---|---|
145
+ | `model.safetensors` | Encoder weights |
146
+ | `config.json` | Architecture and feature contract |
147
+ | `modeling_anima_style_embedding.py` | PyTorch model definition |
148
+ | `metrics/` | Training curves and retrieval results |
149
+ | `SHA256SUMS.json` | Release checksums |
150
+
151
+ ## Limitations
152
+
153
+ - The model is optimized for person-centric anime and illustration images; other domains are not evaluated.
154
+ - Retrieval metrics measure representation quality, not generated-image fidelity.
155
+ - Style and artist-associated content preferences are not completely disentangled.
156
+ - Anima features must follow the documented model, block, resolution, and sigma configuration.
157
+
158
+ ## License
159
+
160
+ No model license has been selected for v1.0. The training images are not distributed with the checkpoint.
161
+
162
+ ## Citation
163
+
164
+ ```bibtex
165
+ @misc{baragi2026animastyleembedding,
166
+ title = {Anima Style Embedding v1.0},
167
+ author = {{Baragi AI}},
168
+ year = {2026},
169
+ howpublished = {Hugging Face model repository},
170
+ url = {https://huggingface.co/Baragi-AI/Anima-Style-Embedding}
171
+ }
172
+ ```
SHA256SUMS.json ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ {
2
+ "model.safetensors": "6cdf126152927f6e31dc856a8d10b8decee3bb20ce4c0ca449206db65d4633ec",
3
+ "config.json": "7323cbf6061896453a88cd0f6302831b96278a52eb8b0b3c1500d84552a1e68f"
4
+ }
assets/generalization_and_gallery_size.png ADDED

Git LFS Details

  • SHA256: 5f9f0fe1210759a3d9a0c17fff7e09508968529204a1de91af535f0939ec7d10
  • Pointer size: 131 Bytes
  • Size of remote file: 117 kB
assets/learned_vs_frozen_baseline.png ADDED

Git LFS Details

  • SHA256: 621f695273313a479e14c940cff58b538e663f1b21e055453c8e927cd184c998
  • Pointer size: 131 Bytes
  • Size of remote file: 114 kB
assets/reference_count_curve.png ADDED

Git LFS Details

  • SHA256: 7eb1e311161a80ec1ad05ab8ef0b6ce1ce8e41f25ce049901db0dbc880f62ee0
  • Pointer size: 131 Bytes
  • Size of remote file: 139 kB
assets/training_validation_curves.png ADDED

Git LFS Details

  • SHA256: aa83cbdbf9327ed5693db371fdf91ce97cd6a7d0faed1b166f977da8868e29a1
  • Pointer size: 131 Bytes
  • Size of remote file: 132 kB
config.json ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model_type": "anima_style_embedding",
3
+ "version": "1.0",
4
+ "architecture": {
5
+ "width": 512,
6
+ "blocks": 4,
7
+ "heads": 8,
8
+ "embedding_dim": 512,
9
+ "dropout": 0.1,
10
+ "reference_grounding": true,
11
+ "functional_factors": true,
12
+ "reference_count": [
13
+ 1,
14
+ 8
15
+ ],
16
+ "trainable_parameters": 17488353
17
+ },
18
+ "inputs": {
19
+ "siglip2_full": {
20
+ "shape": [
21
+ 30,
22
+ 1152
23
+ ],
24
+ "dtype": "bfloat16"
25
+ },
26
+ "siglip2_face": {
27
+ "shape": [
28
+ 30,
29
+ 1152
30
+ ],
31
+ "dtype": "bfloat16",
32
+ "optional": true
33
+ },
34
+ "anima": {
35
+ "shape": [
36
+ 3,
37
+ 4096
38
+ ],
39
+ "dtype": "bfloat16"
40
+ }
41
+ },
42
+ "vision_backbone": {
43
+ "repo_id": "timm/vit_so400m_patch16_siglip_gap_512.v2_webli",
44
+ "image_size": 512,
45
+ "layer_fractions": [
46
+ 0.25,
47
+ 0.55,
48
+ 1.0
49
+ ],
50
+ "pool_sizes": [
51
+ 2,
52
+ 4,
53
+ 2
54
+ ]
55
+ },
56
+ "anima_features": {
57
+ "image_size": 768,
58
+ "blocks": [
59
+ 8,
60
+ 18,
61
+ 26
62
+ ],
63
+ "sigma": 0.1,
64
+ "noise_seed": 20260715
65
+ },
66
+ "training": {
67
+ "checkpoint_step": 4500,
68
+ "face_dropout": 0.3,
69
+ "query_count": 2,
70
+ "optimizer": "AdamW(fused)",
71
+ "scheduler": "cosine_with_linear_warmup",
72
+ "learning_rate": 0.0001,
73
+ "packed_manifest_sha256": "c1267b9fd45c6e0d222b91d6ae2291b36b763277cc39cbc32484874ffeae9b32"
74
+ }
75
+ }
metrics/model_card_metrics.json ADDED
@@ -0,0 +1,169 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "selected_checkpoint": {
3
+ "checkpoint": "/workspace/runs/style_embedding_combined_lr1e4_clip10_5k/best.pt",
4
+ "checkpoint_sha256": "16345685b72c9bb018833ea9d42d18ebdaafa585b2a2eb136f267006c1de5663",
5
+ "step": 4500,
6
+ "validation_checkpoint_score": 0.6301507651805878
7
+ },
8
+ "validation_k5": {
9
+ "synthetic": {
10
+ "styles": 4500.0,
11
+ "queries": 22500.0,
12
+ "top1": 0.5625777840614319,
13
+ "top5": 0.7585333585739136,
14
+ "mrr": 0.6518997550010681,
15
+ "margin": -0.006614952813833952,
16
+ "positive_cosine": 0.7365614771842957,
17
+ "hardest_negative_cosine": 0.7431764006614685,
18
+ "verification_auroc": 0.5534452199935913,
19
+ "embedding_std": 0.04349411278963089,
20
+ "embedding_effective_rank": 24.163583755493164,
21
+ "seen_queries": 20000.0,
22
+ "seen_top1": 0.5681999921798706,
23
+ "seen_top5": 0.7637499570846558,
24
+ "seen_mrr": 0.6573799848556519,
25
+ "seen_margin": -0.004584707319736481,
26
+ "unseen_queries": 2500.0,
27
+ "unseen_top1": 0.5175999999046326,
28
+ "unseen_top5": 0.7167999744415283,
29
+ "unseen_mrr": 0.6080579161643982,
30
+ "unseen_margin": -0.02285691164433956,
31
+ "matched_queries": 4500.0,
32
+ "matched_top1": 0.48955556750297546,
33
+ "matched_top5": 0.6902222037315369,
34
+ "matched_mrr": 0.5840909481048584,
35
+ "matched_margin": -0.030851511284708977,
36
+ "cross_queries": 18000.0,
37
+ "cross_top1": 0.5808333158493042,
38
+ "cross_top5": 0.7756111025810242,
39
+ "cross_mrr": 0.6688519716262817,
40
+ "cross_margin": -0.0005558129050768912
41
+ },
42
+ "human": {
43
+ "styles": 4500.0,
44
+ "queries": 22500.0,
45
+ "top1": 0.6493777632713318,
46
+ "top5": 0.8219555616378784,
47
+ "mrr": 0.7280733585357666,
48
+ "margin": 0.022814957424998283,
49
+ "positive_cosine": 0.7811680436134338,
50
+ "hardest_negative_cosine": 0.7583531141281128,
51
+ "verification_auroc": 0.6369090676307678,
52
+ "embedding_std": 0.043804656714200974,
53
+ "embedding_effective_rank": 27.383806228637695,
54
+ "seen_queries": 20000.0,
55
+ "seen_top1": 0.660099983215332,
56
+ "seen_top5": 0.830549955368042,
57
+ "seen_mrr": 0.7378283143043518,
58
+ "seen_margin": 0.026178810745477676,
59
+ "unseen_queries": 2500.0,
60
+ "unseen_top1": 0.5636000037193298,
61
+ "unseen_top5": 0.7531999945640564,
62
+ "unseen_mrr": 0.6500336527824402,
63
+ "unseen_margin": -0.004095893818885088
64
+ }
65
+ },
66
+ "sealed_test_k5": {
67
+ "synthetic": {
68
+ "styles": 500.0,
69
+ "queries": 2500.0,
70
+ "top1": 0.7375999689102173,
71
+ "top5": 0.9031999707221985,
72
+ "mrr": 0.8114251494407654,
73
+ "margin": 0.06940444558858871,
74
+ "positive_cosine": 0.7258960008621216,
75
+ "hardest_negative_cosine": 0.6564915776252747,
76
+ "verification_auroc": 0.7113653421401978,
77
+ "embedding_std": 0.04344247281551361,
78
+ "embedding_effective_rank": 23.896039962768555,
79
+ "unseen_queries": 2500.0,
80
+ "unseen_top1": 0.7375999689102173,
81
+ "unseen_top5": 0.9031999707221985,
82
+ "unseen_mrr": 0.8114251494407654,
83
+ "unseen_margin": 0.06940444558858871,
84
+ "matched_queries": 500.0,
85
+ "matched_top1": 0.6600000262260437,
86
+ "matched_top5": 0.8520000576972961,
87
+ "matched_mrr": 0.748103678226471,
88
+ "matched_margin": 0.045967720448970795,
89
+ "cross_queries": 2000.0,
90
+ "cross_top1": 0.7570000290870667,
91
+ "cross_top5": 0.9160000681877136,
92
+ "cross_mrr": 0.8272556662559509,
93
+ "cross_margin": 0.0752636268734932
94
+ },
95
+ "human": {
96
+ "styles": 500.0,
97
+ "queries": 2500.0,
98
+ "top1": 0.761199951171875,
99
+ "top5": 0.9199999570846558,
100
+ "mrr": 0.830402135848999,
101
+ "margin": 0.08207859843969345,
102
+ "positive_cosine": 0.7568042874336243,
103
+ "hardest_negative_cosine": 0.6747256517410278,
104
+ "verification_auroc": 0.7453367114067078,
105
+ "embedding_std": 0.04376835376024246,
106
+ "embedding_effective_rank": 26.91031265258789,
107
+ "unseen_queries": 2500.0,
108
+ "unseen_top1": 0.761199951171875,
109
+ "unseen_top5": 0.9199999570846558,
110
+ "unseen_mrr": 0.830402135848999,
111
+ "unseen_margin": 0.08207859843969345
112
+ }
113
+ },
114
+ "frozen_full_face_validation_k5": {
115
+ "synthetic": {
116
+ "styles": 4500.0,
117
+ "queries": 22500.0,
118
+ "top1": 0.2617333233356476,
119
+ "top5": 0.3952000141143799,
120
+ "mrr": 0.3287946879863739,
121
+ "margin": -0.058847684413194656,
122
+ "positive_cosine": 0.3081073760986328,
123
+ "hardest_negative_cosine": 0.36695507168769836,
124
+ "verification_auroc": 0.3488680124282837,
125
+ "seen_queries": 20000.0,
126
+ "seen_top1": 0.2628999948501587,
127
+ "seen_top5": 0.3959999978542328,
128
+ "seen_mrr": 0.3298960030078888,
129
+ "seen_margin": -0.0586077980697155,
130
+ "unseen_queries": 2500.0,
131
+ "unseen_top1": 0.2523999810218811,
132
+ "unseen_top5": 0.3887999951839447,
133
+ "unseen_mrr": 0.31998398900032043,
134
+ "unseen_margin": -0.06076674535870552,
135
+ "matched_queries": 4500.0,
136
+ "matched_top1": 0.10533333569765091,
137
+ "matched_top5": 0.1851111203432083,
138
+ "matched_mrr": 0.14898858964443207,
139
+ "matched_margin": -0.11573364585638046,
140
+ "cross_queries": 18000.0,
141
+ "cross_top1": 0.3008333444595337,
142
+ "cross_top5": 0.4477222263813019,
143
+ "cross_mrr": 0.37374621629714966,
144
+ "cross_margin": -0.04462619498372078
145
+ },
146
+ "human": {
147
+ "styles": 4500.0,
148
+ "queries": 22500.0,
149
+ "top1": 0.43657779693603516,
150
+ "top5": 0.5786222219467163,
151
+ "mrr": 0.5056873559951782,
152
+ "margin": -0.029125619679689407,
153
+ "positive_cosine": 0.4710022509098053,
154
+ "hardest_negative_cosine": 0.5001279711723328,
155
+ "verification_auroc": 0.4406580626964569,
156
+ "seen_queries": 20000.0,
157
+ "seen_top1": 0.4320499897003174,
158
+ "seen_top5": 0.5762999653816223,
159
+ "seen_mrr": 0.5021449327468872,
160
+ "seen_margin": -0.030033092945814133,
161
+ "unseen_queries": 2500.0,
162
+ "unseen_top1": 0.47279998660087585,
163
+ "unseen_top5": 0.5971999764442444,
164
+ "unseen_mrr": 0.5340264439582825,
165
+ "unseen_margin": -0.021865803748369217
166
+ }
167
+ },
168
+ "protocol_note": "Synthetic K=5 uses the locked five-controlled support, one matched and four cross-content query protocol. Other K values use deterministic generic record ordering."
169
+ }
metrics/retrieval_metrics.csv ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ split,source,k,styles,queries,top1,top5,mrr,margin,seen_top1,seen_top5,seen_mrr,unseen_top1,unseen_top5,unseen_mrr,matched_mrr,cross_mrr,verification_auroc,embedding_effective_rank
2
+ validation,synthetic,1,4500.0,40500.0,0.25738272070884705,0.4447901248931885,0.3484785854816437,-0.13694550096988678,0.26072221994400024,0.448972225189209,0.35212650895118713,0.23066666722297668,0.4113333523273468,0.3192950487136841,,,0.2625024914741516,24.163583755493164
3
+ validation,synthetic,2,4500.0,36000.0,0.38269445300102234,0.5837222337722778,0.479046106338501,-0.0735325887799263,0.3878125250339508,0.5885000228881836,0.48388049006462097,0.34175002574920654,0.5455000400543213,0.4403711259365082,,,0.3855718970298767,24.163583755493164
4
+ validation,synthetic,4,4500.0,27000.0,0.4913703501224518,0.6868888735771179,0.5827372670173645,-0.032036565244197845,0.4964166581630707,0.6924583315849304,0.5878510475158691,0.45100000500679016,0.6423333287239075,0.5418276190757751,,,0.4890711009502411,24.163583755493164
5
+ validation,synthetic,5,4500.0,22500.0,0.5625777840614319,0.7585333585739136,0.6518997550010681,-0.006614952813833952,0.5681999921798706,0.7637499570846558,0.6573799848556519,0.5175999999046326,0.7167999744415283,0.6080579161643982,0.5840909481048584,0.6688519716262817,0.5534452199935913,24.163583755493164
6
+ validation,synthetic,8,4500.0,9000.0,0.5631111264228821,0.7501111030578613,0.6487501263618469,-0.006703122518956661,0.5692500472068787,0.7573750615119934,0.6548616290092468,0.5139999985694885,0.6920000314712524,0.5998580455780029,,,0.557915985584259,24.163583755493164
7
+ validation,human,1,4500.0,40500.0,0.37967902421951294,0.5846666693687439,0.47633036971092224,-0.07382111996412277,0.3872777819633484,0.5945833325386047,0.48492416739463806,0.31888890266418457,0.5053333640098572,0.40757980942726135,,,0.38891345262527466,27.383806228637695
8
+ validation,human,2,4500.0,36000.0,0.5184444785118103,0.7187777757644653,0.6118195652961731,-0.018171189352869987,0.5287187695503235,0.729593813419342,0.6219512224197388,0.4362500309944153,0.6322500109672546,0.5307666063308716,,,0.516968846321106,27.383806228637695
9
+ validation,human,4,4500.0,27000.0,0.6229629516601562,0.8089629411697388,0.7071906924247742,0.01628497801721096,0.6336249709129333,0.8175833225250244,0.7167206406593323,0.5376666784286499,0.7400000095367432,0.6309514045715332,,,0.6160270571708679,27.383806228637695
10
+ validation,human,5,4500.0,22500.0,0.6493777632713318,0.8219555616378784,0.7280733585357666,0.022814957424998283,0.660099983215332,0.830549955368042,0.7378283143043518,0.5636000037193298,0.7531999945640564,0.6500336527824402,,,0.6369090676307678,27.383806228637695
11
+ validation,human,8,4500.0,9000.0,0.6846666932106018,0.8516666889190674,0.7596060037612915,0.03352390229701996,0.6943750381469727,0.85875004529953,0.7680479884147644,0.6070000529289246,0.7950000166893005,0.6920705437660217,,,0.6696112155914307,27.383806228637695
12
+ test,synthetic,1,500.0,4500.0,0.41688889265060425,0.6495555639266968,0.5274384617805481,-0.07223178446292877,,,,0.41688889265060425,0.6495555639266968,0.5274384617805481,,,0.41443032026290894,23.896039962768555
13
+ test,synthetic,2,500.0,4000.0,0.5692500472068787,0.7830000519752502,0.6672611236572266,0.00026985956355929375,,,,0.5692500472068787,0.7830000519752502,0.6672611236572266,,,0.557541012763977,23.896039962768555
14
+ test,synthetic,4,500.0,3000.0,0.6786666512489319,0.8600000143051147,0.7601169943809509,0.04286628216505051,,,,0.6786666512489319,0.8600000143051147,0.7601169943809509,,,0.6542216539382935,23.896039962768555
15
+ test,synthetic,5,500.0,2500.0,0.7375999689102173,0.9031999707221985,0.8114251494407654,0.06940444558858871,,,,0.7375999689102173,0.9031999707221985,0.8114251494407654,0.748103678226471,0.8272556662559509,0.7113653421401978,23.896039962768555
16
+ test,synthetic,8,500.0,1000.0,0.7070000171661377,0.8790000677108765,0.7862902879714966,0.06344308704137802,,,,0.7070000171661377,0.8790000677108765,0.7862902879714966,,,0.7011929750442505,23.896039962768555
17
+ test,human,1,500.0,4500.0,0.5155555605888367,0.7431111335754395,0.6204044222831726,-0.0215375367552042,,,,0.5155555605888367,0.7431111335754395,0.6204044222831726,,,0.5082485675811768,26.91031265258789
18
+ test,human,2,500.0,4000.0,0.6565000414848328,0.8540000319480896,0.7454702258110046,0.03674145042896271,,,,0.6565000414848328,0.8540000319480896,0.7454702258110046,,,0.6430025100708008,26.91031265258789
19
+ test,human,4,500.0,3000.0,0.737666666507721,0.9136666655540466,0.8140823245048523,0.07469645887613297,,,,0.737666666507721,0.9136666655540466,0.8140823245048523,,,0.726514458656311,26.91031265258789
20
+ test,human,5,500.0,2500.0,0.761199951171875,0.9199999570846558,0.830402135848999,0.08207859843969345,,,,0.761199951171875,0.9199999570846558,0.830402135848999,,,0.7453367114067078,26.91031265258789
21
+ test,human,8,500.0,1000.0,0.7820000648498535,0.9250000715255737,0.8470030426979065,0.08853543549776077,,,,0.7820000648498535,0.9250000715255737,0.8470030426979065,,,0.7604439854621887,26.91031265258789
metrics/test_k_curve.json ADDED
@@ -0,0 +1,204 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "synthetic": {
3
+ "k1": {
4
+ "styles": 500.0,
5
+ "queries": 4500.0,
6
+ "top1": 0.41688889265060425,
7
+ "top5": 0.6495555639266968,
8
+ "mrr": 0.5274384617805481,
9
+ "margin": -0.07223178446292877,
10
+ "positive_cosine": 0.5964593291282654,
11
+ "hardest_negative_cosine": 0.668691098690033,
12
+ "verification_auroc": 0.41443032026290894,
13
+ "embedding_std": 0.04344247281551361,
14
+ "embedding_effective_rank": 23.896039962768555,
15
+ "unseen_queries": 4500.0,
16
+ "unseen_top1": 0.41688889265060425,
17
+ "unseen_top5": 0.6495555639266968,
18
+ "unseen_mrr": 0.5274384617805481,
19
+ "unseen_margin": -0.07223178446292877
20
+ },
21
+ "k2": {
22
+ "styles": 500.0,
23
+ "queries": 4000.0,
24
+ "top1": 0.5692500472068787,
25
+ "top5": 0.7830000519752502,
26
+ "mrr": 0.6672611236572266,
27
+ "margin": 0.00026985956355929375,
28
+ "positive_cosine": 0.6695296764373779,
29
+ "hardest_negative_cosine": 0.6692599058151245,
30
+ "verification_auroc": 0.557541012763977,
31
+ "embedding_std": 0.04344247281551361,
32
+ "embedding_effective_rank": 23.896039962768555,
33
+ "unseen_queries": 4000.0,
34
+ "unseen_top1": 0.5692500472068787,
35
+ "unseen_top5": 0.7830000519752502,
36
+ "unseen_mrr": 0.6672611236572266,
37
+ "unseen_margin": 0.00026985956355929375
38
+ },
39
+ "k4": {
40
+ "styles": 500.0,
41
+ "queries": 3000.0,
42
+ "top1": 0.6786666512489319,
43
+ "top5": 0.8600000143051147,
44
+ "mrr": 0.7601169943809509,
45
+ "margin": 0.04286628216505051,
46
+ "positive_cosine": 0.7160320281982422,
47
+ "hardest_negative_cosine": 0.6731657981872559,
48
+ "verification_auroc": 0.6542216539382935,
49
+ "embedding_std": 0.04344247281551361,
50
+ "embedding_effective_rank": 23.896039962768555,
51
+ "unseen_queries": 3000.0,
52
+ "unseen_top1": 0.6786666512489319,
53
+ "unseen_top5": 0.8600000143051147,
54
+ "unseen_mrr": 0.7601169943809509,
55
+ "unseen_margin": 0.04286628216505051
56
+ },
57
+ "k5": {
58
+ "styles": 500.0,
59
+ "queries": 2500.0,
60
+ "top1": 0.7375999689102173,
61
+ "top5": 0.9031999707221985,
62
+ "mrr": 0.8114251494407654,
63
+ "margin": 0.06940444558858871,
64
+ "positive_cosine": 0.7258960008621216,
65
+ "hardest_negative_cosine": 0.6564915776252747,
66
+ "verification_auroc": 0.7113653421401978,
67
+ "embedding_std": 0.04344247281551361,
68
+ "embedding_effective_rank": 23.896039962768555,
69
+ "unseen_queries": 2500.0,
70
+ "unseen_top1": 0.7375999689102173,
71
+ "unseen_top5": 0.9031999707221985,
72
+ "unseen_mrr": 0.8114251494407654,
73
+ "unseen_margin": 0.06940444558858871,
74
+ "matched_queries": 500.0,
75
+ "matched_top1": 0.6600000262260437,
76
+ "matched_top5": 0.8520000576972961,
77
+ "matched_mrr": 0.748103678226471,
78
+ "matched_margin": 0.045967720448970795,
79
+ "cross_queries": 2000.0,
80
+ "cross_top1": 0.7570000290870667,
81
+ "cross_top5": 0.9160000681877136,
82
+ "cross_mrr": 0.8272556662559509,
83
+ "cross_margin": 0.0752636268734932
84
+ },
85
+ "k8": {
86
+ "styles": 500.0,
87
+ "queries": 1000.0,
88
+ "top1": 0.7070000171661377,
89
+ "top5": 0.8790000677108765,
90
+ "mrr": 0.7862902879714966,
91
+ "margin": 0.06344308704137802,
92
+ "positive_cosine": 0.739560604095459,
93
+ "hardest_negative_cosine": 0.676117479801178,
94
+ "verification_auroc": 0.7011929750442505,
95
+ "embedding_std": 0.04344247281551361,
96
+ "embedding_effective_rank": 23.896039962768555,
97
+ "unseen_queries": 1000.0,
98
+ "unseen_top1": 0.7070000171661377,
99
+ "unseen_top5": 0.8790000677108765,
100
+ "unseen_mrr": 0.7862902879714966,
101
+ "unseen_margin": 0.06344308704137802
102
+ }
103
+ },
104
+ "human": {
105
+ "k1": {
106
+ "styles": 500.0,
107
+ "queries": 4500.0,
108
+ "top1": 0.5155555605888367,
109
+ "top5": 0.7431111335754395,
110
+ "mrr": 0.6204044222831726,
111
+ "margin": -0.0215375367552042,
112
+ "positive_cosine": 0.6388872861862183,
113
+ "hardest_negative_cosine": 0.6604248285293579,
114
+ "verification_auroc": 0.5082485675811768,
115
+ "embedding_std": 0.04376835376024246,
116
+ "embedding_effective_rank": 26.91031265258789,
117
+ "unseen_queries": 4500.0,
118
+ "unseen_top1": 0.5155555605888367,
119
+ "unseen_top5": 0.7431111335754395,
120
+ "unseen_mrr": 0.6204044222831726,
121
+ "unseen_margin": -0.0215375367552042
122
+ },
123
+ "k2": {
124
+ "styles": 500.0,
125
+ "queries": 4000.0,
126
+ "top1": 0.6565000414848328,
127
+ "top5": 0.8540000319480896,
128
+ "mrr": 0.7454702258110046,
129
+ "margin": 0.03674145042896271,
130
+ "positive_cosine": 0.7047365307807922,
131
+ "hardest_negative_cosine": 0.6679950952529907,
132
+ "verification_auroc": 0.6430025100708008,
133
+ "embedding_std": 0.04376835376024246,
134
+ "embedding_effective_rank": 26.91031265258789,
135
+ "unseen_queries": 4000.0,
136
+ "unseen_top1": 0.6565000414848328,
137
+ "unseen_top5": 0.8540000319480896,
138
+ "unseen_mrr": 0.7454702258110046,
139
+ "unseen_margin": 0.03674145042896271
140
+ },
141
+ "k4": {
142
+ "styles": 500.0,
143
+ "queries": 3000.0,
144
+ "top1": 0.737666666507721,
145
+ "top5": 0.9136666655540466,
146
+ "mrr": 0.8140823245048523,
147
+ "margin": 0.07469645887613297,
148
+ "positive_cosine": 0.7484809756278992,
149
+ "hardest_negative_cosine": 0.6737845540046692,
150
+ "verification_auroc": 0.726514458656311,
151
+ "embedding_std": 0.04376835376024246,
152
+ "embedding_effective_rank": 26.91031265258789,
153
+ "unseen_queries": 3000.0,
154
+ "unseen_top1": 0.737666666507721,
155
+ "unseen_top5": 0.9136666655540466,
156
+ "unseen_mrr": 0.8140823245048523,
157
+ "unseen_margin": 0.07469645887613297
158
+ },
159
+ "k5": {
160
+ "styles": 500.0,
161
+ "queries": 2500.0,
162
+ "top1": 0.761199951171875,
163
+ "top5": 0.9199999570846558,
164
+ "mrr": 0.830402135848999,
165
+ "margin": 0.08207859843969345,
166
+ "positive_cosine": 0.7568042874336243,
167
+ "hardest_negative_cosine": 0.6747256517410278,
168
+ "verification_auroc": 0.7453367114067078,
169
+ "embedding_std": 0.04376835376024246,
170
+ "embedding_effective_rank": 26.91031265258789,
171
+ "unseen_queries": 2500.0,
172
+ "unseen_top1": 0.761199951171875,
173
+ "unseen_top5": 0.9199999570846558,
174
+ "unseen_mrr": 0.830402135848999,
175
+ "unseen_margin": 0.08207859843969345
176
+ },
177
+ "k8": {
178
+ "styles": 500.0,
179
+ "queries": 1000.0,
180
+ "top1": 0.7820000648498535,
181
+ "top5": 0.9250000715255737,
182
+ "mrr": 0.8470030426979065,
183
+ "margin": 0.08853543549776077,
184
+ "positive_cosine": 0.7681199312210083,
185
+ "hardest_negative_cosine": 0.6795844435691833,
186
+ "verification_auroc": 0.7604439854621887,
187
+ "embedding_std": 0.04376835376024246,
188
+ "embedding_effective_rank": 26.91031265258789,
189
+ "unseen_queries": 1000.0,
190
+ "unseen_top1": 0.7820000648498535,
191
+ "unseen_top5": 0.9250000715255737,
192
+ "unseen_mrr": 0.8470030426979065,
193
+ "unseen_margin": 0.08853543549776077
194
+ }
195
+ },
196
+ "checkpoint_score": 0.8209136426448822,
197
+ "checkpoint_config": {
198
+ "packed_manifest_sha256": "c1267b9fd45c6e0d222b91d6ae2291b36b763277cc39cbc32484874ffeae9b32",
199
+ "use_anima": true,
200
+ "face_dropout": 0.3,
201
+ "episode_pairs": 8,
202
+ "seed": 20260719
203
+ }
204
+ }
metrics/training_metrics.jsonl ADDED
The diff for this file is too large to render. See raw diff
 
metrics/validation_k_curve.json ADDED
@@ -0,0 +1,254 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "synthetic": {
3
+ "k1": {
4
+ "styles": 4500.0,
5
+ "queries": 40500.0,
6
+ "top1": 0.25738272070884705,
7
+ "top5": 0.4447901248931885,
8
+ "mrr": 0.3484785854816437,
9
+ "margin": -0.13694550096988678,
10
+ "positive_cosine": 0.6166356205940247,
11
+ "hardest_negative_cosine": 0.7535811066627502,
12
+ "verification_auroc": 0.2625024914741516,
13
+ "embedding_std": 0.04349411278963089,
14
+ "embedding_effective_rank": 24.163583755493164,
15
+ "seen_queries": 36000.0,
16
+ "seen_top1": 0.26072221994400024,
17
+ "seen_top5": 0.448972225189209,
18
+ "seen_mrr": 0.35212650895118713,
19
+ "seen_margin": -0.13477584719657898,
20
+ "unseen_queries": 4500.0,
21
+ "unseen_top1": 0.23066666722297668,
22
+ "unseen_top5": 0.4113333523273468,
23
+ "unseen_mrr": 0.3192950487136841,
24
+ "unseen_margin": -0.15430252254009247
25
+ },
26
+ "k2": {
27
+ "styles": 4500.0,
28
+ "queries": 36000.0,
29
+ "top1": 0.38269445300102234,
30
+ "top5": 0.5837222337722778,
31
+ "mrr": 0.479046106338501,
32
+ "margin": -0.0735325887799263,
33
+ "positive_cosine": 0.6810839176177979,
34
+ "hardest_negative_cosine": 0.7546165585517883,
35
+ "verification_auroc": 0.3855718970298767,
36
+ "embedding_std": 0.04349411278963089,
37
+ "embedding_effective_rank": 24.163583755493164,
38
+ "seen_queries": 32000.0,
39
+ "seen_top1": 0.3878125250339508,
40
+ "seen_top5": 0.5885000228881836,
41
+ "seen_mrr": 0.48388049006462097,
42
+ "seen_margin": -0.07155531644821167,
43
+ "unseen_queries": 4000.0,
44
+ "unseen_top1": 0.34175002574920654,
45
+ "unseen_top5": 0.5455000400543213,
46
+ "unseen_mrr": 0.4403711259365082,
47
+ "unseen_margin": -0.08935073763132095
48
+ },
49
+ "k4": {
50
+ "styles": 4500.0,
51
+ "queries": 27000.0,
52
+ "top1": 0.4913703501224518,
53
+ "top5": 0.6868888735771179,
54
+ "mrr": 0.5827372670173645,
55
+ "margin": -0.032036565244197845,
56
+ "positive_cosine": 0.7242447733879089,
57
+ "hardest_negative_cosine": 0.756281316280365,
58
+ "verification_auroc": 0.4890711009502411,
59
+ "embedding_std": 0.04349411278963089,
60
+ "embedding_effective_rank": 24.163583755493164,
61
+ "seen_queries": 24000.0,
62
+ "seen_top1": 0.4964166581630707,
63
+ "seen_top5": 0.6924583315849304,
64
+ "seen_mrr": 0.5878510475158691,
65
+ "seen_margin": -0.030110228806734085,
66
+ "unseen_queries": 3000.0,
67
+ "unseen_top1": 0.45100000500679016,
68
+ "unseen_top5": 0.6423333287239075,
69
+ "unseen_mrr": 0.5418276190757751,
70
+ "unseen_margin": -0.047447264194488525
71
+ },
72
+ "k5": {
73
+ "styles": 4500.0,
74
+ "queries": 22500.0,
75
+ "top1": 0.5625777840614319,
76
+ "top5": 0.7585333585739136,
77
+ "mrr": 0.6518997550010681,
78
+ "margin": -0.006614952813833952,
79
+ "positive_cosine": 0.7365614771842957,
80
+ "hardest_negative_cosine": 0.7431764006614685,
81
+ "verification_auroc": 0.5534452199935913,
82
+ "embedding_std": 0.04349411278963089,
83
+ "embedding_effective_rank": 24.163583755493164,
84
+ "seen_queries": 20000.0,
85
+ "seen_top1": 0.5681999921798706,
86
+ "seen_top5": 0.7637499570846558,
87
+ "seen_mrr": 0.6573799848556519,
88
+ "seen_margin": -0.004584707319736481,
89
+ "unseen_queries": 2500.0,
90
+ "unseen_top1": 0.5175999999046326,
91
+ "unseen_top5": 0.7167999744415283,
92
+ "unseen_mrr": 0.6080579161643982,
93
+ "unseen_margin": -0.02285691164433956,
94
+ "matched_queries": 4500.0,
95
+ "matched_top1": 0.48955556750297546,
96
+ "matched_top5": 0.6902222037315369,
97
+ "matched_mrr": 0.5840909481048584,
98
+ "matched_margin": -0.030851511284708977,
99
+ "cross_queries": 18000.0,
100
+ "cross_top1": 0.5808333158493042,
101
+ "cross_top5": 0.7756111025810242,
102
+ "cross_mrr": 0.6688519716262817,
103
+ "cross_margin": -0.0005558129050768912
104
+ },
105
+ "k8": {
106
+ "styles": 4500.0,
107
+ "queries": 9000.0,
108
+ "top1": 0.5631111264228821,
109
+ "top5": 0.7501111030578613,
110
+ "mrr": 0.6487501263618469,
111
+ "margin": -0.006703122518956661,
112
+ "positive_cosine": 0.7508071660995483,
113
+ "hardest_negative_cosine": 0.7575103044509888,
114
+ "verification_auroc": 0.557915985584259,
115
+ "embedding_std": 0.04349411278963089,
116
+ "embedding_effective_rank": 24.163583755493164,
117
+ "seen_queries": 8000.0,
118
+ "seen_top1": 0.5692500472068787,
119
+ "seen_top5": 0.7573750615119934,
120
+ "seen_mrr": 0.6548616290092468,
121
+ "seen_margin": -0.004510539583861828,
122
+ "unseen_queries": 1000.0,
123
+ "unseen_top1": 0.5139999985694885,
124
+ "unseen_top5": 0.6920000314712524,
125
+ "unseen_mrr": 0.5998580455780029,
126
+ "unseen_margin": -0.024243783205747604
127
+ }
128
+ },
129
+ "human": {
130
+ "k1": {
131
+ "styles": 4500.0,
132
+ "queries": 40500.0,
133
+ "top1": 0.37967902421951294,
134
+ "top5": 0.5846666693687439,
135
+ "mrr": 0.47633036971092224,
136
+ "margin": -0.07382111996412277,
137
+ "positive_cosine": 0.6724859476089478,
138
+ "hardest_negative_cosine": 0.7463070750236511,
139
+ "verification_auroc": 0.38891345262527466,
140
+ "embedding_std": 0.043804656714200974,
141
+ "embedding_effective_rank": 27.383806228637695,
142
+ "seen_queries": 36000.0,
143
+ "seen_top1": 0.3872777819633484,
144
+ "seen_top5": 0.5945833325386047,
145
+ "seen_mrr": 0.48492416739463806,
146
+ "seen_margin": -0.06964229047298431,
147
+ "unseen_queries": 4500.0,
148
+ "unseen_top1": 0.31888890266418457,
149
+ "unseen_top5": 0.5053333640098572,
150
+ "unseen_mrr": 0.40757980942726135,
151
+ "unseen_margin": -0.10725177824497223
152
+ },
153
+ "k2": {
154
+ "styles": 4500.0,
155
+ "queries": 36000.0,
156
+ "top1": 0.5184444785118103,
157
+ "top5": 0.7187777757644653,
158
+ "mrr": 0.6118195652961731,
159
+ "margin": -0.018171189352869987,
160
+ "positive_cosine": 0.7339839339256287,
161
+ "hardest_negative_cosine": 0.7521551847457886,
162
+ "verification_auroc": 0.516968846321106,
163
+ "embedding_std": 0.043804656714200974,
164
+ "embedding_effective_rank": 27.383806228637695,
165
+ "seen_queries": 32000.0,
166
+ "seen_top1": 0.5287187695503235,
167
+ "seen_top5": 0.729593813419342,
168
+ "seen_mrr": 0.6219512224197388,
169
+ "seen_margin": -0.014534689486026764,
170
+ "unseen_queries": 4000.0,
171
+ "unseen_top1": 0.4362500309944153,
172
+ "unseen_top5": 0.6322500109672546,
173
+ "unseen_mrr": 0.5307666063308716,
174
+ "unseen_margin": -0.04726320877671242
175
+ },
176
+ "k4": {
177
+ "styles": 4500.0,
178
+ "queries": 27000.0,
179
+ "top1": 0.6229629516601562,
180
+ "top5": 0.8089629411697388,
181
+ "mrr": 0.7071906924247742,
182
+ "margin": 0.01628497801721096,
183
+ "positive_cosine": 0.7733137607574463,
184
+ "hardest_negative_cosine": 0.7570288181304932,
185
+ "verification_auroc": 0.6160270571708679,
186
+ "embedding_std": 0.043804656714200974,
187
+ "embedding_effective_rank": 27.383806228637695,
188
+ "seen_queries": 24000.0,
189
+ "seen_top1": 0.6336249709129333,
190
+ "seen_top5": 0.8175833225250244,
191
+ "seen_mrr": 0.7167206406593323,
192
+ "seen_margin": 0.019602350890636444,
193
+ "unseen_queries": 3000.0,
194
+ "unseen_top1": 0.5376666784286499,
195
+ "unseen_top5": 0.7400000095367432,
196
+ "unseen_mrr": 0.6309514045715332,
197
+ "unseen_margin": -0.01025400310754776
198
+ },
199
+ "k5": {
200
+ "styles": 4500.0,
201
+ "queries": 22500.0,
202
+ "top1": 0.6493777632713318,
203
+ "top5": 0.8219555616378784,
204
+ "mrr": 0.7280733585357666,
205
+ "margin": 0.022814957424998283,
206
+ "positive_cosine": 0.7811680436134338,
207
+ "hardest_negative_cosine": 0.7583531141281128,
208
+ "verification_auroc": 0.6369090676307678,
209
+ "embedding_std": 0.043804656714200974,
210
+ "embedding_effective_rank": 27.383806228637695,
211
+ "seen_queries": 20000.0,
212
+ "seen_top1": 0.660099983215332,
213
+ "seen_top5": 0.830549955368042,
214
+ "seen_mrr": 0.7378283143043518,
215
+ "seen_margin": 0.026178810745477676,
216
+ "unseen_queries": 2500.0,
217
+ "unseen_top1": 0.5636000037193298,
218
+ "unseen_top5": 0.7531999945640564,
219
+ "unseen_mrr": 0.6500336527824402,
220
+ "unseen_margin": -0.004095893818885088
221
+ },
222
+ "k8": {
223
+ "styles": 4500.0,
224
+ "queries": 9000.0,
225
+ "top1": 0.6846666932106018,
226
+ "top5": 0.8516666889190674,
227
+ "mrr": 0.7596060037612915,
228
+ "margin": 0.03352390229701996,
229
+ "positive_cosine": 0.793936014175415,
230
+ "hardest_negative_cosine": 0.7604120373725891,
231
+ "verification_auroc": 0.6696112155914307,
232
+ "embedding_std": 0.043804656714200974,
233
+ "embedding_effective_rank": 27.383806228637695,
234
+ "seen_queries": 8000.0,
235
+ "seen_top1": 0.6943750381469727,
236
+ "seen_top5": 0.85875004529953,
237
+ "seen_mrr": 0.7680479884147644,
238
+ "seen_margin": 0.03656964749097824,
239
+ "unseen_queries": 1000.0,
240
+ "unseen_top1": 0.6070000529289246,
241
+ "unseen_top5": 0.7950000166893005,
242
+ "unseen_mrr": 0.6920705437660217,
243
+ "unseen_margin": 0.009157972410321236
244
+ }
245
+ },
246
+ "checkpoint_score": 0.6290457844734192,
247
+ "checkpoint_config": {
248
+ "packed_manifest_sha256": "c1267b9fd45c6e0d222b91d6ae2291b36b763277cc39cbc32484874ffeae9b32",
249
+ "use_anima": true,
250
+ "face_dropout": 0.3,
251
+ "episode_pairs": 8,
252
+ "seed": 20260719
253
+ }
254
+ }
model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6cdf126152927f6e31dc856a8d10b8decee3bb20ce4c0ca449206db65d4633ec
3
+ size 69962484
modeling_anima_style_embedding.py ADDED
@@ -0,0 +1,341 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import math
4
+
5
+ import torch
6
+ from torch import Tensor, nn
7
+ from torch.nn import functional as F
8
+
9
+
10
+ def masked_mean_prototype(per_image: Tensor, mask: Tensor) -> Tensor:
11
+ if per_image.ndim != 3 or mask.shape != per_image.shape[:2]:
12
+ raise ValueError("expected per_image [batch,references,width] and matching mask")
13
+ mask = mask.to(device=per_image.device, dtype=torch.bool)
14
+ counts = mask.sum(dim=1)
15
+ if torch.any(counts < 1) or torch.any(counts > 8):
16
+ raise ValueError("each reference set must contain 1-8 images")
17
+ weights = mask.unsqueeze(-1).to(per_image.dtype)
18
+ mean = (per_image * weights).sum(dim=1) / counts.unsqueeze(-1)
19
+ return F.normalize(mean, dim=-1)
20
+
21
+
22
+ class StyleMixerBlock(nn.Module):
23
+ def __init__(self, width: int, heads: int, dropout: float = 0.0) -> None:
24
+ super().__init__()
25
+ self.query_norm = nn.LayerNorm(width)
26
+ self.token_norm = nn.LayerNorm(width)
27
+ self.attention = nn.MultiheadAttention(width, heads, batch_first=True)
28
+ self.attention_dropout = nn.Dropout(dropout)
29
+ self.output_norm = nn.LayerNorm(width)
30
+ self.mlp = nn.Sequential(
31
+ nn.Linear(width, 4 * width),
32
+ nn.GELU(),
33
+ nn.Dropout(dropout),
34
+ nn.Linear(4 * width, width),
35
+ nn.Dropout(dropout),
36
+ )
37
+
38
+ def forward(self, query: Tensor, tokens: Tensor, token_mask: Tensor) -> Tensor:
39
+ value, _ = self.attention(
40
+ self.query_norm(query),
41
+ self.token_norm(tokens),
42
+ self.token_norm(tokens),
43
+ key_padding_mask=~token_mask,
44
+ need_weights=False,
45
+ )
46
+ query = query + self.attention_dropout(value)
47
+ return query + self.mlp(self.output_norm(query))
48
+
49
+
50
+ class UnifiedStyleEncoder(nn.Module):
51
+ """Encode cached full/face vision tokens and optional Anima descriptors."""
52
+
53
+ def __init__(
54
+ self,
55
+ *,
56
+ external_dim: int = 1152,
57
+ external_tokens: int = 30,
58
+ anima_dim: int = 4096,
59
+ anima_tokens: int = 3,
60
+ width: int = 384,
61
+ blocks: int = 2,
62
+ heads: int = 6,
63
+ embedding_dim: int = 512,
64
+ use_anima: bool = True,
65
+ dropout: float = 0.0,
66
+ reference_grounding: bool = False,
67
+ functional_factors: bool = False,
68
+ ) -> None:
69
+ super().__init__()
70
+ if (
71
+ blocks < 1
72
+ or width % heads
73
+ or (reference_grounding and embedding_dim % heads)
74
+ or not 0.0 <= dropout < 1.0
75
+ ):
76
+ raise ValueError("blocks must be positive and width must be divisible by heads")
77
+ if functional_factors and embedding_dim != 512:
78
+ raise ValueError("functional factorization currently requires a 512-D embedding")
79
+ self.external_tokens = external_tokens
80
+ self.anima_tokens = anima_tokens if use_anima else 0
81
+ self.external_projector = nn.Sequential(
82
+ nn.LayerNorm(external_dim),
83
+ nn.Linear(external_dim, width),
84
+ )
85
+ self.anima_projector = (
86
+ nn.Sequential(nn.LayerNorm(anima_dim), nn.Linear(anima_dim, width))
87
+ if use_anima
88
+ else None
89
+ )
90
+ self.full_positions = nn.Parameter(torch.randn(external_tokens, width) * 0.02)
91
+ self.face_positions = nn.Parameter(torch.randn(external_tokens, width) * 0.02)
92
+ self.anima_positions = (
93
+ nn.Parameter(torch.randn(anima_tokens, width) * 0.02) if use_anima else None
94
+ )
95
+ self.reference_grounding = reference_grounding
96
+ self.functional_factors = functional_factors
97
+ query_count = 5 if functional_factors else 1
98
+ self.style_query = nn.Parameter(torch.randn(1, query_count, width) * 0.02)
99
+ self.blocks = nn.ModuleList(
100
+ [StyleMixerBlock(width, heads, dropout) for _ in range(blocks)]
101
+ )
102
+ if functional_factors:
103
+ self.factor_output = nn.Sequential(nn.LayerNorm(width), nn.Linear(width, 96))
104
+ self.shared_output = nn.Sequential(nn.LayerNorm(width), nn.Linear(width, 128))
105
+ self.output = nn.Sequential(nn.LayerNorm(512), nn.Linear(512, embedding_dim))
106
+ self.factor_decoders = nn.ModuleList([nn.Linear(96, external_dim) for _ in range(4)])
107
+ else:
108
+ self.output = nn.Sequential(nn.LayerNorm(width), nn.Linear(width, embedding_dim))
109
+ if reference_grounding:
110
+ self.consensus_query = nn.Parameter(torch.randn(1, 1, embedding_dim) * 0.02)
111
+ self.consensus_attention = nn.MultiheadAttention(
112
+ embedding_dim, heads, batch_first=True, dropout=dropout
113
+ )
114
+ self.consensus_condition = nn.Linear(embedding_dim, width)
115
+ self.consensus_gamma = nn.Parameter(torch.tensor(-2.9444))
116
+
117
+ def _read_tokens(
118
+ self, tokens: Tensor, token_mask: Tensor, conditioning: Tensor | None = None
119
+ ) -> tuple[Tensor, Tensor | None]:
120
+ query = self.style_query.expand(tokens.shape[0], -1, -1)
121
+ if conditioning is not None:
122
+ query = query + self.consensus_condition(conditioning)[:, None]
123
+ for block in self.blocks:
124
+ query = block(query, tokens, token_mask)
125
+ if self.functional_factors:
126
+ factors = F.normalize(self.factor_output(query[:, :4]), dim=-1)
127
+ shared = self.shared_output(query[:, 4])
128
+ embedding = self.output(torch.cat((factors.flatten(1), shared), dim=-1))
129
+ return F.normalize(embedding, dim=-1), factors
130
+ return F.normalize(self.output(query[:, 0]), dim=-1), None
131
+
132
+ def encode_images(
133
+ self,
134
+ full_features: Tensor,
135
+ *,
136
+ face_features: Tensor | None = None,
137
+ face_mask: Tensor | None = None,
138
+ anima_features: Tensor | None = None,
139
+ conditioning: Tensor | None = None,
140
+ ) -> Tensor:
141
+ """Encode independent images without padding them into reference sets."""
142
+
143
+ if full_features.ndim != 3 or full_features.shape[1] != self.external_tokens:
144
+ raise ValueError("full_features must have shape [images,external_tokens,width]")
145
+ images = full_features.shape[0]
146
+ full = self.external_projector(full_features) + self.full_positions
147
+ tokens = [full]
148
+ masks = [torch.ones(full.shape[:2], dtype=torch.bool, device=full.device)]
149
+
150
+ if face_features is not None:
151
+ if face_features.shape != full_features.shape:
152
+ raise ValueError("face_features must match full_features")
153
+ if face_mask is None or face_mask.shape != (images,):
154
+ raise ValueError("face_mask is required and must contain one value per image")
155
+ face = self.external_projector(face_features)
156
+ tokens.append(face + self.face_positions)
157
+ masks.append(face_mask[:, None].to(torch.bool).expand(-1, self.external_tokens))
158
+
159
+ if self.anima_projector is not None:
160
+ expected = (images, self.anima_tokens)
161
+ if anima_features is None or anima_features.shape[:2] != expected:
162
+ raise ValueError("anima_features are required by this encoder configuration")
163
+ anima = self.anima_projector(anima_features)
164
+ tokens.append(anima + self.anima_positions)
165
+ masks.append(torch.ones(anima.shape[:2], dtype=torch.bool, device=anima.device))
166
+
167
+ token_tensor = torch.cat(tokens, dim=1)
168
+ token_mask = torch.cat(masks, dim=1)
169
+ return self._read_tokens(token_tensor, token_mask, conditioning)[0]
170
+
171
+ def encode_images_with_factors(
172
+ self,
173
+ full_features: Tensor,
174
+ *,
175
+ face_features: Tensor | None = None,
176
+ face_mask: Tensor | None = None,
177
+ anima_features: Tensor | None = None,
178
+ conditioning: Tensor | None = None,
179
+ ) -> tuple[Tensor, Tensor | None]:
180
+ if full_features.ndim != 3 or full_features.shape[1] != self.external_tokens:
181
+ raise ValueError("full_features must have shape [images,external_tokens,width]")
182
+ images = full_features.shape[0]
183
+ full = self.external_projector(full_features) + self.full_positions
184
+ tokens = [full]
185
+ masks = [torch.ones(full.shape[:2], dtype=torch.bool, device=full.device)]
186
+ if face_features is not None:
187
+ if face_features.shape != full_features.shape:
188
+ raise ValueError("face_features must match full_features")
189
+ if face_mask is None or face_mask.shape != (images,):
190
+ raise ValueError("face_mask is required and must contain one value per image")
191
+ tokens.append(self.external_projector(face_features) + self.face_positions)
192
+ masks.append(face_mask[:, None].to(torch.bool).expand(-1, self.external_tokens))
193
+ if self.anima_projector is not None:
194
+ if anima_features is None or anima_features.shape[:2] != (images, self.anima_tokens):
195
+ raise ValueError("anima_features are required by this encoder configuration")
196
+ tokens.append(self.anima_projector(anima_features) + self.anima_positions)
197
+ masks.append(torch.ones(anima_features.shape[:2], dtype=torch.bool, device=full.device))
198
+ return self._read_tokens(torch.cat(tokens, dim=1), torch.cat(masks, dim=1), conditioning)
199
+
200
+ def encode_reference_sets(
201
+ self,
202
+ full_features: Tensor,
203
+ reference_mask: Tensor,
204
+ *,
205
+ face_features: Tensor | None = None,
206
+ face_mask: Tensor | None = None,
207
+ anima_features: Tensor | None = None,
208
+ ) -> tuple[Tensor, Tensor, Tensor | None]:
209
+ batch, references = full_features.shape[:2]
210
+ flat_face = None if face_features is None else face_features.flatten(0, 1)
211
+ flat_face_mask = None if face_mask is None else face_mask.flatten()
212
+ flat_anima = None if anima_features is None else anima_features.flatten(0, 1)
213
+ per_image, factors = self.encode_images_with_factors(
214
+ full_features.flatten(0, 1),
215
+ face_features=flat_face,
216
+ face_mask=flat_face_mask,
217
+ anima_features=flat_anima,
218
+ )
219
+ per_image = per_image.reshape(batch, references, -1)
220
+ factors = None if factors is None else factors.reshape(batch, references, 4, -1)
221
+ base = masked_mean_prototype(per_image, reference_mask)
222
+ if not self.reference_grounding:
223
+ return base, per_image, factors
224
+ consensus, _ = self.consensus_attention(
225
+ self.consensus_query.expand(batch, -1, -1),
226
+ per_image,
227
+ per_image,
228
+ key_padding_mask=~reference_mask,
229
+ need_weights=False,
230
+ )
231
+ consensus = F.normalize(consensus[:, 0], dim=-1)
232
+ reread, factors = self.encode_images_with_factors(
233
+ full_features.flatten(0, 1),
234
+ face_features=flat_face,
235
+ face_mask=flat_face_mask,
236
+ anima_features=flat_anima,
237
+ conditioning=consensus[:, None].expand(-1, references, -1).reshape(batch * references, -1),
238
+ )
239
+ reread = reread.reshape(batch, references, -1)
240
+ factors = None if factors is None else factors.reshape(batch, references, 4, -1)
241
+ agreement = F.cosine_similarity(reread, consensus[:, None], dim=-1)
242
+ centered = agreement - (
243
+ (agreement * reference_mask).sum(1, keepdim=True)
244
+ / reference_mask.sum(1, keepdim=True).clamp_min(1)
245
+ )
246
+ weights = (1.0 + 0.25 * torch.tanh(4.0 * centered)) * reference_mask
247
+ grounded = F.normalize((reread * weights[..., None]).sum(1) / weights.sum(1, keepdim=True), dim=-1)
248
+ gamma = torch.sigmoid(self.consensus_gamma)
249
+ return F.normalize(base + gamma * (grounded - base), dim=-1), reread, factors
250
+
251
+ def functional_response_loss(self, factor_codes: Tensor, full_features: Tensor) -> Tensor:
252
+ """Reconstruct artist response after removing a shared prompt/seed cell mean."""
253
+ if not self.functional_factors:
254
+ return full_features.new_zeros(())
255
+ groups = ((2, 3, 4, 5), (0, 6, 24), tuple(range(8, 24)), (1, 7, 25))
256
+ losses = []
257
+ for index, token_indices in enumerate(groups):
258
+ teacher = full_features[..., list(token_indices), :].float().mean(dim=-2)
259
+ teacher = F.normalize(teacher - teacher.mean(dim=1, keepdim=True), dim=-1)
260
+ prediction = F.normalize(self.factor_decoders[index](factor_codes[..., index, :]).float(), dim=-1)
261
+ losses.append((1.0 - F.cosine_similarity(prediction, teacher, dim=-1)).mean())
262
+ return torch.stack(losses).mean()
263
+
264
+ def forward(
265
+ self,
266
+ full_features: Tensor,
267
+ reference_mask: Tensor,
268
+ *,
269
+ face_features: Tensor | None = None,
270
+ face_mask: Tensor | None = None,
271
+ anima_features: Tensor | None = None,
272
+ ) -> tuple[Tensor, Tensor]:
273
+ if full_features.ndim != 4 or full_features.shape[2] != self.external_tokens:
274
+ raise ValueError("full_features must have shape [batch,references,external_tokens,width]")
275
+ batch, references = full_features.shape[:2]
276
+ if reference_mask.shape != (batch, references):
277
+ raise ValueError("reference_mask shape does not match full_features")
278
+
279
+ prototype, per_image, _ = self.encode_reference_sets(
280
+ full_features,
281
+ reference_mask,
282
+ face_features=face_features,
283
+ face_mask=face_mask,
284
+ anima_features=anima_features,
285
+ )
286
+ return prototype, per_image
287
+
288
+
289
+ class AngularPrototypeLoss(nn.Module):
290
+ """Episode prototype softmax with an optional ArcFace-style positive margin."""
291
+
292
+ def __init__(
293
+ self, initial_scale: float = 10.0, initial_bias: float | None = None
294
+ ) -> None:
295
+ super().__init__()
296
+ if initial_scale <= 0:
297
+ raise ValueError("initial_scale must be positive")
298
+ self.raw_scale = nn.Parameter(torch.tensor(math.log(math.expm1(initial_scale))))
299
+ # initial_bias remains accepted for feasibility-script compatibility. A
300
+ # common softmax bias is a no-op and is not a trainable production parameter.
301
+
302
+ def forward(
303
+ self,
304
+ queries: Tensor,
305
+ prototypes: Tensor,
306
+ targets: Tensor,
307
+ *,
308
+ margin: float = 0.0,
309
+ ) -> tuple[Tensor, Tensor]:
310
+ if queries.ndim < 2 or prototypes.ndim != queries.ndim:
311
+ raise ValueError("queries and prototypes must have matching [episode,...,width] ranks")
312
+ if queries.shape[:-2] != prototypes.shape[:-2] or queries.shape[-1] != prototypes.shape[-1]:
313
+ raise ValueError("queries and prototypes must have matching episode axes and widths")
314
+ if targets.shape != queries.shape[:-1]:
315
+ raise ValueError("targets must contain one class index per query")
316
+ # Autocast can round a near-perfect BF16 cosine to exactly one. ArcFace's
317
+ # sqrt(1-cos²) derivative is then singular, so margin math and CE stay FP32.
318
+ cosine = (
319
+ F.normalize(queries, dim=-1)
320
+ @ F.normalize(prototypes, dim=-1).transpose(-1, -2)
321
+ ).float()
322
+ loss_cosine = cosine
323
+ if margin:
324
+ if not 0.0 <= margin < math.pi / 2:
325
+ raise ValueError("margin must be in [0, pi/2)")
326
+ positive = cosine.gather(-1, targets.unsqueeze(-1)).clamp(-1 + 1e-6, 1 - 1e-6)
327
+ positive_margin = positive * math.cos(margin) - torch.sqrt(1 - positive.square()) * math.sin(margin)
328
+ loss_cosine = cosine.scatter(-1, targets.unsqueeze(-1), positive_margin)
329
+ scale = F.softplus(self.raw_scale).clamp_max(100.0)
330
+ loss_logits = scale * loss_cosine
331
+ metric_logits = scale * cosine
332
+ return (
333
+ F.cross_entropy(loss_logits.flatten(0, -2), targets.flatten()),
334
+ metric_logits,
335
+ )
336
+
337
+
338
+ def subset_consistency_loss(first: Tensor, second: Tensor) -> Tensor:
339
+ if first.shape != second.shape or first.ndim != 2:
340
+ raise ValueError("subset prototypes must have equal [batch,width] shapes")
341
+ return (1.0 - F.cosine_similarity(first, second, dim=-1)).mean()
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ torch>=2.4
2
+ safetensors>=0.4
3
+ huggingface_hub>=0.28