TuWaveGod commited on
Commit
c35c7ce
·
verified ·
1 Parent(s): abf1905

Publish two-stage final LoRA adapters and inference guide

Browse files
README.md ADDED
@@ -0,0 +1,235 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ base_model: HuggingFaceTB/SmolVLM2-2.2B-Instruct
4
+ library_name: peft
5
+ pipeline_tag: image-text-to-text
6
+ tags:
7
+ - smolvlm2
8
+ - peft
9
+ - lora
10
+ - visual-ranking
11
+ - playing-card
12
+ - puzzle
13
+ language:
14
+ - en
15
+ ---
16
+
17
+ # Puker_Judge
18
+
19
+ `Puker_Judge` 是基于
20
+ [`HuggingFaceTB/SmolVLM2-2.2B-Instruct`](https://huggingface.co/HuggingFaceTB/SmolVLM2-2.2B-Instruct)
21
+ 微调的两阶段扑克牌拼接候选判断模型。
22
+
23
+ 本仓库发布的是两个 PEFT LoRA adapter,而不是重复上传两份基础模型:
24
+
25
+ - `binary_adapter/`:判断一张已经拼好的候选牌面是 `VALID` 还是 `INVALID`。
26
+ - `rank_adapter/`:从同一组碎片产生的 2–4 个几何可行候选中选择图案最连贯的一个。
27
+ - `processor/`:训练时使用的 SmolVLM2 processor 和 tokenizer。
28
+
29
+ 第二阶段由第一阶段权重初始化后继续训练,但推理时不要同时叠加两个
30
+ adapter。做单候选判断时加载 `binary_adapter`,做多候选选择时加载
31
+ `rank_adapter`。
32
+
33
+ ## 能做什么
34
+
35
+ 这两个模型只负责视觉判断,不负责枚举几何拼法,也不直接输出机械臂坐标:
36
+
37
+ 1. CV/几何算法检测碎片并枚举能够填满目标矩形的候选拼法;
38
+ 2. 候选只有一个时,可用 `binary_adapter` 判断其图案是否合理;
39
+ 3. 候选有 2–4 个时,用 `rank_adapter` 选择最佳候选;
40
+ 4. 候选超过4个时,先去重或使用 `binary_adapter` 逐张筛选到 Top-4,再交给
41
+ `rank_adapter`。
42
+
43
+ ## 安装
44
+
45
+ BF16:
46
+
47
+ ```bash
48
+ python -m venv .venv
49
+ source .venv/bin/activate
50
+ pip install -r requirements.txt
51
+ ```
52
+
53
+ 在 Linux x86-64 NVIDIA GPU 上使用 bitsandbytes INT4:
54
+
55
+ ```bash
56
+ pip install -r requirements-int4.txt
57
+ ```
58
+
59
+ INT4主要建议用于 `rank_adapter`。实测中,rank adapter 在Joker三候选顺序
60
+ 轮换上保持了BF16的判断;但 binary adapter 的一个测试集VALID样本在INT4下翻转
61
+ 成了INVALID。因此单候选二分类默认应使用BF16,除非已经在自己的数据上重新验证
62
+ INT4准确率。
63
+
64
+ ## 输入图像规范
65
+
66
+ ### 单候选二分类
67
+
68
+ 输入一张透视矫正后的完整候选牌面:
69
+
70
+ - 推荐规范尺寸:`600×360` 像素,对应物理尺寸比例 `100:60`;
71
+ - 牌面应紧密裁剪,尽量删除桌面、机械臂、阴影和大面积背景;
72
+ - 所有碎片必须位于同一个目标矩形内;
73
+ - 整张牌旋转180°仍视为同一个正确答案;
74
+ - 不要添加候选编号或多选题边框。
75
+
76
+ ### 多候选排序 board
77
+
78
+ 模型实际接收的是一张包含所有选项的 board,而不是多张独立图片。
79
+
80
+ - board:`1280×820`;
81
+ - 固定2列×2行布局;
82
+ - 选项数必须是 `2、3或4`,不能超过4;
83
+ - 每个候选先规范化为 `600×360`;
84
+ - 标签必须为连续数字 `1, 2, 3, 4`,放在候选图外部;
85
+ - 少于4个选项时,未使用的格子保持空白;
86
+ - 所有候选必须来自同一张牌、同一组碎片,并且在几何上都可行;
87
+ - 各候选应使用相同的裁剪、尺度、背景和成像处理,避免让模型利用无关差异。
88
+
89
+ `infer_rank.py` 可以接收2–4张候选图并自动生成符合训练格式的 board。
90
+
91
+ ## Prompt
92
+
93
+ 建议保持训练时的英文 prompt,不要随意改写。
94
+
95
+ ### 二分类 prompt
96
+
97
+ ```text
98
+ Judge whether this geometrically assembled playing card has coherent rank, suit, border, portrait, symbols, and continuous artwork. A whole-card 180-degree rotation is valid. Answer VALID or INVALID only.
99
+ ```
100
+
101
+ 输出只能是:
102
+
103
+ ```text
104
+ VALID
105
+ ```
106
+
107
+ 或:
108
+
109
+ ```text
110
+ INVALID
111
+ ```
112
+
113
+ ### 多候选排序 prompt
114
+
115
+ 下面的 `{labels}` 要根据选项数生成,例如3个候选就是 `1, 2, 3`:
116
+
117
+ ```text
118
+ All displayed candidates are geometrically valid reconstructions made from the same playing-card pieces. Select the candidate whose rank, suit, outer border, portrait, symbols, and line artwork form one coherent original playing card. A whole-card 180-degree rotation is equivalent. The available labels are {labels}. Answer with one label only.
119
+ ```
120
+
121
+ 输出只能是一个候选编号。
122
+
123
+ ## 使用方法
124
+
125
+ ### 单独判断一个候选的正误
126
+
127
+ BF16:
128
+
129
+ ```bash
130
+ python infer_binary.py candidate.jpg
131
+ ```
132
+
133
+ INT4 NF4(实验性,binary默认推荐BF16):
134
+
135
+ ```bash
136
+ python infer_binary.py candidate.jpg --int4
137
+ ```
138
+
139
+ 输出示例:
140
+
141
+ ```json
142
+ {
143
+ "prediction": "VALID",
144
+ "raw_output": "VALID",
145
+ "quantization": "int4-nf4"
146
+ }
147
+ ```
148
+
149
+ ### 从2–4张候选图中选择
150
+
151
+ 脚本会自动生成 `candidate_board.jpg`:
152
+
153
+ ```bash
154
+ python infer_rank.py \
155
+ candidate_1.jpg \
156
+ candidate_2.jpg \
157
+ candidate_3.jpg \
158
+ --board-output candidate_board.jpg \
159
+ --int4
160
+ ```
161
+
162
+ 输出示例:
163
+
164
+ ```json
165
+ {
166
+ "selected_label": 2,
167
+ "selected_file": "/path/to/candidate_2.jpg",
168
+ "candidate_count": 3
169
+ }
170
+ ```
171
+
172
+ 如果已经自行生成了 board:
173
+
174
+ ```bash
175
+ python infer_rank.py \
176
+ --board-image candidate_board.jpg \
177
+ --candidate-count 3 \
178
+ --int4
179
+ ```
180
+
181
+ ## 直接用 Transformers + PEFT 加载
182
+
183
+ ```python
184
+ from pathlib import Path
185
+
186
+ import torch
187
+ from huggingface_hub import snapshot_download
188
+ from peft import PeftModel
189
+ from transformers import AutoModelForImageTextToText, AutoProcessor
190
+
191
+ repo_dir = Path(snapshot_download("TuWaveGod/Puker_Judge"))
192
+ processor = AutoProcessor.from_pretrained(repo_dir / "processor")
193
+ base = AutoModelForImageTextToText.from_pretrained(
194
+ "HuggingFaceTB/SmolVLM2-2.2B-Instruct",
195
+ torch_dtype=torch.bfloat16,
196
+ ).to("cuda")
197
+ model = PeftModel.from_pretrained(
198
+ base,
199
+ repo_dir / "rank_adapter",
200
+ ).eval()
201
+ ```
202
+
203
+ ## 训练信息
204
+
205
+ - 基础模型:SmolVLM2-2.2B-Instruct;
206
+ - LoRA:rank 16,alpha 32,dropout 0.05;
207
+ - 最大图像长边:1280;
208
+ - 最大文本长度:2048;
209
+ - rank训练场景:18,000;
210
+ - rank验证/测试场景:各1,000;
211
+ - binary训练样本:33,300;
212
+ - binary验证/测试样本:各1,850;
213
+ - 使用52张标准扑克牌资产,不包含大小王;
214
+ - 训练样本包括普通随机、偏心平行四边形、中心双切、全等对称和近似对称困难样本。
215
+
216
+ ## 已做的实拍检查
217
+
218
+ 模型曾在训练集外的 Joker 实拍候选上进行顺序轮换检查。正确候选分别位于
219
+ 1、2、3号位置时,rank adapter 的原始生成结果分别为1、2、3。使用
220
+ bitsandbytes INT4 NF4 后结果仍保持一致。该结果只是一组定性检查,不应视为完整
221
+ 统计评测。
222
+
223
+ ## 限制
224
+
225
+ - rank adapter 只训练过最多4个选项,禁止直接构造超过4项的大型 board;
226
+ - binary adapter 对INT4量化更敏感,单候选判断默认使用BF16;
227
+ - board内不存在正确答案时,模型仍会被迫选择一个编号;
228
+ - 透视畸变、反光、遮挡、碎片间隙或候选缩放不一致可能影响判断;
229
+ - 模型不保证识别所有未见过的牌面和印刷风格;
230
+ - 输出是视觉判断,不是几何证明,也不是机械臂控制策略;
231
+ - 建议将正确候选轮换到不同board位置重复2–3次,并对原始生成编号投票,以减小位置偏置。
232
+
233
+ ## License
234
+
235
+ 本模型基于 Apache-2.0 许可的 SmolVLM2-2.2B-Instruct。扑克牌源图和训练数据不包含在本仓库中。
SHA256SUMS ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ 6537be03f6fbc4141d3ea86c096ed872e1d5656f5a11c4e3f0d4368ae73ddb73 hf_release/binary_adapter/adapter_model.safetensors
2
+ d2715f57f10feb56f9dc22a79df65f4cad907b77f0f0c2881b110bc92db47197 hf_release/rank_adapter/adapter_model.safetensors
binary_adapter/adapter_config.json ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "alpha_pattern": {},
3
+ "auto_mapping": null,
4
+ "base_model_name_or_path": "HuggingFaceTB/SmolVLM2-2.2B-Instruct",
5
+ "bias": "none",
6
+ "corda_config": null,
7
+ "eva_config": null,
8
+ "exclude_modules": null,
9
+ "fan_in_fan_out": false,
10
+ "inference_mode": true,
11
+ "init_lora_weights": true,
12
+ "layer_replication": null,
13
+ "layers_pattern": null,
14
+ "layers_to_transform": null,
15
+ "loftq_config": {},
16
+ "lora_alpha": 32,
17
+ "lora_bias": false,
18
+ "lora_dropout": 0.05,
19
+ "megatron_config": null,
20
+ "megatron_core": "megatron.core",
21
+ "modules_to_save": null,
22
+ "peft_type": "LORA",
23
+ "r": 16,
24
+ "rank_pattern": {},
25
+ "revision": null,
26
+ "target_modules": [
27
+ "text_model.layers.22.self_attn.v_proj",
28
+ "text_model.layers.3.self_attn.q_proj",
29
+ "text_model.layers.4.self_attn.q_proj",
30
+ "text_model.layers.0.self_attn.q_proj",
31
+ "text_model.layers.12.self_attn.v_proj",
32
+ "text_model.layers.9.self_attn.k_proj",
33
+ "text_model.layers.11.self_attn.q_proj",
34
+ "text_model.layers.15.self_attn.v_proj",
35
+ "text_model.layers.8.self_attn.k_proj",
36
+ "text_model.layers.7.self_attn.k_proj",
37
+ "text_model.layers.18.self_attn.k_proj",
38
+ "o_proj",
39
+ "text_model.layers.11.self_attn.k_proj",
40
+ "text_model.layers.13.self_attn.q_proj",
41
+ "text_model.layers.16.self_attn.q_proj",
42
+ "text_model.layers.20.self_attn.q_proj",
43
+ "text_model.layers.17.self_attn.q_proj",
44
+ "text_model.layers.21.self_attn.v_proj",
45
+ "text_model.layers.12.self_attn.k_proj",
46
+ "text_model.layers.18.self_attn.q_proj",
47
+ "text_model.layers.10.self_attn.v_proj",
48
+ "text_model.layers.23.self_attn.k_proj",
49
+ "text_model.layers.1.self_attn.k_proj",
50
+ "text_model.layers.17.self_attn.k_proj",
51
+ "text_model.layers.19.self_attn.k_proj",
52
+ "text_model.layers.2.self_attn.k_proj",
53
+ "text_model.layers.6.self_attn.k_proj",
54
+ "text_model.layers.9.self_attn.q_proj",
55
+ "text_model.layers.6.self_attn.v_proj",
56
+ "gate_proj",
57
+ "text_model.layers.0.self_attn.k_proj",
58
+ "text_model.layers.16.self_attn.v_proj",
59
+ "text_model.layers.7.self_attn.v_proj",
60
+ "text_model.layers.6.self_attn.q_proj",
61
+ "up_proj",
62
+ "text_model.layers.23.self_attn.v_proj",
63
+ "text_model.layers.10.self_attn.k_proj",
64
+ "text_model.layers.7.self_attn.q_proj",
65
+ "text_model.layers.11.self_attn.v_proj",
66
+ "text_model.layers.3.self_attn.v_proj",
67
+ "text_model.layers.13.self_attn.v_proj",
68
+ "text_model.layers.21.self_attn.k_proj",
69
+ "text_model.layers.3.self_attn.k_proj",
70
+ "text_model.layers.22.self_attn.k_proj",
71
+ "text_model.layers.15.self_attn.q_proj",
72
+ "text_model.layers.1.self_attn.v_proj",
73
+ "text_model.layers.19.self_attn.v_proj",
74
+ "text_model.layers.2.self_attn.v_proj",
75
+ "text_model.layers.1.self_attn.q_proj",
76
+ "text_model.layers.20.self_attn.k_proj",
77
+ "text_model.layers.15.self_attn.k_proj",
78
+ "down_proj",
79
+ "text_model.layers.12.self_attn.q_proj",
80
+ "text_model.layers.16.self_attn.k_proj",
81
+ "text_model.layers.0.self_attn.v_proj",
82
+ "text_model.layers.13.self_attn.k_proj",
83
+ "text_model.layers.14.self_attn.k_proj",
84
+ "text_model.layers.21.self_attn.q_proj",
85
+ "text_model.layers.22.self_attn.q_proj",
86
+ "text_model.layers.18.self_attn.v_proj",
87
+ "text_model.layers.19.self_attn.q_proj",
88
+ "text_model.layers.4.self_attn.k_proj",
89
+ "text_model.layers.5.self_attn.v_proj",
90
+ "text_model.layers.14.self_attn.q_proj",
91
+ "text_model.layers.14.self_attn.v_proj",
92
+ "text_model.layers.2.self_attn.q_proj",
93
+ "text_model.layers.23.self_attn.q_proj",
94
+ "text_model.layers.20.self_attn.v_proj",
95
+ "text_model.layers.9.self_attn.v_proj",
96
+ "text_model.layers.8.self_attn.v_proj",
97
+ "text_model.layers.5.self_attn.q_proj",
98
+ "text_model.layers.10.self_attn.q_proj",
99
+ "text_model.layers.8.self_attn.q_proj",
100
+ "text_model.layers.4.self_attn.v_proj",
101
+ "text_model.layers.17.self_attn.v_proj",
102
+ "text_model.layers.5.self_attn.k_proj"
103
+ ],
104
+ "task_type": "CAUSAL_LM",
105
+ "trainable_token_indices": null,
106
+ "use_dora": false,
107
+ "use_rslora": false
108
+ }
binary_adapter/adapter_model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6537be03f6fbc4141d3ea86c096ed872e1d5656f5a11c4e3f0d4368ae73ddb73
3
+ size 72400072
infer_binary.py ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ from __future__ import annotations
3
+
4
+ import argparse
5
+ import re
6
+ from pathlib import Path
7
+
8
+ from PIL import Image
9
+
10
+ from puker_judge_utils import (
11
+ BASE_MODEL_ID,
12
+ BINARY_PROMPT,
13
+ MODEL_REPO_ID,
14
+ encode_image_prompt,
15
+ generate_answer,
16
+ load_adapter,
17
+ print_json,
18
+ )
19
+
20
+
21
+ def parse_args() -> argparse.Namespace:
22
+ parser = argparse.ArgumentParser(
23
+ description="Judge one assembled playing-card candidate as VALID/INVALID."
24
+ )
25
+ parser.add_argument("image", type=Path)
26
+ parser.add_argument("--repo-id", default=MODEL_REPO_ID)
27
+ parser.add_argument("--base-model-id", default=BASE_MODEL_ID)
28
+ parser.add_argument(
29
+ "--int4",
30
+ action="store_true",
31
+ help="Use bitsandbytes NF4 weights with BF16 compute.",
32
+ )
33
+ return parser.parse_args()
34
+
35
+
36
+ def main() -> None:
37
+ args = parse_args()
38
+ model, processor, device, timings = load_adapter(
39
+ "binary_adapter",
40
+ repo_id=args.repo_id,
41
+ base_model_id=args.base_model_id,
42
+ int4=args.int4,
43
+ )
44
+ with Image.open(args.image) as source:
45
+ image = source.convert("RGB").copy()
46
+ inputs = encode_image_prompt(
47
+ processor,
48
+ image,
49
+ BINARY_PROMPT,
50
+ device,
51
+ )
52
+ raw_output, generation_seconds = generate_answer(
53
+ model,
54
+ processor,
55
+ inputs,
56
+ )
57
+ match = re.search(r"\b(INVALID|VALID)\b", raw_output.upper())
58
+ if match is None:
59
+ raise SystemExit(f"Model returned an invalid answer: {raw_output!r}")
60
+ print_json(
61
+ {
62
+ "prediction": match.group(1),
63
+ "raw_output": raw_output,
64
+ "image": str(args.image.resolve()),
65
+ "quantization": "int4-nf4" if args.int4 else "bf16",
66
+ "generation_seconds": round(generation_seconds, 4),
67
+ **{key: round(value, 4) for key, value in timings.items()},
68
+ }
69
+ )
70
+
71
+
72
+ if __name__ == "__main__":
73
+ main()
infer_rank.py ADDED
@@ -0,0 +1,206 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ from __future__ import annotations
3
+
4
+ import argparse
5
+ import re
6
+ from pathlib import Path
7
+
8
+ from PIL import Image, ImageDraw, ImageFont
9
+
10
+ from puker_judge_utils import (
11
+ BASE_MODEL_ID,
12
+ MODEL_REPO_ID,
13
+ encode_image_prompt,
14
+ generate_answer,
15
+ load_adapter,
16
+ print_json,
17
+ rank_prompt,
18
+ )
19
+
20
+ BOARD_SIZE = (1280, 820)
21
+ CANDIDATE_SIZE = (600, 360)
22
+
23
+
24
+ def parse_args() -> argparse.Namespace:
25
+ parser = argparse.ArgumentParser(
26
+ description="Choose the best of two to four playing-card candidates."
27
+ )
28
+ parser.add_argument(
29
+ "candidates",
30
+ type=Path,
31
+ nargs="*",
32
+ help="Two to four rectified candidate images.",
33
+ )
34
+ parser.add_argument(
35
+ "--board-image",
36
+ type=Path,
37
+ help="Use an already constructed board instead of candidate files.",
38
+ )
39
+ parser.add_argument(
40
+ "--candidate-count",
41
+ type=int,
42
+ help="Required with --board-image; must be between 2 and 4.",
43
+ )
44
+ parser.add_argument(
45
+ "--board-output",
46
+ type=Path,
47
+ default=Path("candidate_board.jpg"),
48
+ )
49
+ parser.add_argument("--repo-id", default=MODEL_REPO_ID)
50
+ parser.add_argument("--base-model-id", default=BASE_MODEL_ID)
51
+ parser.add_argument(
52
+ "--int4",
53
+ action="store_true",
54
+ help="Use bitsandbytes NF4 weights with BF16 compute.",
55
+ )
56
+ return parser.parse_args()
57
+
58
+
59
+ def load_font(size: int) -> ImageFont.ImageFont:
60
+ for path in (
61
+ "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf",
62
+ "DejaVuSans-Bold.ttf",
63
+ ):
64
+ try:
65
+ return ImageFont.truetype(path, size=size)
66
+ except OSError:
67
+ continue
68
+ return ImageFont.load_default()
69
+
70
+
71
+ def build_board(candidate_paths: list[Path]) -> Image.Image:
72
+ count = len(candidate_paths)
73
+ if not 2 <= count <= 4:
74
+ raise ValueError("Provide exactly 2, 3, or 4 candidate images.")
75
+
76
+ board = Image.new("RGB", BOARD_SIZE, (226, 231, 237))
77
+ draw = ImageDraw.Draw(board)
78
+ font = load_font(34)
79
+ outer_margin = 28
80
+ column_gap = 24
81
+ row_gap = 24
82
+ cell_width = (BOARD_SIZE[0] - 2 * outer_margin - column_gap) // 2
83
+ cell_height = (BOARD_SIZE[1] - 2 * outer_margin - row_gap) // 2
84
+ label_height = 46
85
+
86
+ for index, path in enumerate(candidate_paths):
87
+ column = index % 2
88
+ row = index // 2
89
+ x0 = outer_margin + column * (cell_width + column_gap)
90
+ y0 = outer_margin + row * (cell_height + row_gap)
91
+ x1 = x0 + cell_width
92
+ y1 = y0 + cell_height
93
+ draw.rounded_rectangle(
94
+ (x0, y0, x1, y1),
95
+ radius=14,
96
+ fill=(244, 246, 248),
97
+ outline=(178, 184, 192),
98
+ width=2,
99
+ )
100
+ draw.rounded_rectangle(
101
+ (x0 + 12, y0 + 8, x0 + 76, y0 + label_height),
102
+ radius=10,
103
+ fill=(255, 218, 72),
104
+ outline=(45, 48, 52),
105
+ width=2,
106
+ )
107
+ draw.text(
108
+ (x0 + 44, y0 + 8 + label_height // 2),
109
+ str(index + 1),
110
+ font=font,
111
+ fill=(25, 31, 42),
112
+ anchor="mm",
113
+ )
114
+ with Image.open(path) as source:
115
+ candidate = source.convert("RGB").resize(
116
+ CANDIDATE_SIZE,
117
+ Image.Resampling.LANCZOS,
118
+ )
119
+ available_width = cell_width - 36
120
+ available_height = cell_height - label_height - 28
121
+ candidate.thumbnail(
122
+ (available_width, available_height),
123
+ Image.Resampling.LANCZOS,
124
+ )
125
+ paste_x = x0 + (cell_width - candidate.width) // 2
126
+ paste_y = y0 + label_height + (
127
+ cell_height - label_height - candidate.height
128
+ ) // 2
129
+ draw.rectangle(
130
+ (
131
+ paste_x + 4,
132
+ paste_y + 5,
133
+ paste_x + 4 + candidate.width,
134
+ paste_y + 5 + candidate.height,
135
+ ),
136
+ fill=(185, 190, 196),
137
+ )
138
+ board.paste(candidate, (paste_x, paste_y))
139
+ return board
140
+
141
+
142
+ def main() -> None:
143
+ args = parse_args()
144
+ if args.board_image is not None:
145
+ if args.candidates:
146
+ raise SystemExit(
147
+ "Use either candidate files or --board-image, not both."
148
+ )
149
+ if args.candidate_count is None or not 2 <= args.candidate_count <= 4:
150
+ raise SystemExit(
151
+ "--candidate-count 2..4 is required with --board-image."
152
+ )
153
+ with Image.open(args.board_image) as source:
154
+ board = source.convert("RGB").copy()
155
+ candidate_count = args.candidate_count
156
+ candidate_paths: list[Path] = []
157
+ else:
158
+ if args.candidate_count is not None:
159
+ raise SystemExit(
160
+ "--candidate-count is inferred when candidate files are used."
161
+ )
162
+ candidate_paths = args.candidates
163
+ candidate_count = len(candidate_paths)
164
+ board = build_board(candidate_paths)
165
+ args.board_output.parent.mkdir(parents=True, exist_ok=True)
166
+ board.save(args.board_output, "JPEG", quality=96, subsampling=0)
167
+
168
+ model, processor, device, timings = load_adapter(
169
+ "rank_adapter",
170
+ repo_id=args.repo_id,
171
+ base_model_id=args.base_model_id,
172
+ int4=args.int4,
173
+ )
174
+ inputs = encode_image_prompt(
175
+ processor,
176
+ board,
177
+ rank_prompt(candidate_count),
178
+ device,
179
+ )
180
+ raw_output, generation_seconds = generate_answer(
181
+ model,
182
+ processor,
183
+ inputs,
184
+ )
185
+ match = re.search(r"[1-4]", raw_output)
186
+ if match is None or int(match.group(0)) > candidate_count:
187
+ raise SystemExit(f"Model returned an invalid answer: {raw_output!r}")
188
+ label = int(match.group(0))
189
+ payload = {
190
+ "selected_label": label,
191
+ "raw_output": raw_output,
192
+ "candidate_count": candidate_count,
193
+ "quantization": "int4-nf4" if args.int4 else "bf16",
194
+ "generation_seconds": round(generation_seconds, 4),
195
+ **{key: round(value, 4) for key, value in timings.items()},
196
+ }
197
+ if candidate_paths:
198
+ payload["selected_file"] = str(candidate_paths[label - 1].resolve())
199
+ payload["board_image"] = str(args.board_output.resolve())
200
+ else:
201
+ payload["board_image"] = str(args.board_image.resolve())
202
+ print_json(payload)
203
+
204
+
205
+ if __name__ == "__main__":
206
+ main()
processor/added_tokens.json ADDED
@@ -0,0 +1,130 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "<end_of_utterance>": 49279,
3
+ "<fake_token_around_image>": 49189,
4
+ "<global-img>": 49152,
5
+ "<image>": 49190,
6
+ "<row_1_col_1>": 49153,
7
+ "<row_1_col_2>": 49154,
8
+ "<row_1_col_3>": 49155,
9
+ "<row_1_col_4>": 49156,
10
+ "<row_1_col_5>": 49157,
11
+ "<row_1_col_6>": 49158,
12
+ "<row_2_col_1>": 49159,
13
+ "<row_2_col_2>": 49160,
14
+ "<row_2_col_3>": 49161,
15
+ "<row_2_col_4>": 49162,
16
+ "<row_2_col_5>": 49163,
17
+ "<row_2_col_6>": 49164,
18
+ "<row_3_col_1>": 49165,
19
+ "<row_3_col_2>": 49166,
20
+ "<row_3_col_3>": 49167,
21
+ "<row_3_col_4>": 49168,
22
+ "<row_3_col_5>": 49169,
23
+ "<row_3_col_6>": 49170,
24
+ "<row_4_col_1>": 49171,
25
+ "<row_4_col_2>": 49172,
26
+ "<row_4_col_3>": 49173,
27
+ "<row_4_col_4>": 49174,
28
+ "<row_4_col_5>": 49175,
29
+ "<row_4_col_6>": 49176,
30
+ "<row_5_col_1>": 49177,
31
+ "<row_5_col_2>": 49178,
32
+ "<row_5_col_3>": 49179,
33
+ "<row_5_col_4>": 49180,
34
+ "<row_5_col_5>": 49181,
35
+ "<row_5_col_6>": 49182,
36
+ "<row_6_col_1>": 49183,
37
+ "<row_6_col_2>": 49184,
38
+ "<row_6_col_3>": 49185,
39
+ "<row_6_col_4>": 49186,
40
+ "<row_6_col_5>": 49187,
41
+ "<row_6_col_6>": 49188,
42
+ "<|reserved_special_token_0|>": 49191,
43
+ "<|reserved_special_token_10|>": 49201,
44
+ "<|reserved_special_token_11|>": 49202,
45
+ "<|reserved_special_token_12|>": 49203,
46
+ "<|reserved_special_token_13|>": 49204,
47
+ "<|reserved_special_token_14|>": 49205,
48
+ "<|reserved_special_token_15|>": 49206,
49
+ "<|reserved_special_token_16|>": 49207,
50
+ "<|reserved_special_token_17|>": 49208,
51
+ "<|reserved_special_token_18|>": 49209,
52
+ "<|reserved_special_token_19|>": 49210,
53
+ "<|reserved_special_token_1|>": 49192,
54
+ "<|reserved_special_token_20|>": 49211,
55
+ "<|reserved_special_token_21|>": 49212,
56
+ "<|reserved_special_token_22|>": 49213,
57
+ "<|reserved_special_token_23|>": 49214,
58
+ "<|reserved_special_token_24|>": 49215,
59
+ "<|reserved_special_token_25|>": 49216,
60
+ "<|reserved_special_token_26|>": 49217,
61
+ "<|reserved_special_token_27|>": 49218,
62
+ "<|reserved_special_token_28|>": 49219,
63
+ "<|reserved_special_token_29|>": 49220,
64
+ "<|reserved_special_token_2|>": 49193,
65
+ "<|reserved_special_token_30|>": 49221,
66
+ "<|reserved_special_token_31|>": 49222,
67
+ "<|reserved_special_token_32|>": 49223,
68
+ "<|reserved_special_token_33|>": 49224,
69
+ "<|reserved_special_token_34|>": 49225,
70
+ "<|reserved_special_token_35|>": 49226,
71
+ "<|reserved_special_token_36|>": 49227,
72
+ "<|reserved_special_token_37|>": 49228,
73
+ "<|reserved_special_token_38|>": 49229,
74
+ "<|reserved_special_token_39|>": 49230,
75
+ "<|reserved_special_token_3|>": 49194,
76
+ "<|reserved_special_token_40|>": 49231,
77
+ "<|reserved_special_token_41|>": 49232,
78
+ "<|reserved_special_token_42|>": 49233,
79
+ "<|reserved_special_token_43|>": 49234,
80
+ "<|reserved_special_token_44|>": 49235,
81
+ "<|reserved_special_token_45|>": 49236,
82
+ "<|reserved_special_token_46|>": 49237,
83
+ "<|reserved_special_token_47|>": 49238,
84
+ "<|reserved_special_token_48|>": 49239,
85
+ "<|reserved_special_token_49|>": 49240,
86
+ "<|reserved_special_token_4|>": 49195,
87
+ "<|reserved_special_token_50|>": 49241,
88
+ "<|reserved_special_token_51|>": 49242,
89
+ "<|reserved_special_token_52|>": 49243,
90
+ "<|reserved_special_token_53|>": 49244,
91
+ "<|reserved_special_token_54|>": 49245,
92
+ "<|reserved_special_token_55|>": 49246,
93
+ "<|reserved_special_token_56|>": 49247,
94
+ "<|reserved_special_token_57|>": 49248,
95
+ "<|reserved_special_token_58|>": 49249,
96
+ "<|reserved_special_token_59|>": 49250,
97
+ "<|reserved_special_token_5|>": 49196,
98
+ "<|reserved_special_token_60|>": 49251,
99
+ "<|reserved_special_token_61|>": 49252,
100
+ "<|reserved_special_token_62|>": 49253,
101
+ "<|reserved_special_token_63|>": 49254,
102
+ "<|reserved_special_token_64|>": 49255,
103
+ "<|reserved_special_token_65|>": 49256,
104
+ "<|reserved_special_token_66|>": 49257,
105
+ "<|reserved_special_token_67|>": 49258,
106
+ "<|reserved_special_token_68|>": 49259,
107
+ "<|reserved_special_token_69|>": 49260,
108
+ "<|reserved_special_token_6|>": 49197,
109
+ "<|reserved_special_token_70|>": 49261,
110
+ "<|reserved_special_token_71|>": 49262,
111
+ "<|reserved_special_token_72|>": 49263,
112
+ "<|reserved_special_token_73|>": 49264,
113
+ "<|reserved_special_token_74|>": 49265,
114
+ "<|reserved_special_token_75|>": 49266,
115
+ "<|reserved_special_token_76|>": 49267,
116
+ "<|reserved_special_token_77|>": 49268,
117
+ "<|reserved_special_token_78|>": 49269,
118
+ "<|reserved_special_token_79|>": 49270,
119
+ "<|reserved_special_token_7|>": 49198,
120
+ "<|reserved_special_token_80|>": 49271,
121
+ "<|reserved_special_token_81|>": 49272,
122
+ "<|reserved_special_token_82|>": 49273,
123
+ "<|reserved_special_token_83|>": 49274,
124
+ "<|reserved_special_token_84|>": 49275,
125
+ "<|reserved_special_token_85|>": 49276,
126
+ "<|reserved_special_token_86|>": 49277,
127
+ "<|reserved_special_token_87|>": 49278,
128
+ "<|reserved_special_token_8|>": 49199,
129
+ "<|reserved_special_token_9|>": 49200
130
+ }
processor/chat_template.jinja ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ <|im_start|>{% for message in messages %}{{message['role'] | capitalize}}{% if message['content'][0]['type'] == 'image' %}{{':'}}{% else %}{{': '}}{% endif %}{% for line in message['content'] %}{% if line['type'] == 'text' %}{{line['text']}}{% elif line['type'] == 'image' %}{{ '<image>' }}{% endif %}{% endfor %}<end_of_utterance>
2
+ {% endfor %}{% if add_generation_prompt %}{{ 'Assistant:' }}{% endif %}
processor/merges.txt ADDED
The diff for this file is too large to render. See raw diff
 
