tugrulv89 commited on
Commit
33644f7
·
verified ·
1 Parent(s): f4ade94

Use official CPU offload and verified pipeline signature for 48 GB evaluation

Browse files
EVALUATION_PROVENANCE.json CHANGED
@@ -1,7 +1,7 @@
1
  {
2
  "source": "Qwen/Qwen-Image-2.1",
3
  "source_revision": "d26bb61231c349cf6b7896fa83353113880e1ba3",
4
- "handler_git": "1805a9dcb663b115221a5a55d72150d70f2968d7",
5
- "handler_sha256": "d0dc0e84a39786a2de9f7808b8adae83ad0c66ba9661f7ca47ba2707e6eb892a",
6
  "use": "Isolated research/evaluation only; no production promotion"
7
  }
 
1
  {
2
  "source": "Qwen/Qwen-Image-2.1",
3
  "source_revision": "d26bb61231c349cf6b7896fa83353113880e1ba3",
4
+ "handler_git": "cf13cfff6d29586858d45a7e0d7972d0b88fd98f",
5
+ "handler_sha256": "126ca057f75fbc25185a75fb00cb9041942d9744f0489dd64f6685b5faa50877",
6
  "use": "Isolated research/evaluation only; no production promotion"
7
  }
handler/qwen21/README.md CHANGED
@@ -2,6 +2,10 @@
2
 
3
  Research only. Root 2511 handler, Dockerfile and production endpoint stay unchanged.
4
  The official base model is tested at 40 steps, CFG 1 and BF16, with prefix KV cache.
 
 
 
 
5
  This is a base-model quality comparison; it is not an 8-step Turbo benchmark.
6
 
7
  Build from the repository root using `qwen21/Dockerfile`. Set
 
2
 
3
  Research only. Root 2511 handler, Dockerfile and production endpoint stay unchanged.
4
  The official base model is tested at 40 steps, CFG 1 and BF16, with prefix KV cache.
5
+ Reference conditioning uses the upstream `output_resolution=1024` default;
6
+ the requested final image is 1024x1536. Full-resident BF16 failed with CUDA OOM
7
+ on the actual 48 GB worker. The official `enable_model_cpu_offload()` method
8
+ keeps BF16 and moves components in sequence without requiring a 96 GB GPU.
9
  This is a base-model quality comparison; it is not an 8-step Turbo benchmark.
10
 
11
  Build from the repository root using `qwen21/Dockerfile`. Set
handler/qwen21/handler.py CHANGED
@@ -3,6 +3,7 @@ import io
3
  import json
4
  import os
5
  import time
 
6
  import uuid
7
  from pathlib import Path
8
 
@@ -32,7 +33,8 @@ def sampling(job):
32
  raise ValueError('An explicit editing prompt is required')
33
  return {'prompt': job['prompt'], 'negative_prompt': job.get('negative_prompt'),
34
  'width': width, 'height': height, 'num_inference_steps': steps,
35
- 'true_cfg_scale': cfg, 'use_kv_cache': True}
 
36
 
37
 
38
  def cached_model_path():
@@ -51,7 +53,8 @@ def pipeline():
51
  from diffusers import QwenImage21Pipeline
52
  _pipe = QwenImage21Pipeline.from_pretrained(
53
  cached_model_path(), local_files_only=True,
54
- torch_dtype=torch.bfloat16).to('cuda')
 
55
  return _pipe
56
 
57
 
@@ -108,7 +111,7 @@ def handler(event):
108
  'peak_reserved_gib': round(torch.cuda.max_memory_reserved() / 1024**3, 2),
109
  'model_revision': os.environ['QWEN21_MODEL_REVISION']})
110
  except Exception as exc:
111
- detail = str(exc)
112
  for key in ('HF_TOKEN', 'JSON_PATH_KEY'):
113
  if os.environ.get(key):
114
  detail = detail.replace(os.environ[key], '[REDACTED]')
 
3
  import json
4
  import os
5
  import time
6
+ import traceback
7
  import uuid
8
  from pathlib import Path
9
 
 
33
  raise ValueError('An explicit editing prompt is required')
34
  return {'prompt': job['prompt'], 'negative_prompt': job.get('negative_prompt'),
35
  'width': width, 'height': height, 'num_inference_steps': steps,
36
+ 'true_cfg_scale': cfg, 'use_kv_cache': True,
37
+ 'output_resolution': 1024}
38
 
