Text-to-Image
Cosmos
Diffusers
Safetensors
cosmos3_omni
nvidia
cosmos3
vllm-omni
sglang
sglang-diffusion
image-generation
Instructions to use nvidia/Cosmos3-Super-Text2Image with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Cosmos
How to use nvidia/Cosmos3-Super-Text2Image with Cosmos:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Diffusers
How to use nvidia/Cosmos3-Super-Text2Image with Diffusers:
pip install -U diffusers transformers accelerate
import torch from diffusers import DiffusionPipeline # switch to "mps" for apple devices pipe = DiffusionPipeline.from_pretrained("nvidia/Cosmos3-Super-Text2Image", torch_dtype=torch.bfloat16, device_map="cuda") prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k" image = pipe(prompt).images[0] - Notebooks
- Google Colab
- Kaggle
Fix unseeded generation when seed_base is unset; make the critic's request params configurable
#17
by arturzolkowski - opened
agentic_upsampling/clients.py
CHANGED
|
@@ -477,8 +477,9 @@ class VLMQualityJudge:
|
|
| 477 |
api_token: str,
|
| 478 |
endpoint_url: str = DEFAULT_CRITIC_ENDPOINT_URL,
|
| 479 |
model: str = DEFAULT_CRITIC_MODEL,
|
| 480 |
-
max_tokens: int =
|
| 481 |
image_jpeg_quality: int | None = DEFAULT_JPEG_QUALITY,
|
|
|
|
| 482 |
) -> None:
|
| 483 |
self.chat_client = OpenAIChatClient(
|
| 484 |
ChatClientConfig(
|
|
@@ -487,6 +488,7 @@ class VLMQualityJudge:
|
|
| 487 |
api_token=api_token,
|
| 488 |
max_tokens=max_tokens,
|
| 489 |
max_retries=3,
|
|
|
|
| 490 |
)
|
| 491 |
)
|
| 492 |
self.image_jpeg_quality = image_jpeg_quality
|
|
|
|
| 477 |
api_token: str,
|
| 478 |
endpoint_url: str = DEFAULT_CRITIC_ENDPOINT_URL,
|
| 479 |
model: str = DEFAULT_CRITIC_MODEL,
|
| 480 |
+
max_tokens: int = 16384,
|
| 481 |
image_jpeg_quality: int | None = DEFAULT_JPEG_QUALITY,
|
| 482 |
+
extra_body: dict[str, Any] | None = None,
|
| 483 |
) -> None:
|
| 484 |
self.chat_client = OpenAIChatClient(
|
| 485 |
ChatClientConfig(
|
|
|
|
| 488 |
api_token=api_token,
|
| 489 |
max_tokens=max_tokens,
|
| 490 |
max_retries=3,
|
| 491 |
+
extra_body=extra_body,
|
| 492 |
)
|
| 493 |
)
|
| 494 |
self.image_jpeg_quality = image_jpeg_quality
|
agentic_upsampling/runner.py
CHANGED
|
@@ -3,6 +3,7 @@
|
|
| 3 |
from __future__ import annotations
|
| 4 |
|
| 5 |
import json
|
|
|
|
| 6 |
import traceback
|
| 7 |
from concurrent.futures import ThreadPoolExecutor, as_completed
|
| 8 |
from dataclasses import dataclass
|
|
@@ -112,6 +113,12 @@ class AgenticUpsamplerRunner:
|
|
| 112 |
(item_dir / "failure.json").unlink(missing_ok=True)
|
| 113 |
(item_dir / "incomplete.json").unlink(missing_ok=True)
|
| 114 |
self._log(f"[prompt {item.prompt_id}] start")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
candidates: list[dict[str, Any]] = []
|
| 116 |
previous_prompt: dict[str, Any] | None = None
|
| 117 |
previous_analysis: dict[str, Any] | None = None
|
|
@@ -131,6 +138,7 @@ class AgenticUpsamplerRunner:
|
|
| 131 |
previous_analysis,
|
| 132 |
previous_negative_prompt,
|
| 133 |
candidates,
|
|
|
|
| 134 |
)
|
| 135 |
except Exception as exc:
|
| 136 |
if not candidates:
|
|
@@ -152,7 +160,9 @@ class AgenticUpsamplerRunner:
|
|
| 152 |
self._log(f"[prompt {item.prompt_id}] early stop at iter={iteration}")
|
| 153 |
break
|
| 154 |
|
| 155 |
-
|
|
|
|
|
|
|
| 156 |
|
| 157 |
def run_item_safely(self, item: PromptItem) -> dict[str, Any]:
|
| 158 |
"""Run one item and convert failures into structured records."""
|
|
@@ -179,6 +189,7 @@ class AgenticUpsamplerRunner:
|
|
| 179 |
previous_analysis: dict[str, Any] | None,
|
| 180 |
previous_negative_prompt: str,
|
| 181 |
candidates: list[dict[str, Any]],
|
|
|
|
| 182 |
) -> dict[str, Any]:
|
| 183 |
prepared = self.prepare_iteration_prompt(
|
| 184 |
item,
|
|
@@ -195,6 +206,7 @@ class AgenticUpsamplerRunner:
|
|
| 195 |
iteration,
|
| 196 |
prepared.prompt_json,
|
| 197 |
prepared.negative_prompt,
|
|
|
|
| 198 |
)
|
| 199 |
return self.finalize_iteration(item, iteration_dir, iteration, sample_candidates, sample_errors)
|
| 200 |
|
|
@@ -205,6 +217,7 @@ class AgenticUpsamplerRunner:
|
|
| 205 |
iteration: int,
|
| 206 |
prompt_json: dict[str, Any],
|
| 207 |
negative_prompt: str,
|
|
|
|
| 208 |
) -> tuple[list[dict[str, Any]], list[dict[str, Any]]]:
|
| 209 |
"""Generate seed samples concurrently, then judge successful images in sample order."""
|
| 210 |
generation_outputs: dict[int, GenerationOutput] = {}
|
|
@@ -218,6 +231,7 @@ class AgenticUpsamplerRunner:
|
|
| 218 |
sample_index,
|
| 219 |
prompt_json,
|
| 220 |
negative_prompt,
|
|
|
|
| 221 |
): sample_index
|
| 222 |
for sample_index in range(self.config.samples_per_iteration)
|
| 223 |
}
|
|
@@ -300,8 +314,11 @@ class AgenticUpsamplerRunner:
|
|
| 300 |
sample_index: int,
|
| 301 |
prompt_json: dict[str, Any],
|
| 302 |
negative_prompt: str,
|
|
|
|
| 303 |
) -> dict[str, Any]:
|
| 304 |
-
generation = self.run_generation_sample(
|
|
|
|
|
|
|
| 305 |
return self.judge_iteration_sample(
|
| 306 |
item,
|
| 307 |
iteration_dir,
|
|
@@ -319,6 +336,7 @@ class AgenticUpsamplerRunner:
|
|
| 319 |
sample_index: int,
|
| 320 |
prompt_json: dict[str, Any],
|
| 321 |
negative_prompt: str,
|
|
|
|
| 322 |
) -> GenerationOutput:
|
| 323 |
"""Generate one sample image for an iteration."""
|
| 324 |
sample_dir = self._sample_dir(iteration_dir, sample_index)
|
|
@@ -328,7 +346,7 @@ class AgenticUpsamplerRunner:
|
|
| 328 |
prompt_json=prompt_json,
|
| 329 |
prompt_id=item.prompt_id,
|
| 330 |
output_dir=sample_dir,
|
| 331 |
-
seed=
|
| 332 |
negative_prompt=negative_prompt,
|
| 333 |
jpeg_quality=self.config.jpeg_quality,
|
| 334 |
)
|
|
@@ -422,11 +440,6 @@ class AgenticUpsamplerRunner:
|
|
| 422 |
if self.config.verbose:
|
| 423 |
print(message, flush=True)
|
| 424 |
|
| 425 |
-
def _sample_seed(self, sample_index: int) -> int | None:
|
| 426 |
-
if self.config.seed_base is None:
|
| 427 |
-
return None
|
| 428 |
-
return self.config.seed_base + sample_index
|
| 429 |
-
|
| 430 |
def _sample_dir(self, iteration_dir: Path, sample_index: int) -> Path:
|
| 431 |
if self.config.samples_per_iteration == 1:
|
| 432 |
return iteration_dir
|
|
|
|
| 3 |
from __future__ import annotations
|
| 4 |
|
| 5 |
import json
|
| 6 |
+
import random
|
| 7 |
import traceback
|
| 8 |
from concurrent.futures import ThreadPoolExecutor, as_completed
|
| 9 |
from dataclasses import dataclass
|
|
|
|
| 113 |
(item_dir / "failure.json").unlink(missing_ok=True)
|
| 114 |
(item_dir / "incomplete.json").unlink(missing_ok=True)
|
| 115 |
self._log(f"[prompt {item.prompt_id}] start")
|
| 116 |
+
# One base per item, reused by every iteration (sample slot j gets base + j), so a
|
| 117 |
+
# rewrite is compared against the same noise. A resumed run draws a new base.
|
| 118 |
+
seed_base = self.config.seed_base
|
| 119 |
+
if seed_base is None:
|
| 120 |
+
seed_base = random.randint(0, 2**31 - 1 - self.config.samples_per_iteration)
|
| 121 |
+
self._log(f"[prompt {item.prompt_id}] seed_base drawn: {seed_base}")
|
| 122 |
candidates: list[dict[str, Any]] = []
|
| 123 |
previous_prompt: dict[str, Any] | None = None
|
| 124 |
previous_analysis: dict[str, Any] | None = None
|
|
|
|
| 138 |
previous_analysis,
|
| 139 |
previous_negative_prompt,
|
| 140 |
candidates,
|
| 141 |
+
seed_base,
|
| 142 |
)
|
| 143 |
except Exception as exc:
|
| 144 |
if not candidates:
|
|
|
|
| 160 |
self._log(f"[prompt {item.prompt_id}] early stop at iter={iteration}")
|
| 161 |
break
|
| 162 |
|
| 163 |
+
result = self.finalize_item(item, candidates, incomplete_error=incomplete_error)
|
| 164 |
+
result["seed_base"] = seed_base
|
| 165 |
+
return result
|
| 166 |
|
| 167 |
def run_item_safely(self, item: PromptItem) -> dict[str, Any]:
|
| 168 |
"""Run one item and convert failures into structured records."""
|
|
|
|
| 189 |
previous_analysis: dict[str, Any] | None,
|
| 190 |
previous_negative_prompt: str,
|
| 191 |
candidates: list[dict[str, Any]],
|
| 192 |
+
seed_base: int,
|
| 193 |
) -> dict[str, Any]:
|
| 194 |
prepared = self.prepare_iteration_prompt(
|
| 195 |
item,
|
|
|
|
| 206 |
iteration,
|
| 207 |
prepared.prompt_json,
|
| 208 |
prepared.negative_prompt,
|
| 209 |
+
seed_base,
|
| 210 |
)
|
| 211 |
return self.finalize_iteration(item, iteration_dir, iteration, sample_candidates, sample_errors)
|
| 212 |
|
|
|
|
| 217 |
iteration: int,
|
| 218 |
prompt_json: dict[str, Any],
|
| 219 |
negative_prompt: str,
|
| 220 |
+
seed_base: int,
|
| 221 |
) -> tuple[list[dict[str, Any]], list[dict[str, Any]]]:
|
| 222 |
"""Generate seed samples concurrently, then judge successful images in sample order."""
|
| 223 |
generation_outputs: dict[int, GenerationOutput] = {}
|
|
|
|
| 231 |
sample_index,
|
| 232 |
prompt_json,
|
| 233 |
negative_prompt,
|
| 234 |
+
seed_base,
|
| 235 |
): sample_index
|
| 236 |
for sample_index in range(self.config.samples_per_iteration)
|
| 237 |
}
|
|
|
|
| 314 |
sample_index: int,
|
| 315 |
prompt_json: dict[str, Any],
|
| 316 |
negative_prompt: str,
|
| 317 |
+
seed_base: int,
|
| 318 |
) -> dict[str, Any]:
|
| 319 |
+
generation = self.run_generation_sample(
|
| 320 |
+
item, iteration_dir, sample_index, prompt_json, negative_prompt, seed_base
|
| 321 |
+
)
|
| 322 |
return self.judge_iteration_sample(
|
| 323 |
item,
|
| 324 |
iteration_dir,
|
|
|
|
| 336 |
sample_index: int,
|
| 337 |
prompt_json: dict[str, Any],
|
| 338 |
negative_prompt: str,
|
| 339 |
+
seed_base: int,
|
| 340 |
) -> GenerationOutput:
|
| 341 |
"""Generate one sample image for an iteration."""
|
| 342 |
sample_dir = self._sample_dir(iteration_dir, sample_index)
|
|
|
|
| 346 |
prompt_json=prompt_json,
|
| 347 |
prompt_id=item.prompt_id,
|
| 348 |
output_dir=sample_dir,
|
| 349 |
+
seed=seed_base + sample_index,
|
| 350 |
negative_prompt=negative_prompt,
|
| 351 |
jpeg_quality=self.config.jpeg_quality,
|
| 352 |
)
|
|
|
|
| 440 |
if self.config.verbose:
|
| 441 |
print(message, flush=True)
|
| 442 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 443 |
def _sample_dir(self, iteration_dir: Path, sample_index: int) -> Path:
|
| 444 |
if self.config.samples_per_iteration == 1:
|
| 445 |
return iteration_dir
|
tests/test_agentic_upsampling.py
CHANGED
|
@@ -10,7 +10,7 @@ from typing import Any
|
|
| 10 |
|
| 11 |
from PIL import Image
|
| 12 |
|
| 13 |
-
from agentic_upsampling.clients import ImageGenerationClient, PromptRewriterClient
|
| 14 |
from agentic_upsampling.constants import (
|
| 15 |
DEFAULT_CRITIC_ENDPOINT_URL,
|
| 16 |
DEFAULT_CRITIC_MODEL,
|
|
@@ -413,7 +413,32 @@ def test_runner_early_stops_by_default(tmp_path: Path) -> None:
|
|
| 413 |
assert result["best_iteration"] == 0
|
| 414 |
assert rewriter.initial_calls == 1
|
| 415 |
assert rewriter.joint_rewrite_calls == 0
|
| 416 |
-
assert generator.seeds == [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 417 |
|
| 418 |
|
| 419 |
def test_runner_can_disable_early_stop_and_select_best_sample(tmp_path: Path) -> None:
|
|
@@ -496,3 +521,14 @@ def test_extract_best_images_copies_images_and_writes_manifests(tmp_path: Path)
|
|
| 496 |
assert (tmp_path / "export" / "best_generations.jsonl").exists()
|
| 497 |
assert (tmp_path / "export" / "best_generations.csv").exists()
|
| 498 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
|
| 11 |
from PIL import Image
|
| 12 |
|
| 13 |
+
from agentic_upsampling.clients import ImageGenerationClient, PromptRewriterClient, VLMQualityJudge
|
| 14 |
from agentic_upsampling.constants import (
|
| 15 |
DEFAULT_CRITIC_ENDPOINT_URL,
|
| 16 |
DEFAULT_CRITIC_MODEL,
|
|
|
|
| 413 |
assert result["best_iteration"] == 0
|
| 414 |
assert rewriter.initial_calls == 1
|
| 415 |
assert rewriter.joint_rewrite_calls == 0
|
| 416 |
+
assert generator.seeds == [result["seed_base"]]
|
| 417 |
+
|
| 418 |
+
|
| 419 |
+
def test_runner_draws_one_seed_base_when_unset(tmp_path: Path) -> None:
|
| 420 |
+
"""An unset seed_base is drawn once and reused, so slot j gets base + j every iteration."""
|
| 421 |
+
rewriter = FakeRewriter()
|
| 422 |
+
generator = FakeGenerator()
|
| 423 |
+
runner = AgenticUpsamplerRunner(
|
| 424 |
+
rewriter=rewriter,
|
| 425 |
+
generator=generator, # type: ignore[arg-type]
|
| 426 |
+
judge=FakeJudge([5.0, 6.0, 5.5, 6.5]),
|
| 427 |
+
config=RunnerConfig(
|
| 428 |
+
output_dir=tmp_path,
|
| 429 |
+
max_iterations=2,
|
| 430 |
+
samples_per_iteration=2,
|
| 431 |
+
early_stop=False,
|
| 432 |
+
),
|
| 433 |
+
)
|
| 434 |
+
|
| 435 |
+
result = runner.run_item(_item())
|
| 436 |
+
|
| 437 |
+
seed_base = result["seed_base"]
|
| 438 |
+
assert seed_base is not None
|
| 439 |
+
# Samples are generated concurrently, so compare each iteration's seeds as a set.
|
| 440 |
+
assert sorted(generator.seeds[:2]) == [seed_base, seed_base + 1]
|
| 441 |
+
assert sorted(generator.seeds[2:]) == [seed_base, seed_base + 1]
|
| 442 |
|
| 443 |
|
| 444 |
def test_runner_can_disable_early_stop_and_select_best_sample(tmp_path: Path) -> None:
|
|
|
|
| 521 |
assert (tmp_path / "export" / "best_generations.jsonl").exists()
|
| 522 |
assert (tmp_path / "export" / "best_generations.csv").exists()
|
| 523 |
|
| 524 |
+
|
| 525 |
+
def test_vlm_quality_judge_sends_no_extra_body_by_default() -> None:
|
| 526 |
+
judge = VLMQualityJudge(api_token="token")
|
| 527 |
+
|
| 528 |
+
assert judge.chat_client.config.extra_body is None
|
| 529 |
+
|
| 530 |
+
|
| 531 |
+
def test_vlm_quality_judge_forwards_extra_body() -> None:
|
| 532 |
+
judge = VLMQualityJudge(api_token="token", extra_body={"reasoning_effort": "high"})
|
| 533 |
+
|
| 534 |
+
assert judge.chat_client.config.extra_body == {"reasoning_effort": "high"}
|