processor/preprocessor_config.json ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "do_convert_rgb": true,
3
+ "do_image_splitting": true,
4
+ "do_normalize": true,
5
+ "do_pad": true,
6
+ "do_rescale": true,
7
+ "do_resize": true,
8
+ "image_mean": [
9
+ 0.5,
10
+ 0.5,
11
+ 0.5
12
+ ],
13
+ "image_processor_type": "SmolVLMImageProcessor",
14
+ "image_std": [
15
+ 0.5,
16
+ 0.5,
17
+ 0.5
18
+ ],
19
+ "max_image_size": {
20
+ "longest_edge": 384
21
+ },
22
+ "processor_class": "SmolVLMProcessor",
23
+ "resample": 1,
24
+ "rescale_factor": 0.00392156862745098,
25
+ "size": {
26
+ "longest_edge": 1536
27
+ },
28
+ "video_sampling": {
29
+ "fps": 1,
30
+ "max_frames": 64,
31
+ "video_size": {
32
+ "longest_edge": 384
33
+ }
34
+ }
35
+ }
processor/processor_config.json ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ {
2
+ "image_seq_len": 81,
3
+ "processor_class": "SmolVLMProcessor"
4
+ }
processor/special_tokens_map.json ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "additional_special_tokens": [
3
+ "<fake_token_around_image>",
4
+ "<image>",
5
+ "<end_of_utterance>"
6
+ ],
7
+ "bos_token": {
8
+ "content": "<|im_start|>",
9
+ "lstrip": false,
10
+ "normalized": false,
11
+ "rstrip": false,
12
+ "single_word": false
13
+ },
14
+ "end_of_utterance_token": "<end_of_utterance>",
15
+ "eos_token": {
16
+ "content": "<end_of_utterance>",
17
+ "lstrip": false,
18
+ "normalized": false,
19
+ "rstrip": false,
20
+ "single_word": false
21
+ },
22
+ "fake_image_token": "<fake_token_around_image>",
23
+ "global_image_token": "<global-img>",
24
+ "image_token": "<image>",
25
+ "pad_token": {
26
+ "content": "<|im_end|>",
27
+ "lstrip": false,
28
+ "normalized": false,
29
+ "rstrip": false,
30
+ "single_word": false
31
+ },
32
+ "unk_token": {
33
+ "content": "<|endoftext|>",
34
+ "lstrip": false,
35
+ "normalized": false,
36
+ "rstrip": false,
37
+ "single_word": false
38
+ }
39
+ }
processor/tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
processor/tokenizer_config.json ADDED
@@ -0,0 +1,1191 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "add_prefix_space": false,
3
+ "added_tokens_decoder": {
4
+ "0": {
5
+ "content": "<|endoftext|>",
6
+ "lstrip": false,
7
+ "normalized": false,
8
+ "rstrip": false,
9
+ "single_word": false,
10
+ "special": true
11
+ },
12
+ "1": {
13
+ "content": "<|im_start|>",
14
+ "lstrip": false,
15
+ "normalized": false,
16
+ "rstrip": false,
17
+ "single_word": false,
18
+ "special": true
19
+ },
20
+ "2": {
21
+ "content": "<|im_end|>",
22
+ "lstrip": false,
23
+ "normalized": false,
24
+ "rstrip": false,
25
+ "single_word": false,
26
+ "special": true
27
+ },
28
+ "3": {
29
+ "content": "<repo_name>",
30
+ "lstrip": false,
31
+ "normalized": false,
32
+ "rstrip": false,
33
+ "single_word": false,
34
+ "special": true
35
+ },
36
+ "4": {
37
+ "content": "<reponame>",
38
+ "lstrip": false,
39
+ "normalized": false,
40
+ "rstrip": false,
41
+ "single_word": false,
42
+ "special": true
43
+ },
44
+ "5": {
45
+ "content": "<file_sep>",
46
+ "lstrip": false,
47
+ "normalized": false,
48
+ "rstrip": false,
49
+ "single_word": false,
50
+ "special": true
51
+ },
52
+ "6": {
53
+ "content": "<filename>",
54
+ "lstrip": false,
55
+ "normalized": false,
56
+ "rstrip": false,
57
+ "single_word": false,
58
+ "special": true
59
+ },
60
+ "7": {
61
+ "content": "<gh_stars>",
62
+ "lstrip": false,
63
+ "normalized": false,
64
+ "rstrip": false,
65
+ "single_word": false,
66
+ "special": true
67
+ },
68
+ "8": {
69
+ "content": "<issue_start>",
70
+ "lstrip": false,
71
+ "normalized": false,
72
+ "rstrip": false,
73
+ "single_word": false,
74
+ "special": true
75
+ },
76
+ "9": {
77
+ "content": "<issue_comment>",
78
+ "lstrip": false,
79
+ "normalized": false,
80
+ "rstrip": false,
81
+ "single_word": false,
82
+ "special": true
83
+ },
84
+ "10": {
85
+ "content": "<issue_closed>",
86
+ "lstrip": false,
87
+ "normalized": false,
88
+ "rstrip": false,
89
+ "single_word": false,
90
+ "special": true
91
+ },
92
+ "11": {
93
+ "content": "<jupyter_start>",
94
+ "lstrip": false,
95
+ "normalized": false,
96
+ "rstrip": false,
97
+ "single_word": false,
98
+ "special": true
99
+ },
100
+ "12": {
101
+ "content": "<jupyter_text>",
102
+ "lstrip": false,
103
+ "normalized": false,
104
+ "rstrip": false,
105
+ "single_word": false,
106
+ "special": true
107
+ },
108
+ "13": {
109
+ "content": "<jupyter_code>",
110
+ "lstrip": false,
111
+ "normalized": false,
112
+ "rstrip": false,
113
+ "single_word": false,
114
+ "special": true
115
+ },
116
+ "14": {
117
+ "content": "<jupyter_output>",
118
+ "lstrip": false,
119
+ "normalized": false,
120
+ "rstrip": false,
121
+ "single_word": false,
122
+ "special": true
123
+ },
124
+ "15": {
125
+ "content": "<jupyter_script>",
126
+ "lstrip": false,
127
+ "normalized": false,
128
+ "rstrip": false,
129
+ "single_word": false,
130
+ "special": true
131
+ },
132
+ "16": {
133
+ "content": "<empty_output>",
134
+ "lstrip": false,
135
+ "normalized": false,
136
+ "rstrip": false,
137
+ "single_word": false,
138
+ "special": true
139
+ },
140
+ "49152": {
141
+ "content": "<global-img>",
142
+ "lstrip": false,
143
+ "normalized": false,
144
+ "rstrip": false,
145
+ "single_word": false,
146
+ "special": true
147
+ },
148
+ "49153": {
149
+ "content": "<row_1_col_1>",
150
+ "lstrip": false,
151
+ "normalized": false,
152
+ "rstrip": false,
153
+ "single_word": false,
154
+ "special": true
155
+ },
156
+ "49154": {
157
+ "content": "<row_1_col_2>",
158
+ "lstrip": false,
159
+ "normalized": false,
160
+ "rstrip": false,
161
+ "single_word": false,
162
+ "special": true
163
+ },
164
+ "49155": {
165
+ "content": "<row_1_col_3>",
166
+ "lstrip": false,
167
+ "normalized": false,
168
+ "rstrip": false,
169
+ "single_word": false,
170
+ "special": true
171
+ },
172
+ "49156": {
173
+ "content": "<row_1_col_4>",
174
+ "lstrip": false,
175
+ "normalized": false,
176
+ "rstrip": false,
177
+ "single_word": false,
178
+ "special": true
179
+ },
180
+ "49157": {
181
+ "content": "<row_1_col_5>",
182
+ "lstrip": false,
183
+ "normalized": false,
184
+ "rstrip": false,
185
+ "single_word": false,
186
+ "special": true
187
+ },
188
+ "49158": {
189
+ "content": "<row_1_col_6>",
190
+ "lstrip": false,
191
+ "normalized": false,
192
+ "rstrip": false,
193
+ "single_word": false,
194
+ "special": true
195
+ },
196
+ "49159": {
197
+ "content": "<row_2_col_1>",
198
+ "lstrip": false,
199
+ "normalized": false,
200
+ "rstrip": false,
201
+ "single_word": false,
202
+ "special": true
203
+ },
204
+ "49160": {
205
+ "content": "<row_2_col_2>",
206
+ "lstrip": false,
207
+ "normalized": false,
208
+ "rstrip": false,
209
+ "single_word": false,
210
+ "special": true
211
+ },
212
+ "49161": {
213
+ "content": "<row_2_col_3>",
214
+ "lstrip": false,
215
+ "normalized": false,
216
+ "rstrip": false,
217
+ "single_word": false,
218
+ "special": true
219
+ },
220
+ "49162": {
221
+ "content": "<row_2_col_4>",
222
+ "lstrip": false,
223
+ "normalized": false,
224
+ "rstrip": false,
225
+ "single_word": false,
226
+ "special": true
227
+ },
228
+ "49163": {
229
+ "content": "<row_2_col_5>",
230
+ "lstrip": false,
231
+ "normalized": false,
232
+ "rstrip": false,
233
+ "single_word": false,
234
+ "special": true
235
+ },
236
+ "49164": {
237
+ "content": "<row_2_col_6>",
238
+ "lstrip": false,
239
+ "normalized": false,
240
+ "rstrip": false,
241
+ "single_word": false,
242
+ "special": true
243
+ },
244
+ "49165": {
245
+ "content": "<row_3_col_1>",
246
+ "lstrip": false,
247
+ "normalized": false,
248
+ "rstrip": false,
249
+ "single_word": false,
250
+ "special": true
251
+ },
252
+ "49166": {
253
+ "content": "<row_3_col_2>",
254
+ "lstrip": false,
255
+ "normalized": false,
256
+ "rstrip": false,
257
+ "single_word": false,
258
+ "special": true
259
+ },
260
+ "49167": {
261
+ "content": "<row_3_col_3>",
262
+ "lstrip": false,
263
+ "normalized": false,
264
+ "rstrip": false,
265
+ "single_word": false,
266
+ "special": true
267
+ },
268
+ "49168": {
269
+ "content": "<row_3_col_4>",
270
+ "lstrip": false,
271
+ "normalized": false,
272
+ "rstrip": false,
273
+ "single_word": false,
274
+ "special": true
275
+ },
276
+ "49169": {
277
+ "content": "<row_3_col_5>",
278
+ "lstrip": false,
279
+ "normalized": false,
280
+ "rstrip": false,
281
+ "single_word": false,
282
+ "special": true
283
+ },
284
+ "49170": {
285
+ "content": "<row_3_col_6>",
286
+ "lstrip": false,
287
+ "normalized": false,
288
+ "rstrip": false,
289
+ "single_word": false,
290
+ "special": true
291
+ },
292
+ "49171": {
293
+ "content": "<row_4_col_1>",
294
+ "lstrip": false,
295
+ "normalized": false,
296
+ "rstrip": false,
297
+ "single_word": false,
298
+ "special": true
299
+ },
300
+ "49172": {
301
+ "content": "<row_4_col_2>",
302
+ "lstrip": false,
303
+ "normalized": false,
304
+ "rstrip": false,
305
+ "single_word": false,
306
+ "special": true
307
+ },
308
+ "49173": {
309
+ "content": "<row_4_col_3>",
310
+ "lstrip": false,
311
+ "normalized": false,
312
+ "rstrip": false,
313
+ "single_word": false,
314
+ "special": true
315
+ },
316
+ "49174": {
317
+ "content": "<row_4_col_4>",
318
+ "lstrip": false,
319
+ "normalized": false,
320
+ "rstrip": false,
321
+ "single_word": false,
322
+ "special": true
323
+ },
324
+ "49175": {
325
+ "content": "<row_4_col_5>",
326
+ "lstrip": false,
327
+ "normalized": false,
328
+ "rstrip": false,
329
+ "single_word": false,
330
+ "special": true
331
+ },
332
+ "49176": {
333
+ "content": "<row_4_col_6>",
334
+ "lstrip": false,
335
+ "normalized": false,
336
+ "rstrip": false,
337
+ "single_word": false,
338
+ "special": true
339
+ },
340
+ "49177": {
341
+ "content": "<row_5_col_1>",
342
+ "lstrip": false,
343
+ "normalized": false,
344
+ "rstrip": false,
345
+ "single_word": false,
346
+ "special": true
347
+ },
348
+ "49178": {
349
+ "content": "<row_5_col_2>",
350
+ "lstrip": false,
351
+ "normalized": false,
352
+ "rstrip": false,
353
+ "single_word": false,
354
+ "special": true
355
+ },
356
+ "49179": {
357
+ "content": "<row_5_col_3>",
358
+ "lstrip": false,
359
+ "normalized": false,
360
+ "rstrip": false,
361
+ "single_word": false,
362
+ "special": true
363
+ },
364
+ "49180": {
365
+ "content": "<row_5_col_4>",
366
+ "lstrip": false,
367
+ "normalized": false,
368
+ "rstrip": false,
369
+ "single_word": false,
370
+ "special": true
371
+ },
372
+ "49181": {
373
+ "content": "<row_5_col_5>",
374
+ "lstrip": false,
375
+ "normalized": false,
376
+ "rstrip": false,
377
+ "single_word": false,
378
+ "special": true
379
+ },
380
+ "49182": {
381
+ "content": "<row_5_col_6>",
382
+ "lstrip": false,
383
+ "normalized": false,
384
+ "rstrip": false,
385
+ "single_word": false,
386
+ "special": true
387
+ },
388
+ "49183": {
389
+ "content": "<row_6_col_1>",
390
+ "lstrip": false,
391
+ "normalized": false,
392
+ "rstrip": false,
393
+ "single_word": false,
394
+ "special": true
395
+ },
396
+ "49184": {
397
+ "content": "<row_6_col_2>",
398
+ "lstrip": false,
399
+ "normalized": false,
400
+ "rstrip": false,
401
+ "single_word": false,
402
+ "special": true
403
+ },
404
+ "49185": {
405
+ "content": "<row_6_col_3>",
406
+ "lstrip": false,
407
+ "normalized": false,
408
+ "rstrip": false,
409
+ "single_word": false,
410
+ "special": true
411
+ },
412
+ "49186": {
413
+ "content": "<row_6_col_4>",
414
+ "lstrip": false,
415
+ "normalized": false,
416
+ "rstrip": false,
417
+ "single_word": false,
418
+ "special": true
419
+ },
420
+ "49187": {
421
+ "content": "<row_6_col_5>",
422
+ "lstrip": false,
423
+ "normalized": false,
424
+ "rstrip": false,
425
+ "single_word": false,
426
+ "special": true
427
+ },
428
+ "49188": {
429
+ "content": "<row_6_col_6>",
430
+ "lstrip": false,
431
+ "normalized": false,
432
+ "rstrip": false,
433
+ "single_word": false,
434
+ "special": true
435
+ },
436
+ "49189": {
437
+ "content": "<fake_token_around_image>",
438
+ "lstrip": false,
439
+ "normalized": false,
440
+ "rstrip": false,
441
+ "single_word": false,
442
+ "special": true
443
+ },
444
+ "49190": {
445
+ "content": "<image>",
446
+ "lstrip": false,
447
+ "normalized": false,
448
+ "rstrip": false,
449
+ "single_word": false,
450
+ "special": true
451
+ },
452
+ "49191": {
453
+ "content": "<|reserved_special_token_0|>",
454
+ "lstrip": false,
455
+ "normalized": false,
456
+ "rstrip": false,
457
+ "single_word": false,
458
+ "special": true
459
+ },
460
+ "49192": {
461
+ "content": "<|reserved_special_token_1|>",
462
+ "lstrip": false,
463
+ "normalized": false,
464
+ "rstrip": false,
465
+ "single_word": false,
466
+ "special": true
467
+ },
468
+ "49193": {
469
+ "content": "<|reserved_special_token_2|>",
470
+ "lstrip": false,
471
+ "normalized": false,
472
+ "rstrip": false,
473
+ "single_word": false,
474
+ "special": true
475
+ },
476
+ "49194": {
477
+ "content": "<|reserved_special_token_3|>",
478
+ "lstrip": false,
479
+ "normalized": false,
480
+ "rstrip": false,
481
+ "single_word": false,
482
+ "special": true
483
+ },
484
+ "49195": {
485
+ "content": "<|reserved_special_token_4|>",
486
+ "lstrip": false,
487
+ "normalized": false,
488
+ "rstrip": false,
489
+ "single_word": false,
490
+ "special": true
491
+ },
492
+ "49196": {
493
+ "content": "<|reserved_special_token_5|>",
494
+ "lstrip": false,
495
+ "normalized": false,
496
+ "rstrip": false,
497
+ "single_word": false,
498
+ "special": true
499
+ },
500
+ "49197": {
501
+ "content": "<|reserved_special_token_6|>",
502
+ "lstrip": false,
503
+ "normalized": false,
504
+ "rstrip": false,
505
+ "single_word": false,
506
+ "special": true
507
+ },
508
+ "49198": {
509
+ "content": "<|reserved_special_token_7|>",
510
+ "lstrip": false,
511
+ "normalized": false,
512
+ "rstrip": false,
513
+ "single_word": false,
514
+ "special": true
515
+ },
516
+ "49199": {
517
+ "content": "<|reserved_special_token_8|>",
518
+ "lstrip": false,
519
+ "normalized": false,
520
+ "rstrip": false,
521
+ "single_word": false,
522
+ "special": true
523
+ },
524
+ "49200": {
525
+ "content": "<|reserved_special_token_9|>",
526
+ "lstrip": false,
527
+ "normalized": false,
528
+ "rstrip": false,
529
+ "single_word": false,
530
+ "special": true
531
+ },
532
+ "49201": {
533
+ "content": "<|reserved_special_token_10|>",
534
+ "lstrip": false,
535
+ "normalized": false,
536
+ "rstrip": false,
537
+ "single_word": false,
538
+ "special": true
539
+ },
540
+ "49202": {
541
+ "content": "<|reserved_special_token_11|>",
542
+ "lstrip": false,
543
+ "normalized": false,
544
+ "rstrip": false,
545
+ "single_word": false,
546
+ "special": true
547
+ },
548
+ "49203": {
549
+ "content": "<|reserved_special_token_12|>",
550
+ "lstrip": false,
551
+ "normalized": false,
552
+ "rstrip": false,
553
+ "single_word": false,
554
+ "special": true
555
+ },
556
+ "49204": {
557
+ "content": "<|reserved_special_token_13|>",
558
+ "lstrip": false,
559
+ "normalized": false,
560
+ "rstrip": false,
561
+ "single_word": false,
562
+ "special": true
563
+ },
564
+ "49205": {
565
+ "content": "<|reserved_special_token_14|>",
566
+ "lstrip": false,
567
+ "normalized": false,
568
+ "rstrip": false,
569
+ "single_word": false,
570
+ "special": true
571
+ },
572
+ "49206": {
573
+ "content": "<|reserved_special_token_15|>",
574
+ "lstrip": false,
575
+ "normalized": false,
576
+ "rstrip": false,
577
+ "single_word": false,
578
+ "special": true
579
+ },
580
+ "49207": {
581
+ "content": "<|reserved_special_token_16|>",
582
+ "lstrip": false,
583
+ "normalized": false,
584
+ "rstrip": false,
585
+ "single_word": false,
586
+ "special": true
587
+ },
588
+ "49208": {
589
+ "content": "<|reserved_special_token_17|>",
590
+ "lstrip": false,
591
+ "normalized": false,
592
+ "rstrip": false,
593
+ "single_word": false,
594
+ "special": true
595
+ },
596
+ "49209": {
597
+ "content": "<|reserved_special_token_18|>",
598
+ "lstrip": false,
599
+ "normalized": false,
600
+ "rstrip": false,
601
+ "single_word": false,
602
+ "special": true
603
+ },
604
+ "49210": {
605
+ "content": "<|reserved_special_token_19|>",
606
+ "lstrip": false,
607
+ "normalized": false,
608
+ "rstrip": false,
609
+ "single_word": false,
610
+ "special": true
611
+ },
612
+ "49211": {
613
+ "content": "<|reserved_special_token_20|>",
614
+ "lstrip": false,
615
+ "normalized": false,
616
+ "rstrip": false,
617
+ "single_word": false,
618
+ "special": true
619
+ },
620
+ "49212": {
621
+ "content": "<|reserved_special_token_21|>",
622
+ "lstrip": false,
623
+ "normalized": false,
624
+ "rstrip": false,
625
+ "single_word": false,
626
+ "special": true
627
+ },
628
+ "49213": {
629
+ "content": "<|reserved_special_token_22|>",
630
+ "lstrip": false,
631
+ "normalized": false,
632
+ "rstrip": false,
633
+ "single_word": false,
634
+ "special": true
635
+ },
636
+ "49214": {
637
+ "content": "<|reserved_special_token_23|>",
638
+ "lstrip": false,
639
+ "normalized": false,
640
+ "rstrip": false,
641
+ "single_word": false,
642
+ "special": true
643
+ },
644
+ "49215": {
645
+ "content": "<|reserved_special_token_24|>",
646
+ "lstrip": false,
647
+ "normalized": false,
648
+ "rstrip": false,
649
+ "single_word": false,
650
+ "special": true
651
+ },
652
+ "49216": {
653
+ "content": "<|reserved_special_token_25|>",
654
+ "lstrip": false,
655
+ "normalized": false,
656
+ "rstrip": false,
657
+ "single_word": false,
658
+ "special": true
659
+ },
660
+ "49217": {
661
+ "content": "<|reserved_special_token_26|>",
662
+ "lstrip": false,
663
+ "normalized": false,
664
+ "rstrip": false,
665
+ "single_word": false,
666
+ "special": true
667
+ },
668
+ "49218": {
669
+ "content": "<|reserved_special_token_27|>",
670
+ "lstrip": false,
671
+ "normalized": false,
672
+ "rstrip": false,
673
+ "single_word": false,
674
+ "special": true
675
+ },
676
+ "49219": {
677
+ "content": "<|reserved_special_token_28|>",
678
+ "lstrip": false,
679
+ "normalized": false,
680
+ "rstrip": false,
681
+ "single_word": false,
682
+ "special": true
683
+ },
684
+ "49220": {
685
+ "content": "<|reserved_special_token_29|>",
686
+ "lstrip": false,
687
+ "normalized": false,
688
+ "rstrip": false,
689
+ "single_word": false,
690
+ "special": true
691
+ },
692
+ "49221": {
693
+ "content": "<|reserved_special_token_30|>",
694
+ "lstrip": false,
695
+ "normalized": false,
696
+ "rstrip": false,
697
+ "single_word": false,
698
+ "special": true
699
+ },
700
+ "49222": {
701
+ "content": "<|reserved_special_token_31|>",
702
+ "lstrip": false,
703
+ "normalized": false,
704
+ "rstrip": false,
705
+ "single_word": false,
706
+ "special": true
707
+ },
708
+ "49223": {
709
+ "content": "<|reserved_special_token_32|>",
710
+ "lstrip": false,
711
+ "normalized": false,
712
+ "rstrip": false,
713
+ "single_word": false,
714
+ "special": true
715
+ },
716
+ "49224": {
717
+ "content": "<|reserved_special_token_33|>",
718
+ "lstrip": false,
719
+ "normalized": false,
720
+ "rstrip": false,
721
+ "single_word": false,
722
+ "special": true
723
+ },
724
+ "49225": {
725
+ "content": "<|reserved_special_token_34|>",
726
+ "lstrip": false,
727
+ "normalized": false,
728
+ "rstrip": false,
729
+ "single_word": false,
730
+ "special": true
731
+ },
732
+ "49226": {
733
+ "content": "<|reserved_special_token_35|>",
734
+ "lstrip": false,
735
+ "normalized": false,
736
+ "rstrip": false,
737
+ "single_word": false,
738
+ "special": true
739
+ },
740
+ "49227": {
741
+ "content": "<|reserved_special_token_36|>",
742
+ "lstrip": false,
743
+ "normalized": false,
744
+ "rstrip": false,
745
+ "single_word": false,
746
+ "special": true
747
+ },
748
+ "49228": {
749
+ "content": "<|reserved_special_token_37|>",
750
+ "lstrip": false,
751
+ "normalized": false,
752
+ "rstrip": false,
753
+ "single_word": false,
754
+ "special": true
755
+ },
756
+ "49229": {
757
+ "content": "<|reserved_special_token_38|>",
758
+ "lstrip": false,
759
+ "normalized": false,
760
+ "rstrip": false,
761
+ "single_word": false,
762
+ "special": true
763
+ },
764
+ "49230": {
765
+ "content": "<|reserved_special_token_39|>",
766
+ "lstrip": false,
767
+ "normalized": false,
768
+ "rstrip": false,
769
+ "single_word": false,
770
+ "special": true
771
+ },
772
+ "49231": {
773
+ "content": "<|reserved_special_token_40|>",
774
+ "lstrip": false,
775
+ "normalized": false,
776
+ "rstrip": false,
777
+ "single_word": false,
778
+ "special": true
779
+ },
780
+ "49232": {
781
+ "content": "<|reserved_special_token_41|>",
782
+ "lstrip": false,
783
+ "normalized": false,
784
+ "rstrip": false,
785
+ "single_word": false,
786
+ "special": true
787
+ },
788
+ "49233": {
789
+ "content": "<|reserved_special_token_42|>",
790
+ "lstrip": false,
791
+ "normalized": false,
792
+ "rstrip": false,
793
+ "single_word": false,
794
+ "special": true
795
+ },
796
+ "49234": {
797
+ "content": "<|reserved_special_token_43|>",
798
+ "lstrip": false,
799
+ "normalized": false,
800
+ "rstrip": false,
801
+ "single_word": false,
802
+ "special": true
803
+ },
804
+ "49235": {
805
+ "content": "<|reserved_special_token_44|>",
806
+ "lstrip": false,
807
+ "normalized": false,
808
+ "rstrip": false,
809
+ "single_word": false,
810
+ "special": true
811
+ },
812
+ "49236": {
813
+ "content": "<|reserved_special_token_45|>",
814
+ "lstrip": false,
815
+ "normalized": false,
816
+ "rstrip": false,
817
+ "single_word": false,
818
+ "special": true
819
+ },
820
+ "49237": {
821
+ "content": "<|reserved_special_token_46|>",
822
+ "lstrip": false,
823
+ "normalized": false,
824
+ "rstrip": false,
825
+ "single_word": false,
826
+ "special": true
827
+ },
828
+ "49238": {
829
+ "content": "<|reserved_special_token_47|>",
830
+ "lstrip": false,
831
+ "normalized": false,
832
+ "rstrip": false,
833
+ "single_word": false,
834
+ "special": true
835
+ },
836
+ "49239": {
837
+ "content": "<|reserved_special_token_48|>",
838
+ "lstrip": false,
839
+ "normalized": false,
840
+ "rstrip": false,
841
+ "single_word": false,
842
+ "special": true
843
+ },
844
+ "49240": {
845
+ "content": "<|reserved_special_token_49|>",
846
+ "lstrip": false,
847
+ "normalized": false,
848
+ "rstrip": false,
849
+ "single_word": false,
850
+ "special": true
851
+ },
852
+ "49241": {
853
+ "content": "<|reserved_special_token_50|>",
854
+ "lstrip": false,
855
+ "normalized": false,
856
+ "rstrip": false,
857
+ "single_word": false,
858
+ "special": true
859
+ },
860
+ "49242": {
861
+ "content": "<|reserved_special_token_51|>",
862
+ "lstrip": false,
863
+ "normalized": false,
864
+ "rstrip": false,
865
+ "single_word": false,
866
+ "special": true
867
+ },
868
+ "49243": {
869
+ "content": "<|reserved_special_token_52|>",
870
+ "lstrip": false,
871
+ "normalized": false,
872
+ "rstrip": false,
873
+ "single_word": false,
874
+ "special": true
875
+ },
876
+ "49244": {
877
+ "content": "<|reserved_special_token_53|>",
878
+ "lstrip": false,
879
+ "normalized": false,
880
+ "rstrip": false,
881
+ "single_word": false,
882
+ "special": true
883
+ },
884
+ "49245": {
885
+ "content": "<|reserved_special_token_54|>",
886
+ "lstrip": false,
887
+ "normalized": false,
888
+ "rstrip": false,
889
+ "single_word": false,
890
+ "special": true
891
+ },
892
+ "49246": {
893
+ "content": "<|reserved_special_token_55|>",
894
+ "lstrip": false,
895
+ "normalized": false,
896
+ "rstrip": false,
897
+ "single_word": false,
898
+ "special": true
899
+ },
900
+ "49247": {
901
+ "content": "<|reserved_special_token_56|>",
902
+ "lstrip": false,
903
+ "normalized": false,
904
+ "rstrip": false,
905
+ "single_word": false,
906
+ "special": true
907
+ },
908
+ "49248": {
909
+ "content": "<|reserved_special_token_57|>",
910
+ "lstrip": false,
911
+ "normalized": false,
912
+ "rstrip": false,
913
+ "single_word": false,
914
+ "special": true
915
+ },
916
+ "49249": {
917
+ "content": "<|reserved_special_token_58|>",
918
+ "lstrip": false,
919
+ "normalized": false,
920
+ "rstrip": false,
921
+ "single_word": false,
922
+ "special": true
923
+ },
924
+ "49250": {
925
+ "content": "<|reserved_special_token_59|>",
926
+ "lstrip": false,
927
+ "normalized": false,
928
+ "rstrip": false,
929
+ "single_word": false,
930
+ "special": true
931
+ },
932
+ "49251": {
933
+ "content": "<|reserved_special_token_60|>",
934
+ "lstrip": false,
935
+ "normalized": false,
936
+ "rstrip": false,
937
+ "single_word": false,
938
+ "special": true
939
+ },
940
+ "49252": {
941
+ "content": "<|reserved_special_token_61|>",
942
+ "lstrip": false,
943
+ "normalized": false,
944
+ "rstrip": false,
945
+ "single_word": false,
946
+ "special": true
947
+ },
948
+ "49253": {
949
+ "content": "<|reserved_special_token_62|>",
950
+ "lstrip": false,
951
+ "normalized": false,
952
+ "rstrip": false,
953
+ "single_word": false,
954
+ "special": true
955
+ },
956
+ "49254": {
957
+ "content": "<|reserved_special_token_63|>",
958
+ "lstrip": false,
959
+ "normalized": false,
960
+ "rstrip": false,
961
+ "single_word": false,
962
+ "special": true
963
+ },
964
+ "49255": {
965
+ "content": "<|reserved_special_token_64|>",
966
+ "lstrip": false,
967
+ "normalized": false,
968
+ "rstrip": false,
969
+ "single_word": false,
970
+ "special": true
971
+ },
972
+ "49256": {
973
+ "content": "<|reserved_special_token_65|>",
974
+ "lstrip": false,
975
+ "normalized": false,
976
+ "rstrip": false,
977
+ "single_word": false,
978
+ "special": true
979
+ },
980
+ "49257": {
981
+ "content": "<|reserved_special_token_66|>",
982
+ "lstrip": false,
983
+ "normalized": false,
984
+ "rstrip": false,
985
+ "single_word": false,
986
+ "special": true
987
+ },
988
+ "49258": {
989
+ "content": "<|reserved_special_token_67|>",
990
+ "lstrip": false,
991
+ "normalized": false,
992
+ "rstrip": false,
993
+ "single_word": false,
994
+ "special": true
995
+ },
996
+ "49259": {
997
+ "content": "<|reserved_special_token_68|>",
998
+ "lstrip": false,
999
+ "normalized": false,
1000
+ "rstrip": false,
1001
+ "single_word": false,
1002
+ "special": true
1003
+ },
1004
+ "49260": {
1005
+ "content": "<|reserved_special_token_69|>",
1006
+ "lstrip": false,
1007
+ "normalized": false,
1008
+ "rstrip": false,
1009
+ "single_word": false,
1010
+ "special": true
1011
+ },
1012
+ "49261": {
1013
+ "content": "<|reserved_special_token_70|>",
1014
+ "lstrip": false,
1015
+ "normalized": false,
1016
+ "rstrip": false,
1017
+ "single_word": false,
1018
+ "special": true
1019
+ },
1020
+ "49262": {
1021
+ "content": "<|reserved_special_token_71|>",
1022
+ "lstrip": false,
1023
+ "normalized": false,
1024
+ "rstrip": false,
1025
+ "single_word": false,
1026
+ "special": true
1027
+ },
1028
+ "49263": {
1029
+ "content": "<|reserved_special_token_72|>",
1030
+ "lstrip": false,
1031
+ "normalized": false,
1032
+ "rstrip": false,
1033
+ "single_word": false,
1034
+ "special": true
1035
+ },
1036
+ "49264": {
1037
+ "content": "<|reserved_special_token_73|>",
1038
+ "lstrip": false,
1039
+ "normalized": false,
1040
+ "rstrip": false,
1041
+ "single_word": false,
1042
+ "special": true
1043
+ },
1044
+ "49265": {
1045
+ "content": "<|reserved_special_token_74|>",
1046
+ "lstrip": false,
1047
+ "normalized": false,
1048
+ "rstrip": false,
1049
+ "single_word": false,
1050
+ "special": true
1051
+ },
1052
+ "49266": {
1053
+ "content": "<|reserved_special_token_75|>",
1054
+ "lstrip": false,
1055
+ "normalized": false,
1056
+ "rstrip": false,
1057
+ "single_word": false,
1058
+ "special": true
1059
+ },
1060
+ "49267": {
1061
+ "content": "<|reserved_special_token_76|>",
1062
+ "lstrip": false,
1063
+ "normalized": false,
1064
+ "rstrip": false,
1065
+ "single_word": false,
1066
+ "special": true
1067
+ },
1068
+ "49268": {
1069
+ "content": "<|reserved_special_token_77|>",
1070
+ "lstrip": false,
1071
+ "normalized": false,
1072
+ "rstrip": false,
1073
+ "single_word": false,
1074
+ "special": true
1075
+ },
1076
+ "49269": {
1077
+ "content": "<|reserved_special_token_78|>",
1078
+ "lstrip": false,
1079
+ "normalized": false,
1080
+ "rstrip": false,
1081
+ "single_word": false,
1082
+ "special": true
1083
+ },
1084
+ "49270": {
1085
+ "content": "<|reserved_special_token_79|>",
1086
+ "lstrip": false,
1087
+ "normalized": false,
1088
+ "rstrip": false,
1089
+ "single_word": false,
1090
+ "special": true
1091
+ },
1092
+ "49271": {
1093
+ "content": "<|reserved_special_token_80|>",
1094
+ "lstrip": false,
1095
+ "normalized": false,
1096
+ "rstrip": false,
1097
+ "single_word": false,
1098
+ "special": true
1099
+ },
1100
+ "49272": {
1101
+ "content": "<|reserved_special_token_81|>",
1102
+ "lstrip": false,
1103
+ "normalized": false,
1104
+ "rstrip": false,
1105
+ "single_word": false,
1106
+ "special": true
1107
+ },
1108
+ "49273": {
1109
+ "content": "<|reserved_special_token_82|>",
1110
+ "lstrip": false,
1111
+ "normalized": false,
1112
+ "rstrip": false,
1113
+ "single_word": false,
1114
+ "special": true
1115
+ },
1116
+ "49274": {
1117
+ "content": "<|reserved_special_token_83|>",
1118
+ "lstrip": false,
1119
+ "normalized": false,
1120
+ "rstrip": false,
1121
+ "single_word": false,
1122
+ "special": true
1123
+ },
1124
+ "49275": {
1125
+ "content": "<|reserved_special_token_84|>",
1126
+ "lstrip": false,
1127
+ "normalized": false,
1128
+ "rstrip": false,
1129
+ "single_word": false,
1130
+ "special": true
1131
+ },
1132
+ "49276": {
1133
+ "content": "<|reserved_special_token_85|>",
1134
+ "lstrip": false,
1135
+ "normalized": false,
1136
+ "rstrip": false,
1137
+ "single_word": false,
1138
+ "special": true
1139
+ },
1140
+ "49277": {
1141
+ "content": "<|reserved_special_token_86|>",
1142
+ "lstrip": false,
1143
+ "normalized": false,
1144
+ "rstrip": false,
1145
+ "single_word": false,
1146
+ "special": true
1147
+ },
1148
+ "49278": {
1149
+ "content": "<|reserved_special_token_87|>",
1150
+ "lstrip": false,
1151
+ "normalized": false,
1152
+ "rstrip": false,
1153
+ "single_word": false,
1154
+ "special": true
1155
+ },
1156
+ "49279": {
1157
+ "content": "<end_of_utterance>",
1158
+ "lstrip": false,
1159
+ "normalized": false,
1160
+ "rstrip": false,
1161
+ "single_word": false,
1162
+ "special": true
1163
+ }
1164
+ },
1165
+ "additional_special_tokens": [
1166
+ "<fake_token_around_image>",
1167
+ "<image>",
1168
+ "<end_of_utterance>"
1169
+ ],
1170
+ "bos_token": "<|im_start|>",
1171
+ "clean_up_tokenization_spaces": false,
1172
+ "end_of_utterance_token": "<end_of_utterance>",
1173
+ "eos_token": "<end_of_utterance>",
1174
+ "extra_special_tokens": {
1175
+ "end_of_utterance_token": "<end_of_utterance>",
1176
+ "fake_image_token": "<fake_token_around_image>",
1177
+ "global_image_token": "<global-img>",
1178
+ "image_token": "<image>"
1179
+ },
1180
+ "fake_image_token": "<fake_token_around_image>",
1181
+ "global_image_token": "<global-img>",
1182
+ "image_token": "<image>",
1183
+ "legacy": false,
1184
+ "model_max_length": 16384,
1185
+ "pad_token": "<|im_end|>",
1186
+ "processor_class": "SmolVLMProcessor",
1187
+ "tokenizer_class": "GPT2Tokenizer",
1188
+ "truncation_side": "left",
1189
+ "unk_token": "<|endoftext|>",
1190
+ "vocab_size": 49152
1191
+ }
processor/vocab.json ADDED
The diff for this file is too large to render. See raw diff
 