39
 
40
  def cached_model_path():
 
53
  from diffusers import QwenImage21Pipeline
54
  _pipe = QwenImage21Pipeline.from_pretrained(
55
  cached_model_path(), local_files_only=True,
56
+ torch_dtype=torch.bfloat16)
57
+ _pipe.enable_model_cpu_offload()
58
  return _pipe
59
 
60
 
 
111
  'peak_reserved_gib': round(torch.cuda.max_memory_reserved() / 1024**3, 2),
112
  'model_revision': os.environ['QWEN21_MODEL_REVISION']})
113
  except Exception as exc:
114
+ detail = traceback.format_exc()
115
  for key in ('HF_TOKEN', 'JSON_PATH_KEY'):
116
  if os.environ.get(key):
117
  detail = detail.replace(os.environ[key], '[REDACTED]')
handler/qwen21/tests/pipeline_contract.json ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "diffusers_commit": "85c9fa4caee33d1c5b473395784471d2d7957c1b",
3
+ "source": "src/diffusers/pipelines/qwenimage21/pipeline_qwenimage21.py",
4
+ "source_sha256": "e75e4ce38d38e194edaac818bba99b2115b4bb2bfdbd15ce03a2813b0fe8856c",
5
+ "call_parameters": [
6
+ "prompt",
7
+ "image",
8
+ "negative_prompt",
9
+ "true_cfg_scale",
10
+ "height",
11
+ "width",
12
+ "num_inference_steps",
13
+ "sigmas",
14
+ "num_images_per_prompt",
15
+ "generator",
16
+ "latents",
17
+ "prompt_embeds",
18
+ "prompt_embeds_mask",
19
+ "negative_prompt_embeds",
20
+ "negative_prompt_embeds_mask",
21
+ "output_type",
22
+ "return_dict",
23
+ "attention_kwargs",
24
+ "callback_on_step_end",
25
+ "callback_on_step_end_tensor_inputs",
26
+ "output_resolution",
27
+ "use_kv_cache"
28
+ ]
29
+ }
handler/qwen21/tests/test_sampling.py CHANGED
@@ -1,6 +1,7 @@
1
  import unittest
2
  import os
3
  import tempfile
 
4
  from pathlib import Path
5
  from unittest.mock import patch
6
 
@@ -29,9 +30,17 @@ class SamplingTests(unittest.TestCase):
29
  self.assertEqual((args['width'], args['height'], args['num_inference_steps']), (1024, 1536, 40))
30
  self.assertEqual(args['true_cfg_scale'], 1.0)
31
  self.assertTrue(args['use_kv_cache'])
 
32
  self.assertNotIn('guidance_scale', args)
33
  self.assertNotIn('sigmas', args)
34
 
 
 
 
 
 
 
 
35
  def test_invalid_controls_fail_before_loading_a_model(self):
36
  with patch('qwen21.handler.pipeline') as load:
37
  result = handler({'input': {'task': 'edit', 'jobs': [
 
1
  import unittest
2
  import os
3
  import tempfile
4
+ import json
5
  from pathlib import Path
6
  from unittest.mock import patch
7
 
 
30
  self.assertEqual((args['width'], args['height'], args['num_inference_steps']), (1024, 1536, 40))
31
  self.assertEqual(args['true_cfg_scale'], 1.0)
32
  self.assertTrue(args['use_kv_cache'])
33
+ self.assertEqual(args['output_resolution'], 1024)
34
  self.assertNotIn('guidance_scale', args)
35
  self.assertNotIn('sigmas', args)
36
 
37
+ def test_sampling_matches_the_pinned_official_pipeline_signature(self):
38
+ root = Path(__file__).parents[1]
39
+ contract = json.loads((root / 'tests/pipeline_contract.json').read_text())
40
+ self.assertIn(contract['diffusers_commit'], (root / 'requirements.txt').read_text())
41
+ self.assertLessEqual(set(sampling({'prompt': 'Keep the actual bag.'})),
42
+ set(contract['call_parameters']))
43
+
44
  def test_invalid_controls_fail_before_loading_a_model(self):
45
  with patch('qwen21.handler.pipeline') as load:
46
  result = handler({'input': {'task': 'edit', 'jobs': [