antoine-chaffin-pplx commited on
Commit
6195aa5
·
verified ·
1 Parent(s): 5cd25e3

Raise image cap from 512x512 to configurable max_image_pixels (default 2048x2048)

Browse files

DecisionModel 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 CHANGED
@@ -83,8 +83,38 @@ probabilities = model.predict([row])[0]
83
  print(answer(question, probabilities))
84
  ```
85
 
86
- `source/src/autojev/model.py` is copied byte-for-byte from the evaluated training
87
- run. `release-manifest.json` records file checksums and checkpoint provenance.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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": 262144,
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": 4339,
24
- "sha256": "7fd072ef02e89803dede5d57ea578d8eeab075137d39ab89da856d925d83aa8d"
25
  },
26
  "chat_template.jinja": {
27
  "bytes": 8952,
@@ -92,8 +92,8 @@
92
  "sha256": "dc39d771cb240f775399e1845b11d081d8e007f14eecae3b780bc6272b128a46"
93
  },
94
  "processor_config.json": {
95
- "bytes": 1218,
96
- "sha256": "abb488b9a03a53407dc9c8e43c0a2caec9142e5fc7a1203807fdf54b2149cc8f"
97
  },
98
  "readout.safetensors": {
99
  "bytes": 2611288,
@@ -132,8 +132,8 @@
132
  "sha256": "2e4f4ae4b8aafac0247f931220b592a140bd2f5cd032dce8a517a158fbeedda3"
133
  },
134
  "source/src/autojev/model.py": {
135
- "bytes": 17038,
136
- "sha256": "824721da4d8f8ba1e534f3ee35081869243c4457f6b3bd0a9a91b611b2ec1076"
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
- self.processor.image_processor.size = {"shortest_edge": 65536, "longest_edge": 262144}
 
 
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)