puker_judge_utils.py ADDED
@@ -0,0 +1,193 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import time
5
+ from pathlib import Path
6
+ from typing import Any
7
+
8
+ import torch
9
+ from huggingface_hub import snapshot_download
10
+ from peft import PeftModel
11
+ from PIL import Image
12
+ from transformers import (
13
+ AutoModelForImageTextToText,
14
+ AutoProcessor,
15
+ BitsAndBytesConfig,
16
+ )
17
+
18
+ BASE_MODEL_ID = "HuggingFaceTB/SmolVLM2-2.2B-Instruct"
19
+ MODEL_REPO_ID = "TuWaveGod/Puker_Judge"
20
+ MAX_LENGTH = 2048
21
+ MAX_IMAGE_LONGEST_EDGE = 1280
22
+
23
+ BINARY_PROMPT = (
24
+ "Judge whether this geometrically assembled playing card has coherent rank, "
25
+ "suit, border, portrait, symbols, and continuous artwork. A whole-card "
26
+ "180-degree rotation is valid. Answer VALID or INVALID only."
27
+ )
28
+
29
+
30
+ def rank_prompt(candidate_count: int) -> str:
31
+ if not 2 <= candidate_count <= 4:
32
+ raise ValueError("Rank inference requires 2 to 4 candidates.")
33
+ labels = ", ".join(str(index) for index in range(1, candidate_count + 1))
34
+ return (
35
+ "All displayed candidates are geometrically valid reconstructions made "
36
+ "from the same playing-card pieces. Select the candidate whose rank, suit, "
37
+ "outer border, portrait, symbols, and line artwork form one coherent "
38
+ "original playing card. A whole-card 180-degree rotation is equivalent. "
39
+ f"The available labels are {labels}. Answer with one label only."
40
+ )
41
+
42
+
43
+ def resize_for_model(image: Image.Image) -> Image.Image:
44
+ image = image.convert("RGB")
45
+ longest = max(image.size)
46
+ if longest <= MAX_IMAGE_LONGEST_EDGE:
47
+ return image
48
+ scale = MAX_IMAGE_LONGEST_EDGE / longest
49
+ return image.resize(
50
+ (
51
+ max(1, int(round(image.width * scale))),
52
+ max(1, int(round(image.height * scale))),
53
+ ),
54
+ Image.Resampling.LANCZOS,
55
+ )
56
+
57
+
58
+ def load_adapter(
59
+ adapter_name: str,
60
+ *,
61
+ repo_id: str = MODEL_REPO_ID,
62
+ base_model_id: str = BASE_MODEL_ID,
63
+ int4: bool = False,
64
+ ) -> tuple[Any, Any, torch.device, dict[str, float]]:
65
+ if adapter_name not in {"binary_adapter", "rank_adapter"}:
66
+ raise ValueError(f"Unknown adapter: {adapter_name}")
67
+ if not torch.cuda.is_available():
68
+ raise RuntimeError("A CUDA GPU is required by these example scripts.")
69
+
70
+ local_repo = Path(repo_id).expanduser()
71
+ if local_repo.is_dir():
72
+ snapshot_path = local_repo.resolve()
73
+ download_seconds = 0.0
74
+ else:
75
+ download_started = time.perf_counter()
76
+ snapshot_path = Path(
77
+ snapshot_download(
78
+ repo_id=repo_id,
79
+ allow_patterns=[
80
+ f"{adapter_name}/*",
81
+ "processor/*",
82
+ ],
83
+ )
84
+ )
85
+ download_seconds = time.perf_counter() - download_started
86
+
87
+ processor = AutoProcessor.from_pretrained(snapshot_path / "processor")
88
+ load_kwargs: dict[str, Any] = {
89
+ "torch_dtype": torch.bfloat16,
90
+ "attn_implementation": "sdpa",
91
+ }
92
+ if int4:
93
+ load_kwargs.update(
94
+ {
95
+ "quantization_config": BitsAndBytesConfig(
96
+ load_in_4bit=True,
97
+ bnb_4bit_quant_type="nf4",
98
+ bnb_4bit_compute_dtype=torch.bfloat16,
99
+ bnb_4bit_use_double_quant=True,
100
+ ),
101
+ "device_map": {"": 0},
102
+ }
103
+ )
104
+
105
+ load_started = time.perf_counter()
106
+ base_model = AutoModelForImageTextToText.from_pretrained(
107
+ base_model_id,
108
+ **load_kwargs,
109
+ )
110
+ if not int4:
111
+ base_model = base_model.to("cuda:0")
112
+ model = PeftModel.from_pretrained(
113
+ base_model,
114
+ snapshot_path / adapter_name,
115
+ ).eval()
116
+ torch.cuda.synchronize()
117
+ load_seconds = time.perf_counter() - load_started
118
+ return (
119
+ model,
120
+ processor,
121
+ torch.device("cuda:0"),
122
+ {
123
+ "snapshot_download_seconds": download_seconds,
124
+ "model_load_seconds": load_seconds,
125
+ },
126
+ )
127
+
128
+
129
+ def encode_image_prompt(
130
+ processor: Any,
131
+ image: Image.Image,
132
+ prompt: str,
133
+ device: torch.device,
134
+ ) -> dict[str, Any]:
135
+ messages = [
136
+ {
137
+ "role": "user",
138
+ "content": [
139
+ {"type": "image"},
140
+ {"type": "text", "text": prompt},
141
+ ],
142
+ }
143
+ ]
144
+ text = processor.apply_chat_template(
145
+ messages,
146
+ add_generation_prompt=True,
147
+ tokenize=False,
148
+ )
149
+ inputs = processor(
150
+ text=text,
151
+ images=resize_for_model(image),
152
+ return_tensors="pt",
153
+ truncation=True,
154
+ max_length=MAX_LENGTH,
155
+ )
156
+ moved: dict[str, Any] = {}
157
+ for key, value in inputs.items():
158
+ if not isinstance(value, torch.Tensor):
159
+ moved[key] = value
160
+ elif key == "pixel_values":
161
+ moved[key] = value.to(device=device, dtype=torch.bfloat16)
162
+ else:
163
+ moved[key] = value.to(device=device)
164
+ return moved
165
+
166
+
167
+ def generate_answer(
168
+ model: Any,
169
+ processor: Any,
170
+ inputs: dict[str, Any],
171
+ *,
172
+ max_new_tokens: int = 4,
173
+ ) -> tuple[str, float]:
174
+ input_length = int(inputs["input_ids"].shape[1])
175
+ torch.cuda.synchronize()
176
+ started = time.perf_counter()
177
+ with torch.inference_mode():
178
+ output_ids = model.generate(
179
+ **inputs,
180
+ do_sample=False,
181
+ max_new_tokens=max_new_tokens,
182
+ )
183
+ torch.cuda.synchronize()
184
+ elapsed = time.perf_counter() - started
185
+ answer = processor.decode(
186
+ output_ids[0, input_length:],
187
+ skip_special_tokens=True,
188
+ ).strip()
189
+ return answer, elapsed
190
+
191
+
192
+ def print_json(payload: dict[str, Any]) -> None:
193
+ print(json.dumps(payload, ensure_ascii=False, indent=2))
rank_adapter/adapter_config.json ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "alpha_pattern": {},
3
+ "auto_mapping": null,
4
+ "base_model_name_or_path": "HuggingFaceTB/SmolVLM2-2.2B-Instruct",
5
+ "bias": "none",
6
+ "corda_config": null,
7
+ "eva_config": null,
8
+ "exclude_modules": null,
9
+ "fan_in_fan_out": false,
10
+ "inference_mode": true,
11
+ "init_lora_weights": true,
12
+ "layer_replication": null,
13
+ "layers_pattern": null,
14
+ "layers_to_transform": null,
15
+ "loftq_config": {},
16
+ "lora_alpha": 32,
17
+ "lora_bias": false,
18
+ "lora_dropout": 0.05,
19
+ "megatron_config": null,
20
+ "megatron_core": "megatron.core",
21
+ "modules_to_save": null,
22
+ "peft_type": "LORA",
23
+ "r": 16,
24
+ "rank_pattern": {},
25
+ "revision": null,
26
+ "target_modules": [
27
+ "text_model.layers.20.self_attn.k_proj",
28
+ "text_model.layers.21.self_attn.k_proj",
29
+ "text_model.layers.23.self_attn.v_proj",
30
+ "text_model.layers.20.self_attn.q_proj",
31
+ "text_model.layers.17.self_attn.q_proj",
32
+ "text_model.layers.7.self_attn.v_proj",
33
+ "text_model.layers.3.self_attn.v_proj",
34
+ "text_model.layers.19.self_attn.v_proj",
35
+ "text_model.layers.2.self_attn.v_proj",
36
+ "text_model.layers.0.self_attn.v_proj",
37
+ "text_model.layers.21.self_attn.q_proj",
38
+ "text_model.layers.5.self_attn.q_proj",
39
+ "text_model.layers.12.self_attn.v_proj",
40
+ "text_model.layers.23.self_attn.k_proj",
41
+ "text_model.layers.16.self_attn.v_proj",
42
+ "text_model.layers.7.self_attn.q_proj",
43
+ "text_model.layers.4.self_attn.q_proj",
44
+ "o_proj",
45
+ "text_model.layers.8.self_attn.k_proj",
46
+ "text_model.layers.0.self_attn.q_proj",
47
+ "text_model.layers.9.self_attn.k_proj",
48
+ "text_model.layers.6.self_attn.v_proj",
49
+ "text_model.layers.23.self_attn.q_proj",
50
+ "text_model.layers.19.self_attn.q_proj",
51
+ "text_model.layers.8.self_attn.v_proj",
52
+ "text_model.layers.15.self_attn.k_proj",
53
+ "text_model.layers.15.self_attn.v_proj",
54
+ "up_proj",
55
+ "text_model.layers.9.self_attn.q_proj",
56
+ "text_model.layers.1.self_attn.q_proj",
57
+ "text_model.layers.4.self_attn.v_proj",
58
+ "text_model.layers.11.self_attn.v_proj",
59
+ "text_model.layers.9.self_attn.v_proj",
60
+ "text_model.layers.14.self_attn.k_proj",
61
+ "text_model.layers.17.self_attn.k_proj",
62
+ "text_model.layers.4.self_attn.k_proj",
63
+ "text_model.layers.2.self_attn.q_proj",
64
+ "text_model.layers.16.self_attn.k_proj",
65
+ "text_model.layers.14.self_attn.q_proj",
66
+ "text_model.layers.22.self_attn.q_proj",
67
+ "text_model.layers.5.self_attn.k_proj",
68
+ "text_model.layers.10.self_attn.v_proj",
69
+ "text_model.layers.15.self_attn.q_proj",
70
+ "text_model.layers.13.self_attn.q_proj",
71
+ "text_model.layers.0.self_attn.k_proj",
72
+ "down_proj",
73
+ "text_model.layers.19.self_attn.k_proj",
74
+ "text_model.layers.6.self_attn.q_proj",
75
+ "text_model.layers.10.self_attn.k_proj",
76
+ "text_model.layers.22.self_attn.v_proj",
77
+ "text_model.layers.2.self_attn.k_proj",
78
+ "text_model.layers.20.self_attn.v_proj",
79
+ "text_model.layers.13.self_attn.v_proj",
80
+ "text_model.layers.5.self_attn.v_proj",
81
+ "text_model.layers.6.self_attn.k_proj",
82
+ "text_model.layers.12.self_attn.q_proj",
83
+ "text_model.layers.21.self_attn.v_proj",
84
+ "text_model.layers.14.self_attn.v_proj",
85
+ "text_model.layers.16.self_attn.q_proj",
86
+ "text_model.layers.3.self_attn.q_proj",
87
+ "text_model.layers.18.self_attn.v_proj",
88
+ "text_model.layers.11.self_attn.k_proj",
89
+ "gate_proj",
90
+ "text_model.layers.11.self_attn.q_proj",
91
+ "text_model.layers.7.self_attn.k_proj",
92
+ "text_model.layers.12.self_attn.k_proj",
93
+ "text_model.layers.18.self_attn.q_proj",
94
+ "text_model.layers.1.self_attn.k_proj",
95
+ "text_model.layers.3.self_attn.k_proj",
96
+ "text_model.layers.22.self_attn.k_proj",
97
+ "text_model.layers.1.self_attn.v_proj",
98
+ "text_model.layers.8.self_attn.q_proj",
99
+ "text_model.layers.17.self_attn.v_proj",
100
+ "text_model.layers.13.self_attn.k_proj",
101
+ "text_model.layers.10.self_attn.q_proj",
102
+ "text_model.layers.18.self_attn.k_proj"
103
+ ],
104
+ "task_type": "CAUSAL_LM",
105
+ "trainable_token_indices": null,
106
+ "use_dora": false,
107
+ "use_rslora": false
108
+ }
rank_adapter/adapter_model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d2715f57f10feb56f9dc22a79df65f4cad907b77f0f0c2881b110bc92db47197
3
+ size 72400072
requirements-int4.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ -r requirements.txt
2
+ bitsandbytes==0.50.0
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ torch>=2.5.1
2
+ transformers==4.52.4
3
+ peft==0.15.2
4
+ accelerate==1.7.0
5
+ huggingface-hub>=0.32.4
6
+ safetensors>=0.5.3
7
+ Pillow>=11.2.1
training_config.yaml ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ project:
2
+ seed: 20260730
3
+ data_dir: data
4
+ output_dir: outputs
5
+ artifact_dir: artifacts
6
+
7
+ resources:
8
+ card_asset_dir: asset/cards/robmikh_svg_cards
9
+ expected_card_count: 52
10
+ model_dir: model/smolvlm2-2.2b-instruct
11
+ card_split_counts:
12
+ train: 40
13
+ val: 6
14
+ test: 6
15
+
16
+ geometry:
17
+ card_width_mm: 100.0
18
+ card_height_mm: 60.0
19
+ min_piece_count: 2
20
+ max_piece_count: 4
21
+ max_piece_edges: 5
22
+ min_edge_mm: 20.0
23
+ min_piece_area_mm2: 350.0
24
+ random_partition_attempts: 800
25
+ congruence_tolerance_mm: 0.08
26
+ difficult_congruence_tolerance_mm: 3.5
27
+ max_enumerated_candidates: 512
28
+ max_rank_candidates: 4
29
+ visual_equivalence_mae: 2.0
30
+
31
+ dataset:
32
+ train_samples: 18000
33
+ val_samples: 1000
34
+ test_samples: 1000
35
+ family_weights:
36
+ random_unique: 0.15
37
+ offset_parallelogram_diagonal: 0.25
38
+ center_double_cut: 0.25
39
+ congruent_symmetric: 0.20
40
+ difficult_near_symmetric: 0.15
41
+ generation_retries: 80
42
+ progress_every: 100
43
+ binary_hard_negatives_per_scene: 1
44
+
45
+ render:
46
+ pixels_per_mm: 6.0
47
+ card_width_px: 600
48
+ card_height_px: 360
49
+ board_width_px: 1280
50
+ board_height_px: 820
51
+ board_background_rgb: [226, 231, 237]
52
+ cell_background_rgb: [244, 246, 248]
53
+ label_rgb: [25, 31, 42]
54
+ seam_width_px_range: [1, 3]
55
+ piece_brightness_range: [0.94, 1.06]
56
+ piece_color_range: [0.96, 1.04]
57
+ global_brightness_range: [0.90, 1.10]
58
+ global_contrast_range: [0.92, 1.08]
59
+ noise_sigma_range: [0.0, 2.0]
60
+ blur_radius_range: [0.0, 0.45]
61
+ jpeg_quality: 94
62
+
63
+ model:
64
+ max_length: 2048
65
+ max_image_longest_edge: 1280
66
+
67
+ training:
68
+ seed: 20260730
69
+ learning_rate: 0.0002
70
+ train_batch_size_per_gpu: 1
71
+ eval_batch_size_per_gpu: 1
72
+ gradient_accumulation_steps: 4
73
+ lora_rank: 16
74
+ lora_alpha: 32
75
+ lora_dropout: 0.05
76
+ warmup_ratio: 0.05
77
+ logging_steps: 10
78
+ eval_steps: 250
79
+ save_steps: 250
80
+ save_total_limit: 2
81
+ dataloader_workers_per_gpu: 2
82
+ binary_epochs: 1
83
+ rank_epochs: 3
84
+
85
+ evaluation:
86
+ max_samples: 1000
87
+ max_new_tokens: 4