Raise image cap from 512x512 to configurable max_image_pixels (default 2048x2048)
Browse filesDecisionModel gains a max_image_pixels kwarg (default 2048*2048); processor_config longest_edge 262144 -> 4194304; README documents aspect-ratio-preserving resize and token budget; manifest checksums updated.
- README.md +32 -2
- processor_config.json +1 -1
- release-manifest.json +6 -6
- source/src/autojev/model.py +6 -1
README.md
CHANGED
|
@@ -83,8 +83,38 @@ probabilities = model.predict([row])[0]
|
|
| 83 |
print(answer(question, probabilities))
|
| 84 |
```
|
| 85 |
|
| 86 |
-
|
| 87 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 88 |
|
| 89 |
|
| 90 |
## Acknowledgment
|
|
|
|
| 83 |
print(answer(question, probabilities))
|
| 84 |
```
|
| 85 |
|
| 86 |
+
### Images
|
| 87 |
+
|
| 88 |
+
Pass images as file paths, PIL images, or `data:image/...;base64` URLs in
|
| 89 |
+
`row["images"]`. The processor resizes them **while preserving aspect ratio**.
|
| 90 |
+
Each side is rounded to a multiple of 32 px, and the total area is kept between
|
| 91 |
+
256×256 (65,536 px) and `max_image_pixels`. Each 32×32 patch costs one visual token,
|
| 92 |
+
so an image uses about `width * height / 1024` tokens.
|
| 93 |
+
|
| 94 |
+
`max_image_pixels` defaults to 2048×2048 (4,194,304 px, ≤4,096 tokens per image).
|
| 95 |
+
Larger images are downscaled automatically, so you don't need to resize them
|
| 96 |
+
yourself. To lower or raise the cap:
|
| 97 |
+
|
| 98 |
+
```python
|
| 99 |
+
model = DecisionModel(checkpoint, device="cuda", max_image_pixels=1600 * 1000)
|
| 100 |
+
```
|
| 101 |
+
|
| 102 |
+
Keep in mind:
|
| 103 |
+
|
| 104 |
+
- The text and all images of a decision must fit in `prepare`'s 8,192-token
|
| 105 |
+
limit. Inputs are rejected rather than truncated. With several images per
|
| 106 |
+
decision, lower `max_image_pixels` or downscale the images first.
|
| 107 |
+
- Training and the reported evaluation capped images at 512×512 (262,144 px,
|
| 108 |
+
≤256 tokens). Higher resolutions keep more detail but fall outside the training
|
| 109 |
+
distribution, and they cost more memory and latency. To reproduce the evaluated
|
| 110 |
+
setup exactly, use `max_image_pixels=512 * 512`.
|
| 111 |
+
- If you resize images yourself, scale both sides by the same factor
|
| 112 |
+
`min(1, sqrt(max_image_pixels / (width * height)))` to keep the aspect ratio.
|
| 113 |
+
|
| 114 |
+
`source/src/autojev/model.py` is the evaluated training-run code, with one change:
|
| 115 |
+
the image-size cap is now the configurable `max_image_pixels`. It was previously
|
| 116 |
+
hardcoded at 512×512 pixels. `release-manifest.json` records file checksums and
|
| 117 |
+
checkpoint provenance.
|
| 118 |
|
| 119 |
|
| 120 |
## Acknowledgment
|
processor_config.json
CHANGED
|
@@ -20,7 +20,7 @@
|
|
| 20 |
"resample": 3,
|
| 21 |
"rescale_factor": 0.00392156862745098,
|
| 22 |
"size": {
|
| 23 |
-
"longest_edge":
|
| 24 |
"shortest_edge": 65536
|
| 25 |
},
|
| 26 |
"temporal_patch_size": 2
|
|
|
|
| 20 |
"resample": 3,
|
| 21 |
"rescale_factor": 0.00392156862745098,
|
| 22 |
"size": {
|
| 23 |
+
"longest_edge": 4194304,
|
| 24 |
"shortest_edge": 65536
|
| 25 |
},
|
| 26 |
"temporal_patch_size": 2
|
release-manifest.json
CHANGED
|
@@ -20,8 +20,8 @@
|
|
| 20 |
"sha256": "3792cbe9e964a7ed65fff010d3f94bb27c6e726e2940ab6b0e1db5d30df92510"
|
| 21 |
},
|
| 22 |
"README.md": {
|
| 23 |
-
"bytes":
|
| 24 |
-
"sha256": "
|
| 25 |
},
|
| 26 |
"chat_template.jinja": {
|
| 27 |
"bytes": 8952,
|
|
@@ -92,8 +92,8 @@
|
|
| 92 |
"sha256": "dc39d771cb240f775399e1845b11d081d8e007f14eecae3b780bc6272b128a46"
|
| 93 |
},
|
| 94 |
"processor_config.json": {
|
| 95 |
-
"bytes":
|
| 96 |
-
"sha256": "
|
| 97 |
},
|
| 98 |
"readout.safetensors": {
|
| 99 |
"bytes": 2611288,
|
|
@@ -132,8 +132,8 @@
|
|
| 132 |
"sha256": "2e4f4ae4b8aafac0247f931220b592a140bd2f5cd032dce8a517a158fbeedda3"
|
| 133 |
},
|
| 134 |
"source/src/autojev/model.py": {
|
| 135 |
-
"bytes":
|
| 136 |
-
"sha256": "
|
| 137 |
},
|
| 138 |
"source/src/autojev/optim.py": {
|
| 139 |
"bytes": 4702,
|
|
|
|
| 20 |
"sha256": "3792cbe9e964a7ed65fff010d3f94bb27c6e726e2940ab6b0e1db5d30df92510"
|
| 21 |
},
|
| 22 |
"README.md": {
|
| 23 |
+
"bytes": 5696,
|
| 24 |
+
"sha256": "265e16155cbc9c65bcf2a797521b8214eb659cf327f7bbed19ddcc298491eae4"
|
| 25 |
},
|
| 26 |
"chat_template.jinja": {
|
| 27 |
"bytes": 8952,
|
|
|
|
| 92 |
"sha256": "dc39d771cb240f775399e1845b11d081d8e007f14eecae3b780bc6272b128a46"
|
| 93 |
},
|
| 94 |
"processor_config.json": {
|
| 95 |
+
"bytes": 1219,
|
| 96 |
+
"sha256": "f76f21cad63dc9da928676e84e4f4889f154b9122e8c3f6b38093d39729fc266"
|
| 97 |
},
|
| 98 |
"readout.safetensors": {
|
| 99 |
"bytes": 2611288,
|
|
|
|
| 132 |
"sha256": "2e4f4ae4b8aafac0247f931220b592a140bd2f5cd032dce8a517a158fbeedda3"
|
| 133 |
},
|
| 134 |
"source/src/autojev/model.py": {
|
| 135 |
+
"bytes": 17304,
|
| 136 |
+
"sha256": "02940963e9fba5736b8f625f860812f31de2e6658a49606fbed49fd7215c20f9"
|
| 137 |
},
|
| 138 |
"source/src/autojev/optim.py": {
|
| 139 |
"bytes": 4702,
|
source/src/autojev/model.py
CHANGED
|
@@ -23,6 +23,8 @@ from autojev.types import Answer, Content, DecisionInput, ImageInput, JSONValue,
|
|
| 23 |
BASE_MODEL = "Qwen/Qwen3.8-27B"
|
| 24 |
BASE_REVISION = "1d4bf0f2ff6012fd82039f2fa52739d0dd7c60c0"
|
| 25 |
MAX_OPTIONS = 255
|
|
|
|
|
|
|
| 26 |
|
| 27 |
|
| 28 |
def enable_noncausal_full_attention(text_model: torch.nn.Module) -> None:
|
|
@@ -170,6 +172,7 @@ class DecisionModel(torch.nn.Module):
|
|
| 170 |
cache_dir: str | Path | None = None,
|
| 171 |
attention_mode: str | None = None,
|
| 172 |
pooling: str | None = None,
|
|
|
|
| 173 |
) -> None:
|
| 174 |
super().__init__()
|
| 175 |
torch.set_num_threads(cpu_threads)
|
|
@@ -205,7 +208,9 @@ class DecisionModel(torch.nn.Module):
|
|
| 205 |
),
|
| 206 |
)
|
| 207 |
self.processor.tokenizer.padding_side = "left"
|
| 208 |
-
|
|
|
|
|
|
|
| 209 |
tokenizer = self.processor.tokenizer
|
| 210 |
candidates = list(string.ascii_uppercase) + [
|
| 211 |
"".join(pair) for pair in itertools.product(string.ascii_uppercase, repeat=2)
|
|
|
|
| 23 |
BASE_MODEL = "Qwen/Qwen3.8-27B"
|
| 24 |
BASE_REVISION = "1d4bf0f2ff6012fd82039f2fa52739d0dd7c60c0"
|
| 25 |
MAX_OPTIONS = 255
|
| 26 |
+
MIN_IMAGE_PIXELS = 256 * 256
|
| 27 |
+
MAX_IMAGE_PIXELS = 2048 * 2048
|
| 28 |
|
| 29 |
|
| 30 |
def enable_noncausal_full_attention(text_model: torch.nn.Module) -> None:
|
|
|
|
| 172 |
cache_dir: str | Path | None = None,
|
| 173 |
attention_mode: str | None = None,
|
| 174 |
pooling: str | None = None,
|
| 175 |
+
max_image_pixels: int = MAX_IMAGE_PIXELS,
|
| 176 |
) -> None:
|
| 177 |
super().__init__()
|
| 178 |
torch.set_num_threads(cpu_threads)
|
|
|
|
| 208 |
),
|
| 209 |
)
|
| 210 |
self.processor.tokenizer.padding_side = "left"
|
| 211 |
+
if max_image_pixels < MIN_IMAGE_PIXELS:
|
| 212 |
+
raise ValueError(f"max_image_pixels must be at least {MIN_IMAGE_PIXELS}.")
|
| 213 |
+
self.processor.image_processor.size = {"shortest_edge": MIN_IMAGE_PIXELS, "longest_edge": max_image_pixels}
|
| 214 |
tokenizer = self.processor.tokenizer
|
| 215 |
candidates = list(string.ascii_uppercase) + [
|
| 216 |
"".join(pair) for pair in itertools.product(string.ascii_uppercase, repeat=2)
|