Elea Zhong commited on
Commit
77afe44
·
1 Parent(s): 9629589

add sage attention, fix fuse bug

Browse files
qwenimage/experiments/experiments_qwen.py CHANGED
@@ -21,7 +21,7 @@ from torch.utils._pytree import tree_map
21
  from torchao.utils import get_model_size_in_bytes
22
 
23
  from qwenimage.debug import ctimed, ftimed, print_first_param
24
- from qwenimage.models.attention_processors import QwenDoubleStreamAttnProcessorFA3
25
  from qwenimage.models.first_block_cache import apply_cache_on_pipe
26
  from qwenimage.models.pipeline_qwenimage_edit_plus import QwenImageEditPlusPipeline, calculate_dimensions
27
  from qwenimage.models.transformer_qwenimage import QwenImageTransformer2DModel
@@ -319,6 +319,7 @@ class Qwen_Fuse(QwenBaseExperiment):
319
  @ftimed
320
  def optimize(self):
321
  self.pipe.transformer.fuse_qkv_projections()
 
322
 
323
 
324
  @ExperimentRegistry.register(name="qwen_fuse_aot")
@@ -326,6 +327,8 @@ class Qwen_Fuse_AoT(QwenBaseExperiment):
326
  @ftimed
327
  def optimize(self):
328
  self.pipe.transformer.fuse_qkv_projections()
 
 
329
  optimize_pipeline_(
330
  self.pipe,
331
  cache_compiled=self.config.cache_compiled,
@@ -344,6 +347,7 @@ class Qwen_FA3_Fuse(QwenBaseExperiment):
344
  def optimize(self):
345
  self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
346
  self.pipe.transformer.fuse_qkv_projections()
 
347
 
348
 
349
  @ExperimentRegistry.register(name="qwen_fa3")
@@ -352,6 +356,39 @@ class Qwen_FA3(QwenBaseExperiment):
352
  def optimize(self):
353
  self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
354
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
355
  @ExperimentRegistry.register(name="qwen_aot")
356
  class Qwen_AoT(QwenBaseExperiment):
357
  @ftimed
@@ -385,6 +422,23 @@ class Qwen_FA3_AoT(QwenBaseExperiment):
385
  }
386
  )
387
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
388
 
389
  @ExperimentRegistry.register(name="qwen_fa3_aot_int8")
390
  class Qwen_FA3_AoT_int8(QwenBaseExperiment):
@@ -403,13 +457,63 @@ class Qwen_FA3_AoT_int8(QwenBaseExperiment):
403
  }
404
  )
405
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
406
 
407
  @ExperimentRegistry.register(name="qwen_fp8")
408
  class Qwen_fp8(QwenBaseExperiment):
409
  @ftimed
410
  def optimize(self):
411
  self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
412
- quantize_(self.pipe.transformer, Float8WeightOnlyConfig())
413
 
414
 
415
  @ExperimentRegistry.register(name="qwen_int8")
@@ -417,8 +521,7 @@ class Qwen_int8(QwenBaseExperiment):
417
  @ftimed
418
  def optimize(self):
419
  self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
420
- quantize_(self.pipe.transformer, Int8WeightOnlyConfig())
421
-
422
 
423
 
424
 
@@ -473,6 +576,24 @@ class Qwen_FA3_AoT_fp8(QwenBaseExperiment):
473
 
474
  aoti_apply(compiled_transformer, self.pipe.transformer)
475
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
476
  # FA3_AoT_fp8_fuse
477
  @ExperimentRegistry.register(name="qwen_fa3_aot_fp8_fuse")
478
  class Qwen_FA3_AoT_fp8_fuse(QwenBaseExperiment):
@@ -481,6 +602,7 @@ class Qwen_FA3_AoT_fp8_fuse(QwenBaseExperiment):
481
  def optimize(self):
482
  self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
483
  self.pipe.transformer.fuse_qkv_projections()
 
484
 
485
  pipe_kwargs={
486
  "image": [Image.new("RGB", (1024, 1024))],
@@ -536,6 +658,7 @@ class Qwen_FA3_AoT_int8_fuse(QwenBaseExperiment):
536
  def optimize(self):
537
  self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
538
  self.pipe.transformer.fuse_qkv_projections()
 
539
  optimize_pipeline_(
540
  self.pipe,
541
  cache_compiled=self.config.cache_compiled,
@@ -557,6 +680,7 @@ class Qwen_lightning_FA3_AoT_fp8_fuse(Qwen_Lightning_Lora):
557
  def optimize(self):
558
  self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
559
  self.pipe.transformer.fuse_qkv_projections()
 
560
 
561
  pipe_kwargs={
562
  "image": [Image.new("RGB", (1024, 1024))],
@@ -612,6 +736,7 @@ class Qwen_Lightning_FA3_AoT_int8_fuse(Qwen_Lightning_Lora):
612
  def optimize(self):
613
  self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
614
  self.pipe.transformer.fuse_qkv_projections()
 
615
  optimize_pipeline_(
616
  self.pipe,
617
  cache_compiled=self.config.cache_compiled,
@@ -708,6 +833,7 @@ class Qwen_lightning_FA3_AoT_autoquant_fuse(Qwen_Lightning_Lora):
708
  def optimize(self):
709
  self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
710
  self.pipe.transformer.fuse_qkv_projections()
 
711
 
712
  pipe_kwargs={
713
  "image": [Image.new("RGB", (1024, 1024))],
@@ -782,6 +908,7 @@ class Qwen_Lightning_FA3_AoT_int8_fuse_2step_FBCache055_Downsize512(Qwen_Lightni
782
  def optimize(self):
783
  self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
784
  self.pipe.transformer.fuse_qkv_projections()
 
785
  apply_cache_on_pipe(self.pipe, residual_diff_threshold=0.55,)
786
  optimize_pipeline_(
787
  self.pipe,
@@ -814,6 +941,7 @@ class Qwen_Lightning_FA3_AoT_int8_fuse_Downsize512(Qwen_Lightning_Lora):
814
  def optimize(self):
815
  self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
816
  self.pipe.transformer.fuse_qkv_projections()
 
817
  optimize_pipeline_(
818
  self.pipe,
819
  cache_compiled=self.config.cache_compiled,
@@ -844,6 +972,7 @@ class Qwen_Lightning_FA3_AoT_int8_fuse_1step_FBCache055_Downsize512(Qwen_Lightni
844
  def optimize(self):
845
  self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
846
  self.pipe.transformer.fuse_qkv_projections()
 
847
  apply_cache_on_pipe(self.pipe, residual_diff_threshold=0.55,)
848
  optimize_pipeline_(
849
  self.pipe,
@@ -876,6 +1005,7 @@ class Qwen_Lightning_FA3_AoT_int8_fuse_4step_FBCache055_Downsize512(Qwen_Lightni
876
  def optimize(self):
877
  self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
878
  self.pipe.transformer.fuse_qkv_projections()
 
879
  apply_cache_on_pipe(self.pipe, residual_diff_threshold=0.55,)
880
  optimize_pipeline_(
881
  self.pipe,
 
21
  from torchao.utils import get_model_size_in_bytes
22
 
23
  from qwenimage.debug import ctimed, ftimed, print_first_param
24
+ from qwenimage.models.attention_processors import QwenDoubleStreamAttnProcessorFA3, QwenDoubleStreamAttnProcessorSageAttn2, sageattn_qk_int8_pv_fp16_cuda_wrapper, sageattn_qk_int8_pv_fp16_triton_wrapper, sageattn_qk_int8_pv_fp8_cuda_sm90_wrapper, sageattn_qk_int8_pv_fp8_cuda_wrapper, sageattn_wrapper
25
  from qwenimage.models.first_block_cache import apply_cache_on_pipe
26
  from qwenimage.models.pipeline_qwenimage_edit_plus import QwenImageEditPlusPipeline, calculate_dimensions
27
  from qwenimage.models.transformer_qwenimage import QwenImageTransformer2DModel
 
319
  @ftimed
320
  def optimize(self):
321
  self.pipe.transformer.fuse_qkv_projections()
322
+ self.pipe.transformer.check_fused_qkv()
323
 
324
 
325
  @ExperimentRegistry.register(name="qwen_fuse_aot")
 
327
  @ftimed
328
  def optimize(self):
329
  self.pipe.transformer.fuse_qkv_projections()
330
+ self.pipe.transformer.check_fused_qkv()
331
+
332
  optimize_pipeline_(
333
  self.pipe,
334
  cache_compiled=self.config.cache_compiled,
 
347
  def optimize(self):
348
  self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
349
  self.pipe.transformer.fuse_qkv_projections()
350
+ self.pipe.transformer.check_fused_qkv()
351
 
352
 
353
  @ExperimentRegistry.register(name="qwen_fa3")
 
356
  def optimize(self):
357
  self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
358
 
359
+
360
+ @ExperimentRegistry.register(name="qwen_sageattn")
361
+ class Qwen_Sageattn(QwenBaseExperiment):
362
+ @ftimed
363
+ def optimize(self):
364
+ self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorSageAttn2(sageattn_wrapper))
365
+
366
+ @ExperimentRegistry.register(name="qwen_sageattn_qk_int8_pv_fp16_cuda")
367
+ class Qwen_Sageattn_qk_int8_pv_fp16_cuda(QwenBaseExperiment):
368
+ @ftimed
369
+ def optimize(self):
370
+ self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorSageAttn2(sageattn_qk_int8_pv_fp16_cuda_wrapper))
371
+
372
+ @ExperimentRegistry.register(name="qwen_sageattn_qk_int8_pv_fp16_triton")
373
+ class Qwen_Sageattn_qk_int8_pv_fp16_triton(QwenBaseExperiment):
374
+ @ftimed
375
+ def optimize(self):
376
+ self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorSageAttn2(sageattn_qk_int8_pv_fp16_triton_wrapper))
377
+
378
+ @ExperimentRegistry.register(name="qwen_sageattn_qk_int8_pv_fp8_cuda")
379
+ class Qwen_Sageattn_qk_int8_pv_fp8_cuda(QwenBaseExperiment):
380
+ @ftimed
381
+ def optimize(self):
382
+ self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorSageAttn2(sageattn_qk_int8_pv_fp8_cuda_wrapper))
383
+
384
+ @ExperimentRegistry.register(name="qwen_sageattn_qk_int8_pv_fp8_cuda_sm90")
385
+ class Qwen_Sageattn_qk_int8_pv_fp8_cuda_sm90(QwenBaseExperiment):
386
+ @ftimed
387
+ def optimize(self):
388
+ self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorSageAttn2(sageattn_qk_int8_pv_fp8_cuda_sm90_wrapper))
389
+
390
+
391
+
392
  @ExperimentRegistry.register(name="qwen_aot")
393
  class Qwen_AoT(QwenBaseExperiment):
394
  @ftimed
 
422
  }
423
  )
424
 
425
+ @ExperimentRegistry.register(name="qwen_sage_aot")
426
+ class Qwen_Sage_AoT(QwenBaseExperiment):
427
+ @ftimed
428
+ def optimize(self):
429
+ self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorSageAttn2())
430
+ optimize_pipeline_(
431
+ self.pipe,
432
+ cache_compiled=self.config.cache_compiled,
433
+ quantize=False,
434
+ suffix="_sage",
435
+ pipe_kwargs={
436
+ "image": [Image.new("RGB", (1024, 1024))],
437
+ "prompt":"prompt",
438
+ "num_inference_steps":4
439
+ }
440
+ )
441
+
442
 
443
  @ExperimentRegistry.register(name="qwen_fa3_aot_int8")
444
  class Qwen_FA3_AoT_int8(QwenBaseExperiment):
 
457
  }
458
  )
459
 
460
+ @ExperimentRegistry.register(name="qwen_sage_aot_int8")
461
+ class Qwen_Sage_AoT_int8(QwenBaseExperiment):
462
+ @ftimed
463
+ def optimize(self):
464
+ self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorSageAttn2())
465
+ optimize_pipeline_(
466
+ self.pipe,
467
+ cache_compiled=self.config.cache_compiled,
468
+ quantize=True,
469
+ suffix="_sage",
470
+ pipe_kwargs={
471
+ "image": [Image.new("RGB", (1024, 1024))],
472
+ "prompt":"prompt",
473
+ "num_inference_steps":4
474
+ }
475
+ )
476
+
477
+ @ExperimentRegistry.register(name="qwen_sage_aot_int8da")
478
+ class Qwen_Sage_AoT_int8da(QwenBaseExperiment):
479
+ @ftimed
480
+ def optimize(self):
481
+ self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorSageAttn2(sageattn_qk_int8_pv_fp8_cuda_sm90_wrapper))
482
+ optimize_pipeline_(
483
+ self.pipe,
484
+ cache_compiled=self.config.cache_compiled,
485
+ quantize=True,
486
+ quantize_config=Int8DynamicActivationInt8WeightConfig(),
487
+ suffix="_int8da_sage",
488
+ pipe_kwargs={
489
+ "image": [Image.new("RGB", (1024, 1024))],
490
+ "prompt":"prompt",
491
+ "num_inference_steps":4
492
+ }
493
+ )
494
+
495
+ @ExperimentRegistry.register(name="qwen_fp8_weightonly")
496
+ class Qwen_fp8_Weightonly(QwenBaseExperiment):
497
+ @ftimed
498
+ def optimize(self):
499
+ self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
500
+ quantize_(self.pipe.transformer, Float8WeightOnlyConfig())
501
+
502
+
503
+ @ExperimentRegistry.register(name="qwen_int8_weightonly")
504
+ class Qwen_int8_Weightonly(QwenBaseExperiment):
505
+ @ftimed
506
+ def optimize(self):
507
+ self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
508
+ quantize_(self.pipe.transformer, Int8WeightOnlyConfig())
509
+
510
 
511
  @ExperimentRegistry.register(name="qwen_fp8")
512
  class Qwen_fp8(QwenBaseExperiment):
513
  @ftimed
514
  def optimize(self):
515
  self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
516
+ quantize_(self.pipe.transformer, Float8DynamicActivationFloat8WeightConfig())
517
 
518
 
519
  @ExperimentRegistry.register(name="qwen_int8")
 
521
  @ftimed
522
  def optimize(self):
523
  self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
524
+ quantize_(self.pipe.transformer, Int8DynamicActivationInt8WeightConfig())
 
525
 
526
 
527
 
 
576
 
577
  aoti_apply(compiled_transformer, self.pipe.transformer)
578
 
579
+ @ExperimentRegistry.register(name="qwen_sage_aot_fp8")
580
+ class Qwen_Sage_AoT_fp8(QwenBaseExperiment):
581
+ @ftimed
582
+ def optimize(self):
583
+ self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorSageAttn2())
584
+ optimize_pipeline_(
585
+ self.pipe,
586
+ cache_compiled=self.config.cache_compiled,
587
+ quantize=True,
588
+ quantize_config=Float8DynamicActivationFloat8WeightConfig(),
589
+ suffix="_fp8_sage",
590
+ pipe_kwargs={
591
+ "image": [Image.new("RGB", (1024, 1024))],
592
+ "prompt":"prompt",
593
+ "num_inference_steps":4
594
+ }
595
+ )
596
+
597
  # FA3_AoT_fp8_fuse
598
  @ExperimentRegistry.register(name="qwen_fa3_aot_fp8_fuse")
599
  class Qwen_FA3_AoT_fp8_fuse(QwenBaseExperiment):
 
602
  def optimize(self):
603
  self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
604
  self.pipe.transformer.fuse_qkv_projections()
605
+ self.pipe.transformer.check_fused_qkv()
606
 
607
  pipe_kwargs={
608
  "image": [Image.new("RGB", (1024, 1024))],
 
658
  def optimize(self):
659
  self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
660
  self.pipe.transformer.fuse_qkv_projections()
661
+ self.pipe.transformer.check_fused_qkv()
662
  optimize_pipeline_(
663
  self.pipe,
664
  cache_compiled=self.config.cache_compiled,
 
680
  def optimize(self):
681
  self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
682
  self.pipe.transformer.fuse_qkv_projections()
683
+ self.pipe.transformer.check_fused_qkv()
684
 
685
  pipe_kwargs={
686
  "image": [Image.new("RGB", (1024, 1024))],
 
736
  def optimize(self):
737
  self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
738
  self.pipe.transformer.fuse_qkv_projections()
739
+ self.pipe.transformer.check_fused_qkv()
740
  optimize_pipeline_(
741
  self.pipe,
742
  cache_compiled=self.config.cache_compiled,
 
833
  def optimize(self):
834
  self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
835
  self.pipe.transformer.fuse_qkv_projections()
836
+ self.pipe.transformer.check_fused_qkv()
837
 
838
  pipe_kwargs={
839
  "image": [Image.new("RGB", (1024, 1024))],
 
908
  def optimize(self):
909
  self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
910
  self.pipe.transformer.fuse_qkv_projections()
911
+ self.pipe.transformer.check_fused_qkv()
912
  apply_cache_on_pipe(self.pipe, residual_diff_threshold=0.55,)
913
  optimize_pipeline_(
914
  self.pipe,
 
941
  def optimize(self):
942
  self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
943
  self.pipe.transformer.fuse_qkv_projections()
944
+ self.pipe.transformer.check_fused_qkv()
945
  optimize_pipeline_(
946
  self.pipe,
947
  cache_compiled=self.config.cache_compiled,
 
972
  def optimize(self):
973
  self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
974
  self.pipe.transformer.fuse_qkv_projections()
975
+ self.pipe.transformer.check_fused_qkv()
976
  apply_cache_on_pipe(self.pipe, residual_diff_threshold=0.55,)
977
  optimize_pipeline_(
978
  self.pipe,
 
1005
  def optimize(self):
1006
  self.pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
1007
  self.pipe.transformer.fuse_qkv_projections()
1008
+ self.pipe.transformer.check_fused_qkv()
1009
  apply_cache_on_pipe(self.pipe, residual_diff_threshold=0.55,)
1010
  optimize_pipeline_(
1011
  self.pipe,
qwenimage/models/attention_processors.py CHANGED
@@ -5,6 +5,8 @@ import torch.nn.functional as F
5
  from typing import Optional, Tuple
6
  from diffusers.models.transformers.transformer_qwenimage import apply_rotary_emb_qwen
7
 
 
 
8
  try:
9
  from kernels import get_kernel
10
  _k = get_kernel("kernels-community/vllm-flash-attn3")
@@ -52,7 +54,7 @@ def flash_attn_func(
52
  return outputs
53
 
54
  @flash_attn_func.register_fake
55
- def _(q, k, v, **kwargs):
56
  # two outputs:
57
  # 1. output: (batch, seq_len, num_heads, head_dim)
58
  # 2. softmax_lse: (batch, num_heads, seq_len) with dtype=torch.float32
@@ -60,6 +62,68 @@ def _(q, k, v, **kwargs):
60
  return meta_q #, q.new_empty((q.size(0), q.size(2), q.size(1)), dtype=torch.float32)
61
 
62
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
 
64
  class QwenDoubleStreamAttnProcessorFA3:
65
  """
@@ -164,7 +228,7 @@ class QwenDoubleStreamAttnProcessor2_0:
164
  implements joint attention computation where text and image streams are processed together.
165
  """
166
 
167
- _attention_backend = None
168
 
169
  def __init__(self):
170
  if not hasattr(F, "scaled_dot_product_attention"):
@@ -253,22 +317,9 @@ class QwenDoubleStreamAttnProcessor2_0:
253
 
254
 
255
 
256
- class QwenDoubleStreamAttnProcessorFA3:
257
- """
258
- FA3-based attention processor for Qwen double-stream architecture.
259
- Computes joint attention over concatenated [text, image] streams using vLLM FlashAttention-3
260
- accessed via Hugging Face `kernels`.
261
-
262
- Notes / limitations:
263
- - General attention masks are not supported here (FA3 path). `is_causal=False` and no arbitrary mask.
264
- - Optional windowed attention / sink tokens / softcap can be plumbed through if you use those features.
265
- - Expects an available `apply_rotary_emb_qwen` in scope (same as your non-FA3 processor).
266
- """
267
-
268
- _attention_backend = "fa3" # for parity with your other processors, not used internally
269
-
270
- def __init__(self):
271
- _ensure_fa3_available()
272
 
273
  @torch.no_grad()
274
  def __call__(
@@ -329,9 +380,14 @@ class QwenDoubleStreamAttnProcessorFA3:
329
  q = torch.cat([txt_q, img_q], dim=1)
330
  k = torch.cat([txt_k, img_k], dim=1)
331
  v = torch.cat([txt_v, img_v], dim=1)
 
332
 
333
- # FlashAttention-3 path expects (B, S, H, D_h) and returns (out, softmax_lse)
334
- out = flash_attn_func(q, k, v, causal=False) # out: (B, S_total, H, D_h)
 
 
 
 
335
 
336
  # ---- Back to (B, S, D_model) ----
337
  out = out.flatten(2, 3).to(q.dtype)
 
5
  from typing import Optional, Tuple
6
  from diffusers.models.transformers.transformer_qwenimage import apply_rotary_emb_qwen
7
 
8
+ from sageattention import sageattn, sageattn_qk_int8_pv_fp16_cuda, sageattn_qk_int8_pv_fp16_triton, sageattn_qk_int8_pv_fp8_cuda, sageattn_qk_int8_pv_fp8_cuda_sm90
9
+
10
  try:
11
  from kernels import get_kernel
12
  _k = get_kernel("kernels-community/vllm-flash-attn3")
 
54
  return outputs
55
 
56
  @flash_attn_func.register_fake
57
+ def _fa(q, k, v, **kwargs):
58
  # two outputs:
59
  # 1. output: (batch, seq_len, num_heads, head_dim)
60
  # 2. softmax_lse: (batch, num_heads, seq_len) with dtype=torch.float32
 
62
  return meta_q #, q.new_empty((q.size(0), q.size(2), q.size(1)), dtype=torch.float32)
63
 
64
 
65
+ @torch.library.custom_op("sage::sageattn", mutates_args=())
66
+ def sageattn_wrapper(
67
+ q: torch.Tensor, k: torch.Tensor, v: torch.Tensor
68
+ ) -> torch.Tensor:
69
+ outputs = sageattn(q, k, v)
70
+ return outputs
71
+
72
+ @sageattn_wrapper.register_fake
73
+ def _sageattn_wrapper_fake(q, k, v):
74
+ meta_q = torch.empty_like(q).contiguous()
75
+ return meta_q
76
+
77
+ @torch.library.custom_op("sage::sageattn_qk_int8_pv_fp16_cuda", mutates_args=())
78
+ def sageattn_qk_int8_pv_fp16_cuda_wrapper(
79
+ q: torch.Tensor, k: torch.Tensor, v: torch.Tensor
80
+ ) -> torch.Tensor:
81
+ outputs = sageattn_qk_int8_pv_fp16_cuda(q, k, v)
82
+ return outputs
83
+
84
+ @sageattn_qk_int8_pv_fp16_cuda_wrapper.register_fake
85
+ def _sageattn_qk_int8_pv_fp16_cuda_wrapper_fake(q, k, v):
86
+ meta_q = torch.empty_like(q).contiguous()
87
+ return meta_q
88
+
89
+
90
+ @torch.library.custom_op("sage::sageattn_qk_int8_pv_fp16_triton", mutates_args=())
91
+ def sageattn_qk_int8_pv_fp16_triton_wrapper(
92
+ q: torch.Tensor, k: torch.Tensor, v: torch.Tensor
93
+ ) -> torch.Tensor:
94
+ outputs = sageattn_qk_int8_pv_fp16_triton(q, k, v)
95
+ return outputs
96
+
97
+ @sageattn_qk_int8_pv_fp16_triton_wrapper.register_fake
98
+ def _sageattn_qk_int8_pv_fp16_triton_wrapper_fake(q, k, v):
99
+ meta_q = torch.empty_like(q).contiguous()
100
+ return meta_q
101
+
102
+ @torch.library.custom_op("sage::sageattn_qk_int8_pv_fp8_cuda", mutates_args=())
103
+ def sageattn_qk_int8_pv_fp8_cuda_wrapper(
104
+ q: torch.Tensor, k: torch.Tensor, v: torch.Tensor
105
+ ) -> torch.Tensor:
106
+ outputs = sageattn_qk_int8_pv_fp8_cuda(q, k, v)
107
+ return outputs
108
+
109
+ @sageattn_qk_int8_pv_fp8_cuda_wrapper.register_fake
110
+ def _sageattn_qk_int8_pv_fp8_cuda_wrapper_fake(q, k, v):
111
+ meta_q = torch.empty_like(q).contiguous()
112
+ return meta_q
113
+
114
+ @torch.library.custom_op("sage::sageattn_qk_int8_pv_fp8_cuda_sm90", mutates_args=())
115
+ def sageattn_qk_int8_pv_fp8_cuda_sm90_wrapper(
116
+ q: torch.Tensor, k: torch.Tensor, v: torch.Tensor
117
+ ) -> torch.Tensor:
118
+ outputs = sageattn_qk_int8_pv_fp8_cuda_sm90(q, k, v)
119
+ return outputs
120
+
121
+ @sageattn_qk_int8_pv_fp8_cuda_sm90_wrapper.register_fake
122
+ def _sageattn_qk_int8_pv_fp8_cuda_sm90_wrapper_fake(q, k, v):
123
+ meta_q = torch.empty_like(q).contiguous()
124
+ return meta_q
125
+
126
+
127
 
128
  class QwenDoubleStreamAttnProcessorFA3:
129
  """
 
228
  implements joint attention computation where text and image streams are processed together.
229
  """
230
 
231
+ _attention_backend = None #"_native_flash"
232
 
233
  def __init__(self):
234
  if not hasattr(F, "scaled_dot_product_attention"):
 
317
 
318
 
319
 
320
+ class QwenDoubleStreamAttnProcessorSageAttn2:
321
+ def __init__(self, sageattn_func):
322
+ self.sageattn_func = sageattn_func
 
 
 
 
 
 
 
 
 
 
 
 
 
323
 
324
  @torch.no_grad()
325
  def __call__(
 
380
  q = torch.cat([txt_q, img_q], dim=1)
381
  k = torch.cat([txt_k, img_k], dim=1)
382
  v = torch.cat([txt_v, img_v], dim=1)
383
+
384
 
385
+ # sage attention
386
+ q = q.transpose(1, 2) # (B, H, S, D_h)
387
+ k = k.transpose(1, 2)
388
+ v = v.transpose(1, 2)
389
+ out = self.sageattn_func(q, k, v) # out: (B, H, S, D_h)
390
+ out = out.transpose(1, 2) # to (B, S, H, D_h)
391
 
392
  # ---- Back to (B, S, D_model) ----
393
  out = out.flatten(2, 3).to(q.dtype)
qwenimage/models/transformer_qwenimage.py CHANGED
@@ -549,8 +549,16 @@ class QwenImageTransformer2DModel(ModelMixin, ConfigMixin, PeftAdapterMixin, Fro
549
  """
550
  Override AttenionMixin
551
  """
 
552
  super().fuse_qkv_projections()
553
 
554
  for module in self.modules():
555
  if isinstance(module, Attention):
556
- module.fuse_projections()
 
 
 
 
 
 
 
 
549
  """
550
  Override AttenionMixin
551
  """
552
+ print("override")
553
  super().fuse_qkv_projections()
554
 
555
  for module in self.modules():
556
  if isinstance(module, Attention):
557
+ module.fuse_projections()
558
+
559
+ def check_fused_qkv(self):
560
+ fused = all([b.attn.fused_projections for b in self.transformer_blocks])
561
+ if fused:
562
+ print(f"All attention fused!")
563
+ else:
564
+ print({i:b.attn.fused_projections for i,b in enumerate(self.transformer_blocks)})
qwenimage/optimization.py CHANGED
@@ -6,6 +6,7 @@ from typing import Any
6
  from typing import Callable
7
  from typing import ParamSpec
8
  from spaces.zero.torch.aoti import ZeroGPUCompiledModel, ZeroGPUWeights
 
9
  from torchao.quantization import quantize_
10
  from torchao.quantization import Int8WeightOnlyConfig
11
  import spaces
@@ -73,12 +74,20 @@ def optimize_pipeline_(
73
  pipeline: Callable[P, Any],
74
  cache_compiled=True,
75
  quantize=True,
 
76
  inductor_config=None,
77
  suffix="",
78
  pipe_kwargs={}
79
  ):
80
 
81
- if quantize:
 
 
 
 
 
 
 
82
  transformer_pt2_cache_path = f"checkpoints/transformer_int8{suffix}_archive.pt2"
83
  transformer_weights_cache_path = f"checkpoints/transformer_int8{suffix}_weights.pt"
84
  print(f"original model size: {get_model_size_in_bytes(pipeline.transformer) / 1024 / 1024} MB")
 
6
  from typing import Callable
7
  from typing import ParamSpec
8
  from spaces.zero.torch.aoti import ZeroGPUCompiledModel, ZeroGPUWeights
9
+ from torchao.core.config import AOBaseConfig
10
  from torchao.quantization import quantize_
11
  from torchao.quantization import Int8WeightOnlyConfig
12
  import spaces
 
74
  pipeline: Callable[P, Any],
75
  cache_compiled=True,
76
  quantize=True,
77
+ quantize_config:AOBaseConfig=None,
78
  inductor_config=None,
79
  suffix="",
80
  pipe_kwargs={}
81
  ):
82
 
83
+ if quantize and quantize_config is not None:
84
+ transformer_pt2_cache_path = f"checkpoints/transformer{suffix}_archive.pt2"
85
+ transformer_weights_cache_path = f"checkpoints/transformer{suffix}_weights.pt"
86
+ print(f"original model size: {get_model_size_in_bytes(pipeline.transformer) / 1024 / 1024} MB")
87
+ quantize_(pipeline.transformer, quantize_config)
88
+ print_first_param(pipeline.transformer)
89
+ print(f"quantized model size: {get_model_size_in_bytes(pipeline.transformer) / 1024 / 1024} MB")
90
+ elif quantize:
91
  transformer_pt2_cache_path = f"checkpoints/transformer_int8{suffix}_archive.pt2"
92
  transformer_weights_cache_path = f"checkpoints/transformer_int8{suffix}_weights.pt"
93
  print(f"original model size: {get_model_size_in_bytes(pipeline.transformer) / 1024 / 1024} MB")
qwenimage/reporting/__init__.py ADDED
File without changes
qwenimage/reporting/datamodels.py ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel
2
+ from PIL import Image
3
+
4
+ from qwenimage.experiment import ExperimentConfig
5
+
6
+
7
+ class ExperimentSet(BaseModel):
8
+ original: str
9
+ comparisons: list[str]
10
+
11
+ @classmethod
12
+ def create(cls, *names):
13
+ if len(names)<2:
14
+ raise ValueError(f"{len(names)=}")
15
+ orig = names[0]
16
+ comp = names[1:]
17
+ return cls(original=orig, comparisons=comp)
18
+
19
+ class SetData:
20
+ def __init__(self, name: str):
21
+ self.name=name
22
+ report_dir = ExperimentConfig().report_dir
23
+ output_dir = report_dir / f"{name}_outputs"
24
+ self.image_paths = sorted(list(output_dir.glob("*.jpg")))
25
+
26
+ def __len__(self):
27
+ return len(self.image_paths)
28
+
29
+ def __getitem__(self, ind):
30
+ return Image.open(self.image_paths[ind])
qwenimage/{reporting.py → reporting/lpips_metric.py} RENAMED
@@ -2,6 +2,7 @@ import math
2
  from pathlib import Path
3
  from collections import defaultdict
4
  import statistics
 
5
 
6
  from pydantic import BaseModel
7
  import pandas as pd
@@ -13,35 +14,6 @@ import torch
13
  import torchvision.transforms.v2 as T
14
  import torchvision.transforms.v2.functional as TF
15
 
16
- from qwenimage.experiment import ExperimentConfig
17
- from qwenimage.experiments.experiments_qwen import ExperimentRegistry
18
-
19
-
20
- class ExperimentSet(BaseModel):
21
- original: str
22
- comparisons: list[str]
23
-
24
- @classmethod
25
- def create(cls, *names):
26
- if len(names)<2:
27
- raise ValueError(f"{len(names)=}")
28
- orig = names[0]
29
- comp = names[1:]
30
- return cls(original=orig, comparisons=comp)
31
-
32
- class SetData:
33
- def __init__(self, name: str):
34
- self.name=name
35
- report_dir = ExperimentConfig().report_dir
36
- output_dir = report_dir / f"{name}_outputs"
37
- self.image_paths = sorted(list(output_dir.glob("*.jpg")))
38
-
39
- def __len__(self):
40
- return len(self.image_paths)
41
-
42
- def __getitem__(self, ind):
43
- return Image.open(self.image_paths[ind])
44
-
45
 
46
  _transforms = T.Compose([
47
  T.ToImage(),
@@ -66,3 +38,21 @@ def compare_lpips(loss_fn, image1, image2, resize=False, device="cuda", to_item=
66
  if to_item:
67
  return score.float().item()
68
  return score
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  from pathlib import Path
3
  from collections import defaultdict
4
  import statistics
5
+ from typing import Literal
6
 
7
  from pydantic import BaseModel
8
  import pandas as pd
 
14
  import torchvision.transforms.v2 as T
15
  import torchvision.transforms.v2.functional as TF
16
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
  _transforms = T.Compose([
19
  T.ToImage(),
 
38
  if to_item:
39
  return score.float().item()
40
  return score
41
+
42
+ class LpipsCalculator:
43
+ def __init__(self, resize=False, device="cuda", to_item=True):
44
+ self.resize = resize
45
+ self.to_item = to_item
46
+ self.loss_fn = lpips.LPIPS(net='alex')
47
+ if torch.cuda.is_available():
48
+ self.device = "cuda"
49
+ else:
50
+ self.device = "cpu"
51
+ self.loss_fn = self.loss_fn.to(device=self.device)
52
+
53
+ def __call__(self, image1, image2, resize=None, to_item=None):
54
+ if resize is None:
55
+ resize = self.resize
56
+ if to_item is None:
57
+ to_item = self.to_item
58
+ return compare_lpips(self.loss_fn, image1, image2, resize=resize, device=self.device, to_item=to_item)
qwenimage/reporting/visualize_barplot.py ADDED
@@ -0,0 +1,235 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+ from pathlib import Path
3
+ from collections import defaultdict
4
+ import statistics
5
+ from typing import Literal
6
+
7
+ from pydantic import BaseModel
8
+ import pandas as pd
9
+ from matplotlib import pyplot as plt
10
+ from PIL import Image
11
+ import numpy as np
12
+ import lpips
13
+ import torch
14
+ import torchvision.transforms.v2 as T
15
+ import torchvision.transforms.v2.functional as TF
16
+
17
+ from qwenimage.experiment import ExperimentConfig
18
+ from qwenimage.experiments.experiments_qwen import ExperimentRegistry
19
+ from qwenimage.reporting.datamodels import ExperimentSet, SetData
20
+ from qwenimage.reporting.lpips_metric import compare_lpips
21
+
22
+ def compare_sets(experiment_set:ExperimentSet, sort_by_mean=False, loss_fn=None):
23
+ original_data = SetData(name=experiment_set.original)
24
+ comparison_data = [SetData(name=comp) for comp in experiment_set.comparisons]
25
+
26
+ if loss_fn is None:
27
+ loss_fn = lpips.LPIPS(net='alex') # or 'vgg' or 'squeeze'
28
+ if torch.cuda.is_available():
29
+ loss_fn = loss_fn.cuda()
30
+
31
+ all_set_errors = defaultdict(list)
32
+ for i in range(len(original_data)):
33
+ for comp in comparison_data:
34
+ lpips_error = compare_lpips(loss_fn, original_data[i], comp[i])
35
+ all_set_errors[comp.name].append(lpips_error)
36
+
37
+ error_stat_list = []
38
+ for name, errors in all_set_errors.items():
39
+ err_mean = statistics.mean(errors)
40
+ err_std = statistics.stdev(errors)
41
+ err_len = len(errors)
42
+ error_stat_list.append({
43
+ 'name': f"{name}",
44
+ 'mean': err_mean,
45
+ 'std': err_std,
46
+ 'len': err_len
47
+ })
48
+
49
+ err_df = pd.DataFrame(error_stat_list)
50
+ report_dir = ExperimentConfig().report_dir
51
+ err_df.to_csv(report_dir / f"{experiment_set.original}_{'_'.join(experiment_set.comparisons)[:100]}.csv")
52
+
53
+ if sort_by_mean:
54
+ err_df = err_df.sort_values('mean', ascending=False)
55
+
56
+
57
+ fig, ax = plt.subplots(figsize=(12, 6))
58
+ x_pos = range(len(err_df))
59
+
60
+ # bar_x = err_df["name"]
61
+ bar_h = err_df["mean"]
62
+ bar_std = err_df["std"]
63
+ bars = ax.bar(
64
+ x_pos, bar_h, yerr=bar_std,
65
+ capsize=12, alpha=0.7, edgecolor='black'
66
+ )
67
+
68
+ ax.set_xlabel('LPIPS error for experiment type', fontsize=12, fontweight='bold')
69
+ ax.set_ylabel('Error', fontsize=12, fontweight='bold')
70
+ ax.set_title(f"LPIPS comparison",
71
+ fontsize=14, fontweight='bold')
72
+
73
+
74
+ ax.set_xticks(x_pos)
75
+ ax.set_xticklabels(
76
+ # [row['experiment'] for _, row in plot_data.iterrows()],
77
+ err_df["name"],
78
+ rotation=15, ha='right', fontsize=12
79
+ )
80
+
81
+ ax.grid(axis='y', alpha=0.3)
82
+
83
+
84
+ for i, (idx, row) in enumerate(err_df.iterrows()):
85
+ ax.text(i - 0.2, row['mean'] + 0.01, f"{row['mean']:.3f}",
86
+ ha='center', va='bottom', fontsize=12)
87
+
88
+ plt.tight_layout()
89
+
90
+ plot_path = report_dir / f"{experiment_set.original}_{'_'.join(experiment_set.comparisons)[:100]}.png"
91
+ plt.savefig(plot_path, dpi=300, bbox_inches='tight')
92
+
93
+ plt.show()
94
+
95
+
96
+
97
+ def compare_sets_with_timing(experiment_set: ExperimentSet, profile_target: str = "loop", sort_by="time", loss_fn=None, match_strategy:Literal["equal", "contain"]="equal"):
98
+ """
99
+ Create dual-axis bar plot with LPIPS error (left) and profile time (right) for each experiment.
100
+
101
+ Args:
102
+ experiment_set: ExperimentSet with original and comparison experiments
103
+ profile_target: Which profile target to plot timing for (e.g., "loop", "run_once")
104
+ sort_by: Sort experiments by "time", "lpips", or None
105
+ loss_fn: LPIPS loss function (will create if None)
106
+ """
107
+ # Get LPIPS data
108
+ original_data = SetData(name=experiment_set.original)
109
+ comparison_data = [SetData(name=comp) for comp in experiment_set.comparisons]
110
+
111
+ if loss_fn is None:
112
+ loss_fn = lpips.LPIPS(net='alex')
113
+ if torch.cuda.is_available():
114
+ loss_fn = loss_fn.cuda()
115
+
116
+ all_set_errors = defaultdict(list)
117
+ for i in range(len(original_data)):
118
+ for comp in comparison_data:
119
+ lpips_error = compare_lpips(loss_fn, original_data[i], comp[i])
120
+ all_set_errors[comp.name].append(lpips_error)
121
+
122
+ lpips_stats = []
123
+ # Add the original experiment with LPIPS = 0.0 (compared to itself)
124
+ lpips_stats.append({
125
+ 'experiment': experiment_set.original,
126
+ 'lpips_mean': 0.0,
127
+ 'lpips_std': 0.0
128
+ })
129
+ # Add comparison experiments
130
+ for name, errors in all_set_errors.items():
131
+ err_mean = statistics.mean(errors)
132
+ err_std = statistics.stdev(errors)
133
+ lpips_stats.append({
134
+ 'experiment': name,
135
+ 'lpips_mean': err_mean,
136
+ 'lpips_std': err_std
137
+ })
138
+
139
+ lpips_df = pd.DataFrame(lpips_stats)
140
+
141
+ # Get timing data
142
+ report_dir = ExperimentConfig().report_dir
143
+ timing_data = []
144
+ # Include original and all comparisons
145
+ all_experiments = [experiment_set.original] + list(experiment_set.comparisons)
146
+ for name in all_experiments:
147
+ csv_path = report_dir / f"{name}.csv"
148
+ if csv_path.exists():
149
+ df = pd.read_csv(csv_path, index_col=0)
150
+ if match_strategy == "equal":
151
+ target_row = df[df['name'] == profile_target]
152
+ elif match_strategy == "contain":
153
+ target_row = df[df['name'].str.contains(profile_target, case=False, na=False)]
154
+ else:
155
+ raise ValueError()
156
+
157
+ if not target_row.empty:
158
+ timing_data.append({
159
+ 'experiment': name,
160
+ 'time_mean': target_row['mean'].values[0],
161
+ 'time_std': target_row['std'].values[0]
162
+ })
163
+
164
+ timing_df = pd.DataFrame(timing_data)
165
+
166
+ # Merge data
167
+ combined_df = pd.merge(lpips_df, timing_df, on='experiment', how='inner')
168
+
169
+ # Sort if requested
170
+ if sort_by == "time":
171
+ combined_df = combined_df.sort_values('time_mean', ascending=False)
172
+ elif sort_by == "lpips":
173
+ combined_df = combined_df.sort_values('lpips_mean', ascending=False)
174
+
175
+ # Create dual-axis plot
176
+ fig, ax1 = plt.subplots(figsize=(14, 7))
177
+
178
+ x = np.arange(len(combined_df))
179
+ width = 0.35
180
+
181
+ # Left axis - LPIPS
182
+ ax1.set_xlabel('Experiment', fontsize=12, fontweight='bold')
183
+ ax1.set_ylabel('LPIPS Error', fontsize=12, fontweight='bold', color='tab:blue')
184
+ bars1 = ax1.bar(x - width/2, combined_df['lpips_mean'], width,
185
+ yerr=combined_df['lpips_std'], capsize=5,
186
+ label='LPIPS Error', color='tab:blue', alpha=0.7, edgecolor='black')
187
+ ax1.tick_params(axis='y', labelcolor='tab:blue')
188
+ ax1.grid(axis='y', alpha=0.3)
189
+
190
+ # Right axis - Time
191
+ ax2 = ax1.twinx()
192
+ ax2.set_ylabel(f'Time (s) - {profile_target}', fontsize=12, fontweight='bold', color='tab:orange')
193
+ bars2 = ax2.bar(x + width/2, combined_df['time_mean'], width,
194
+ yerr=combined_df['time_std'], capsize=5,
195
+ label=f'{profile_target} Time', color='tab:orange', alpha=0.7, edgecolor='black')
196
+ ax2.tick_params(axis='y', labelcolor='tab:orange')
197
+
198
+ # Align both axes to start at 0
199
+ ax1.set_ylim(bottom=0)
200
+ ax2.set_ylim(bottom=0)
201
+
202
+ # Set x-axis labels
203
+ ax1.set_xticks(x)
204
+ ax1.set_xticklabels(combined_df['experiment'], rotation=45, ha='right', fontsize=10)
205
+
206
+ # Add value labels on bars
207
+ for i, row in combined_df.iterrows():
208
+ idx = combined_df.index.get_loc(i)
209
+ # LPIPS value
210
+ ax1.text(idx - width/2, row['lpips_mean'] + row['lpips_std'] + 0.001,
211
+ f"{row['lpips_mean']:.4f}", ha='center', va='bottom',
212
+ fontsize=9, color='tab:blue')
213
+ # Time value
214
+ ax2.text(idx + width/2, row['time_mean'] + row['time_std'] + 0.01,
215
+ f"{row['time_mean']:.3f}s", ha='center', va='bottom',
216
+ fontsize=9, color='tab:orange')
217
+
218
+ # Title and legend
219
+ ax1.set_title(f'LPIPS Error vs {profile_target.title()} Time Comparison\nBaseline: {experiment_set.original}',
220
+ fontsize=14, fontweight='bold', pad=20)
221
+
222
+ # Combine legends
223
+ lines1, labels1 = ax1.get_legend_handles_labels()
224
+ lines2, labels2 = ax2.get_legend_handles_labels()
225
+ ax1.legend(lines1 + lines2, labels1 + labels2, loc='upper left', fontsize=10)
226
+
227
+ plt.tight_layout()
228
+
229
+ # Save plot
230
+ plot_path = report_dir / f"{experiment_set.original}_dual_axis_{profile_target}.png"
231
+ plt.savefig(plot_path, dpi=300, bbox_inches='tight')
232
+
233
+ plt.show()
234
+
235
+ return combined_df
scripts/attn_eval.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
scripts/fuse_eval.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
scripts/quant_eval.ipynb ADDED
@@ -0,0 +1,266 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": 1,
6
+ "id": "e76b6794",
7
+ "metadata": {},
8
+ "outputs": [
9
+ {
10
+ "name": "stdout",
11
+ "output_type": "stream",
12
+ "text": [
13
+ "/home/ubuntu/Qwen-Image-Edit-Angles\n"
14
+ ]
15
+ }
16
+ ],
17
+ "source": [
18
+ "%cd /home/ubuntu/Qwen-Image-Edit-Angles"
19
+ ]
20
+ },
21
+ {
22
+ "cell_type": "code",
23
+ "execution_count": null,
24
+ "id": "f0f4ce28",
25
+ "metadata": {},
26
+ "outputs": [
27
+ {
28
+ "name": "stderr",
29
+ "output_type": "stream",
30
+ "text": [
31
+ "/usr/lib/python3/dist-packages/scipy/__init__.py:146: UserWarning: A NumPy version >=1.17.3 and <1.25.0 is required for this version of SciPy (detected version 1.26.4\n",
32
+ " warnings.warn(f\"A NumPy version >={np_minversion} and <{np_maxversion}\"\n",
33
+ "/home/ubuntu/.local/lib/python3.10/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
34
+ " from .autonotebook import tqdm as notebook_tqdm\n",
35
+ "Skipping import of cpp extensions due to incompatible torch version 2.9.1+cu128 for torchao version 0.14.1 Please see https://github.com/pytorch/ao/issues/2919 for more info\n",
36
+ "TMA benchmarks will be running without grid constant TMA descriptor.\n",
37
+ "2025-11-19 09:44:55.971435: I tensorflow/core/util/port.cc:153] oneDNN custom operations are on. You may see slightly different numerical results due to floating-point round-off errors from different computation orders. To turn them off, set the environment variable `TF_ENABLE_ONEDNN_OPTS=0`.\n",
38
+ "2025-11-19 09:44:55.985769: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:467] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered\n",
39
+ "WARNING: All log messages before absl::InitializeLog() is called are written to STDERR\n",
40
+ "E0000 00:00:1763545496.003110 2604295 cuda_dnn.cc:8579] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered\n",
41
+ "E0000 00:00:1763545496.009514 2604295 cuda_blas.cc:1407] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered\n",
42
+ "W0000 00:00:1763545496.021977 2604295 computation_placer.cc:177] computation placer already registered. Please check linkage and avoid linking the same target more than once.\n",
43
+ "W0000 00:00:1763545496.021992 2604295 computation_placer.cc:177] computation placer already registered. Please check linkage and avoid linking the same target more than once.\n",
44
+ "W0000 00:00:1763545496.021994 2604295 computation_placer.cc:177] computation placer already registered. Please check linkage and avoid linking the same target more than once.\n",
45
+ "W0000 00:00:1763545496.021996 2604295 computation_placer.cc:177] computation placer already registered. Please check linkage and avoid linking the same target more than once.\n",
46
+ "2025-11-19 09:44:56.026039: I tensorflow/core/platform/cpu_feature_guard.cc:210] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.\n",
47
+ "To enable the following instructions: AVX512F AVX512_VNNI AVX512_BF16 AVX512_FP16 AVX_VNNI, in other operations, rebuild TensorFlow with the appropriate compiler flags.\n",
48
+ "/usr/lib/python3/dist-packages/sklearn/utils/fixes.py:25: UserWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html. The pkg_resources package is slated for removal as early as 2025-11-30. Refrain from using this package or pin to Setuptools<81.\n",
49
+ " from pkg_resources import parse_version # type: ignore\n",
50
+ "Fetching 7 files: 100%|██████████| 7/7 [00:00<00:00, 75282.38it/s]\n"
51
+ ]
52
+ }
53
+ ],
54
+ "source": [
55
+ "from qwenimage.reporting.datamodels import ExperimentSet\n",
56
+ "from qwenimage.reporting.visualize_barplot import compare_sets_with_timing"
57
+ ]
58
+ },
59
+ {
60
+ "cell_type": "code",
61
+ "execution_count": 3,
62
+ "id": "226af1b2",
63
+ "metadata": {},
64
+ "outputs": [
65
+ {
66
+ "name": "stderr",
67
+ "output_type": "stream",
68
+ "text": [
69
+ "/home/ubuntu/.local/lib/python3.10/site-packages/torchvision/models/_utils.py:208: UserWarning: The parameter 'pretrained' is deprecated since 0.13 and may be removed in the future, please use 'weights' instead.\n",
70
+ " warnings.warn(\n",
71
+ "/home/ubuntu/.local/lib/python3.10/site-packages/torchvision/models/_utils.py:223: UserWarning: Arguments other than a weight enum or `None` for 'weights' are deprecated since 0.13 and may be removed in the future. The current behavior is equivalent to passing `weights=AlexNet_Weights.IMAGENET1K_V1`. You can also use `weights=AlexNet_Weights.DEFAULT` to get the most up-to-date weights.\n",
72
+ " warnings.warn(msg)\n"
73
+ ]
74
+ },
75
+ {
76
+ "name": "stdout",
77
+ "output_type": "stream",
78
+ "text": [
79
+ "Setting up [LPIPS] perceptual loss: trunk [alex], v[0.1], spatial [off]\n",
80
+ "Loading model from: /home/ubuntu/.local/lib/python3.10/site-packages/lpips/weights/v0.1/alex.pth\n"
81
+ ]
82
+ },
83
+ {
84
+ "data": {
85
+ "image/png": "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a6+9Nk8//TR77rkn55xzDj16dK6hwxprrMG7777L2LFjOe2001h33XUZN24cH//4x9luu+0466yzmDlzJtdccw2bbLIJr7/+OieddBITJ04E4Mwzz2SPPfZYrp+LJEmSJGnFdPsEvZyuuuoqxo0bxyOPPMLUqVPZZZdd2HPPPbnrrrs6XA9w33338eSTT7LRRhux3377cdVVV/GJT3ximc/9yCOPMH78eAYOHMjGG2/M8ccfz3333cdZZ53F7373O84880y++tWvcsopp/CBD3yAiRMn8pGPfITx48ev7B+DJEmSJKkTTNC70J133smnPvUpqqqqWHfddRk1ahT333//YtevueaajBw5ko033hiAT33qU9x5553LlaDvsssurL/++gBssskmfPjDHwZgu+2247bbbgPglltu4cknn5y/z7Rp03jnnXfo37//ir51SZIkSdIyMkHvQimlZVoPEBFLXO6sXr16zX/do0eP+cs9evRgzpw5AMybN4+7776bPn36LNc5JEmSJEkrj6O4d6E999yTyy67jLlz5/L6669zxx13MHLkyMWuh6yJ+wsvvMC8efO47LLL+MAHPtBl8X34wx/m7LPPnr88bty4LjuXJEmSJGnJTNC70CGHHML222/PDjvswN57780vfvEL1ltvvcWuB3j/+99PQ0MD2267LcOHD+eQQw7psvh++9vf8sADD7D99tuz9dZbc+6553bZuSRJkiRJSxZLam5d6fr165emT5++0Lrx48ez1VZbzV9elaZZ62jqtErV/ucsSZIkldPo0aOB7Dt1ORww6n0rdfaoVcUBf5zAdbc/WO4wligiZqSU+pU7js7o9n3QyzlnuSRJkiRJndXtE/RVyejRo+ff+ZMkSZIkrV7sgy5JkiRJUgXolgn6qtyvflXgz1eSJEmSVr5ul6D37t2bN954wySyi6SUeOONN+jdu3e5Q5EkSZKkbqXb9UEfOnQokyZN4vXXXy93KN1W7969GTp0aLnDkCRJkqRupdsl6DU1NQwfPrzcYUiSJEmStEy6XRN3SZIkSZJWRSbokiRJkiRVABN0SZIkSZIqgAm6JEmSJEkVoNsNEidJkiSpfA498mgmTn615Od96pFHANhl1L4lPzfAjOYXgU3Lcm51HyVL0OsamvYDzgKqgD83N9Y3dlBmNHAmUANMbW6sH1Wq+CRJkiStuImTX2X7435a8vNOajwJoCznBrjj1A+V5bzqXkrSxL2uoakK+D2wP7A18Km6hqat25UZAJwDHNjcWL8N8MlSxCZJkiRJUiUoVR/0kcCE5sb655sb62cDlwIHtStzJHBVc2P9RIDmxvopJYpNkiRJkqSyK1UT9yHAS0XLk4Bd25XZHKipa2gaC/QHzmpurL+w/YEi4gTgBICamhqmTp3aJQFLkiRJWnYbDtmAgdXvlfy81TEPoCznBuhZU8Ps2bPLcu5ymjNnrjnZSlSqBD06WJfaLVcD7wP2AfoAd9c1NN3T3Fj/zEI7pTQGGAPQr1+/NGjQoC4IV5IkSdLymDj5ZQbM6VXy885JWePgN8twboDZra307NmzLOcup+rqKszJVp5SJeiTgGFFy0OBlzsoM7W5sX46ML2uoekOYAfgGSRJkiRJ6uZKlaDfD2xW19A0HJgMHEHW57zYP4Gz6xqaqoGeZE3gf1Oi+CRJkiRJKquSDBLX3Fg/BzgZ+BcwHri8ubH+ibqGppPqGppOysuMB24CHgXuI5uK7fFSxCdJkiRJUrmVbB705sb6G4Ab2q07t93yL4FfliomSZIkSZIqRammWZMkSZIkSUtggi5JkiRJUgUwQZckSZIkqQKYoEuSJEmSVAFM0CVJkiRJqgAm6JIkSZIkVQATdEmSJEmSKoAJuiRJkiRJFcAEXZIkSZKkClBd7gAkSZIkSSqbQu0pwPFAAh4DjqPQMqscoViDLkmSJElaPRVqhwBfAXam0LItUAUcUa5wTNAlSZIkSauzaqAPhdpqoC/wcrkCMUGXJEmSJHVn1RHxQNHjhPlbCi2TgV8BE4FXgBYKLTeXKU4TdEmSJElStzYnpbRz0WPM/C2F2rWAg4DhwAZAPwq1ny5TnCbokiRJkqTV1oeAFyi0vE6hpRW4Cti9XME4irskSZIkaXU1EdiNQm1fYCawD/BAuYKxBl2SJEmStHoqtNwLXAE8RDbFWg9gzBL36ULWoEuSJEmSVl+FltOA08odBliDLkmSJElSRbAGXZIkSdIq56FrxjDun39eZP15x41caHnEQcez08EnLFJOqkQm6JIkSZJWOTsdfIKJt7odm7hLkiRJklQBTNAlSZIkSaoAJuiSJEmSJFUAE3RJkiRJkiqACbokSZIkSRXABF2SJEmSpApggi5JkiRJUgUwQZckSZIkqQKYoEuSJEmSVAFM0CVJkiRJqgAm6JIkSZIkVQATdEmSJEmSKoAJuiRJkiRJFcAEXZIkSZKkCmCCLkmSJElSBTBBlyRJkiSpAlSX6kR1DU37AWcBVcCfmxvrG9ttHw38E3ghX3VVc2P9D0sVnyRJkiRJ5VSSBL2uoakK+D2wLzAJuL+uoena5sb6J9sV/W9zY/3HShGTJEmSJEmVpFRN3EcCE5ob659vbqyfDVwKHFSic0uSJEmSVPFK1cR9CPBS0fIkYNcOyr2/rqHpEeBl4JvNjfVPtC8QEScAJwDU1NQwderULghXkiRJ0vLYcMgGDKx+r9xhlFzPmhpmz55d7jBKbs6cueZkK1GpEvToYF1qt/wQsFFzY/27dQ1NHwWuATZbZKeUxgBjAPr165cGDRq0kkOVJEmStLwmTn6ZAXN6lTuMkpvd2krPnj3LHUbJVVdXYU628pQqQZ8EDCtaHkpWSz5fc2P9tKLXN9Q1NJ1T19A0qLmx3tsxkiRJy+gfD7zEJfdNJCI4/cBt2HZI7fxt1z7yMhfe1UyPCNboXc1ZR4ygf+8abnt6Cr/59zP0qu7BBgP6cMYnd6C6KusR+faM2ez5i9s4/aBtOGTHocyeM49TLhvHlHdmMXtu4jsf2YLdN/VLuiStiFIl6PcDm9U1NA0HJgNHAEcWF6hraFoPeK25sT7VNTSNJOsf/0aJ4pMkSeo2Wma0csFdzVz9xT14bdosTrlsHFd8Yff52/fbZj0O3GEDAH5989Nc/fBkjnl/Hb+++Rn+8OmdGLpWX75x+SP8d8JU9tpiMADnjH2OnesGzj/Gf599nT49q/jHSbvz0pszOPmSh/mnCbokrZCSDBLX3Fg/BzgZ+BcwHri8ubH+ibqGppPqGppOyot9Ang874P+W+CI5sb69s3gJUmStBQPv/QWu9QNpGd1D4YN7Mv02XN5b87c+dt7Vi/4CjizdS6bDe4PwGbrrsG0mXNIKfHOrFbW7pc115389kymTJvFdkW18But3ZfZc+aRUqJlZiuD+q1+TXslaWUr2TzozY31NwA3tFt3btHrs4GzSxWPJElSd9Uys5XaPjXzl/v3rqZlRiuD16yav+6y+ydy3p3N9K7pwUmjNgHg0J2G8pnz76N/r2q2Wn9Nth86AICzbnmGk/felOseeWX+/sMG9mVW61z2OeN2ps1q5c+f2aU0b06SurFSTbMmSZKkEqntU8O0Wa3zl9+ZNYfavjULlTl8lw351yl7sv926zPmjucBOPXqx/jnl/bg1m+OprZvDU2PvsJTr04jCDbNa9nbXPngZDYY0Idbvzmaq7+4B9+9+rGuf2OS1M2VrAZdkiRJpbHjsLU44+ZnaJ07jynvvEe/nlX0ql5Qez6rdS69a7LlNXvXMHN21vy9KmJ+zfva/Xry9szZPDZpDs9PfZdjzruPF9+YTp+aKoYPWoNEYq2+WbP22r41TH9vTonfpSR1PybokiRJ3Uxt3xqO3m0jDv/j3UQEpx2wNU+83MKdz07lxFGbMOaO5/nfhGyinAF9a/jFJ3YA4Bsf3oIj/3QPvaqrWLNPNSeN2oR+var55M7ZZDy/+fcz1A3qy4hhA9h83TX4yiUPc9gf72ZW61y++ZEtyvZ+Jam7iJRW3XHY+vXrl6ZPn17uMCRJkiTldhm1L9sf99Nyh1Fyd5z6IZ791X7lDqPkDvjjBK67/cFyh7FEETEjpdSv3HF0hn3QJUmSJEmqACbokiRJq6lCoUBELPVRKBTKHaokrRbsgy5JkrSaKhQKCyXfo0ePBmDs2LFliUeSVnfWoEuSJEmSVAFM0CVJkiRJqgAm6JIkSZIkVQATdEmSJEmSKoAJuiRJkiRJFcAEXZIkSZKkCmCCLkmSJElSBTBBlyRJkiSpAlSXOwBJkiRJkrqNQm1fYAgwmULLjGXZ1QRdkiRJkqQVVahdCxgDfLxo3VXAiRRa3uzMIUzQJUmSJElacX8BDm637uNAFcVJ+xLYB12SJEmSpBX3IeAFYATQG9gReDFf3ynWoEuSJEmStOKagfsotDyaLz9CofY2skS9U0zQJUmSJElacX8DvkuhdhzwFLAVcChQoFC75/xShZY7FncAE3RJkiRJklZcI5CAs9qtP6PodWIJebgJuiRJkiRJK24iWQK+3EzQJUmSJElaUYWWuhU9hAm6JEmSJEkrQ6G2FvgksBHZoHFXUmh5u7O7LzVBr2toqgJmAVc2N9YfsXxRSpIkSZLUjRVqNwduA9YrWvtDCrV7U2h5ujOHWOo86M2N9XOBZ4B5yxWkJEmSJEnd36+A9YFHgMuAcfnyLzp7gM42cf87UKhraHoauAt4r21Dc2P9YoeIlyRJkiSp4hVqBwB/BrYlG+jtsxRa7l7Go+wG3EyhZb+i494IvL+zB+hsgv5jsiB/0G79EoeIlyRJkiRpFXAWcBOFlk9QqO0J9F2OYwQwu9262fn6Tulscr3Cw8VLkiRJklRxCrVrAnsCx2bLLbNZNNHujAeBegq1/wHGA1sCewE3d/YAnUrQmxvr65YjOEmSJEmSyq06Ih4oWh6TUhpTtLwx8DpwPoXaHcgS7a9SaJm+jOf5NnA7WVK+V76uBWjodKCdLVjX0LTIcPHNjfVvd3Z/SZIkSZLKYE5KaeclbK8GdgK+TKHlXgq1Z5El1d9fprMUWh6lULsVcDRQR5Y3/41CyyudPcRSR3EHqGto2hx4EvgjcCowBniirqFpi2UKWJIkSZKkyjIJmESh5d58+QqyhH3ZFVpeBa4GrgKuXpbkHDqZoLMShouXJEmSJKniZEn1SxRq2yqg9yGroF7G49TWUqi9AXiarN/50xRqb6RQW9vZQ3S2iftuwM3NjfXzh4uva2hapuHiJUmSJEmqUF8G/p6P4P48cNxyHOMnwH7AHGAqMAj4MPBT4EudOUBnE/QVHi5ekiRJkqSKVGgZByypn3pnfAx4HNiLQssbFGrXBm4D6lnJCfqDQH1dQ9NyDxcvSZIkSVI3NhC4jULLGwB5kv4gcGhnD9DZBL14uPjRZDXnyzRcfF1D035kk79XAX9ubqxvXEy5XYB7gMObG+uv6OzxJUmSJEkqo6eBIyjUPgc8RVaxfTjwRGcP0KlB4pob6x8FtgK+A5ybP2/d3Fj/SGf2r2toqgJ+D+wPbA18qq6haevFlPs58K9ORS9JkiRJUmX4KdALOJ1scPXTgd5Ah5XTHVlqDXpdQ1M1WcJ8V3Nj/bLNA7fASGBCc2P98/kxLwUOYtGR8b4MXAnsspznkSRJkiSp9AotV1OorSfLazcimwf99xRabujsIZaaoDc31s+pa2jakmwku+U1BHipaHkSsGtxgbqGpiHAIcDeLCFBj4gTgBMAampqmDp16gqEJUmSpDatra0Afr/SCtlwyAYMrH6v3GGUXM+aGmbPbj+udvc3Z85cPzOKFVpuBG5c3t072wf9h8CP6xqa/kZWk966jOfpaLT31G75TOA7zY31c+samhZ7oJTSGGAMQL9+/dKgQYOWMRRJkiR1pKamBgC/X2lFTJz8MgPm9Cp3GCU3u7WVnj17ljuMkquurlq9PzMKted1olSi0PK5zhyuswn6H8gS6lsBihLo1NxY35ljTAKGFS0PBV5uV2Zn4NL82IOAj9Y1NM1pbqy/ppMxSpIkSZJUSseS5cpLmoI8ASs1QWcxJ+zsPOj3A5vVNTQNByYDRwBHFhdobqwf3va6rqHpAuB6k3NJkiRJUgU7fWUerLMJ+vClF1m8vB/7yWSDzVUB5zU31j9R19B0Ur793BU5viRJkiRJJVdoKW2Cno/ifh4rNoo7zY31NwA3tFvXYWLe3Fh/7PKeR5IkSZKkVdFS50FvbqyfQzbB+npdH44kSZIkSaunUo3iLkmSpE469MijmTj51ZKf96lHHgFgl1H7lvzcABsOWY8rL76oLOeWpEpQqlHcJUmS1EkTJ7/K9sf9tOTnndR4EkBZzg3w6PmnluW8klQpltrEvUh08FiW/SVJkiRJ6t4KtV+iUHvr8uxaklHcJUmSJElaTWwKjFqeHTuVoDc31r+4PAeXJEmSJEmds8Qm6nUNTQ/VNTR9PX/9qbqGpvOKtv20rqHpja4OUJIkSZKkVchbwMTl2XFpfchHAEPz1yOBzxRt6wMMWJ6TSpIkSZLULRVafkihZbm6iTvImyRJkiRJFaAzfdBTl0chqdv6xwMvccl9E4kITj9wG7YdUjt/27m3P8eNj79KdY9g2w3WpHDgNkQE37j8Eca/Mo3+vatZe42enHPU+wAY+/QUzvrPswB87UObM2rzdeYf667npnLkn+7l7v/bm/Vr+5T2TUqSJEkrQWcS9C/WNTQdR9aknbqGpjfz9X4DlrRELTNaueCuZq7+4h68Nm0Wp1w2jiu+sPv87R/ZZj1OGrUJAF/6+0Pc9dwb7LHpIABOP2gbdqkbOL/s3HmJxhuf4rIT3w/A4X+8mw9sOoiqHkFKib/89wW2H1qLJEmStKrqTBP3XmR9zXuRzX0+oGhZkhbr4ZfeYpe6gfSs7sGwgX2ZPnsu782ZO3/78EH95r+uqQqqesT85R9f/ySfPPcurnvkZQBemDqdoWv1pbZPDbV9ahi6Vl9efGM6AE2PvcKem69Dn5qqEr0zSZIkaeVbWg36XiWJQlK31DKzldo+NfOX+/eupmVGK4PXXDiRvvu5N5jyznvsOjyrMf9u/VYM7NeTt2fM5sg/3csOQwfQMnP2Qsdas081b81opXXuPC67/yX+8plduOGxV0rzxiRJkqT2CrXrkg20vhbwNjCOQsury3KIJSbozY31ty9vbJJU26eGabNa5y+/M2sOtX1rFioz/pVp/OJfT/GXz+xCRFaDPrBfTwAG9O3JBzcbxJOvTGPTwWsscqwBfWu45L6JHDxiCD2rHfNSkiRJJVaorQKOBU4E3tfB9oeAPwB/pdAyd5Ht7fiNVlKX2XHYWjzQ/Batc+cx+e2Z9OtZRa/qBbXnzVOn8+0rHuV3n9pxflIOWc07wOw583jgxbfYeJ1+DB/Uj5fenME7s1p5Z1YrL705g7q1+/H0q+9wzbjJHHPefTz16jucctk4ZrUu9bNPkiRJWhmeBMaQJefPAdcDF+fPzwE7AX/Oyy1VZwaJk6TlUtu3hqN324jD/3g3EcFpB2zNEy+3cOezUzlx1Cb88PonmTarlW9c/ggAJ47amL23XJeTL36IGbPnMmfuPA7ecQibr9sfgO/styXHnHff/NdVPYKfHLLd/PMd/se7+c3hI+htX3RJkiSVRk/gW8ClFFpeXmRroXYD4FPAyZ05mAm6pC512C7DOGyXYQut22aDbLT1847dpcN9Lvrcrh2u32vLwey15eDFnqtthHdJkiSpRDZdYtP1LGk/g0LtmZ05mE3cJUmSJElaHktMzmv3oFC77VLLFVmmBL2uoWnNuoamr9U1NH2/rqFp96XvIUlLVygUiIilPgqFQrlDlSRJkjpWqD2XQu04CrVBofZvwB3AIxRqv9jZQyyxiXtdQ9OlwAHAEKAFuBXYMd98Wl1D01HNjfWXLV/0kpQpFAoLJd+jR48GYOzYsWWJR5IkSVoOHyYbDK4vcDjwGFAHfAU4pzMHWFoN+vuAe5sb698G9iAbga4VuBaYR9YZXpIkSZKk1d36wIvA1mS59tHAZcCGnT3A0hL09YBn8tcfyp/Pb26sPwS4EthsWaKVJEmSJKmbehcYQTZqeyvwFNko77M6e4ClJejzgP75692BBPwnX54OROdjlSRJkiSp2xoLvB/4KnArhZZWYDvg6c4eYGnTrD0OfKKuoakvsDcwlwUJ+pbAK8sYsCRJkiRJ3dHnyZLxauBMCrU9ybqHP9TZAywtQf8B8E/goHz5jObG+rfqGpo2BnYD/rrMIUuSJEmS1N0UWt4Gvtdu7Q+X5RBLbOLe3Fj/H2Bz4FBg9+bG+u/km1rJkvYfLcvJJEmSJEnqNgq1p1OoHbSUMoMo1HYqUV9aDTrAFGACMLVtRXNj/UvAS505gSRJkiRJ3dT3gQYKtf8hm/d8PPAO2VhuWwGjyLqLV5O1UF+ipc2DvilwEzA8Xz67ubH+qysSvSRJkiRJ3cQ+wE+B/YCPtNvWNqj6PcB3O3OwpdWgNwIbFy2fXNfQdFlzY/1dnTm4JEmSJEndVqHlNuD9FGp3AD4GbA+sBbwNPApcT6FlXGcPt7QEfQ/gOeBwsqr5M4APACbokiRJkiQBFFoeAR5Z0cMsbR70dYEbmxvrHwJ+m68bvKInlSRJkiRJC+vMIHFr1TU0bceC9vPr1jU0bd+2sbmx/tEuiUySJEmSpNVIZxL0I/MHQOpguTPHkCRJkiRJS9CZ5DqWc5skSZIkSeqkJSbozY31S+ujLkmSJEmSAAq1A4FPAJsCPwF2AJ6m0PJaZ3Y3AZckSZIkaUUVarcBxgN/AL6Rr70RKHT2EEusQa9raHpoKfun5sb693X2ZJIkSZIkdVO/BgYAzwMbU2hpoVB7O/Chzh5gaX3QRyxle+rsieoamvYDzgKqgD83N9Y3ttt+EPAjYB4wB/hac2P9nZ09viRJkiRJZTQSuAZ4GfhKvu5FYFRnD7C0BP245QqrnbqGpirg98C+wCTg/rqGpmubG+ufLCr2H+Da5sb6lE/jdjmw5co4vyRJkiRJXWw6sEa7ddsDb3T2AEsbJO6vyxFUR0YCE5ob658HqGtouhQ4CJifoDc31r9bVL4fy1A7L0mSJElSmd1JNkDcdgAUau8D3gdc0tkDLK0P+hpkHdw/CrwOfL+5sf4fyxHoEOClouVJwK4dnO8Q4GfAYKC+owNFxAnACQA1NTVMnTp1OcKRVMlaW1sB/PtW2V33+Otc/egUAL69Tx1brttv/rZHJr/DT//9Ai+9NYurj9+Bdfv3AuDRl9/hzLETqeoRfHDjARwzcoP5+7TMnMPBfx7Ht/ap46NbD5q//oGJLZx0+VM0nThi/nG0ettwyAYMrH6v5OetjnkAZTk3ZO/bz/5VX7mu33LrWVPD7Nmzyx1Gyc2ZM9e/2wW+BewMbJwv70zWH/3Uzh5gaU3cfwQclb9eC/h7XUPTA82N9S8sY6AdzZe+SA15c2P91cDVdQ1Ne+bnXqQzfUppDDAGoF+/fmnQoEHti0haxdXU1ADg37fKqWVGK1c8Op6rv/hBXps2i1MuG8cVX9h9/vZd1qjl2i2H8dkL7mfgwIEMqu0DwJmXPsUfjhnJkAF9OO78+5iWerPxOllrtzE3jGeX4WvTv/8a86/vlBL/uP4Fth9au9BxtHqbOPllBswp/c2aOSmb4OfNMpwbsvftZ/+qr1zXb7nNbm2lZ8+e5Q6j5Kqrq/y7bVNoeYlC7XbAx4CNgGbgBgotMzp7iKVNs3YwMA34JnAF2QBvByxHqJOAYUXLQ8k6zneoubH+DmCTuoYmf9OSpLJ4+KW32KVuID2rezBsYF+mz57Le3Pmzt++Zu8a+vVa9D73O7PmMGRAlmRvN3QA9zz/JgCT357JlGmz2G5I7ULlmx57hT03X4c+NVVd+G4kSVJJFFpmUmj5B4WWX1FouWJZknNYeoI+FLi8ubH+18BnyWrChyxHmPcDm9U1NA2va2jqCRwBXFtcoK6hadO6hqbIX+8E9GQZOtNLkrQytcxspbZPzfzl/r2raZnRutT91upbw5MvT2P2nHn8b8JU3p6ZNXc865ZnOHnvTRcq2zp3Hpfd/xKfGrnhyg1ekiSVXqF2BIXaOyjUTqNQO7foMaezh1haE/cq4F3IBnGra2gCqFniHh1obqyfU9fQdDLwr/yY5zU31j9R19B0Ur79XOBQ4Ji6hqZWYCZweHNjvQPFSZLKorZPDdNmLUjI35k1h9q+S/8X2Hjo9vy4aTwpJTYc2Jd1+/fmqVenEQSbDu4PvDK/7CX3TeTgEUPoWb20++VS13jomjGM++efF1l/3nEjF1oecdDx7HTwCaUKS5JWVRcB23SwvqMu3x1aWoIO8IW6hqZj89ep/XJzY/3anTlRc2P9DcAN7dadW/T658DPO3MsSZK62o7D1uKMm5+hde48przzHv16VtGreunN0Ddftz8XfnYks+fM48SLHmD0Futw61NTeH7quxxz3n28+MZ0+tRUMXzQGjz96jtMfHMG/3zkZZ569R1OuWwcFxw3kt42d1eJ7HTwCSbekrTy1AF3AScB7yzPATqToPfKHx0tW8MtSeqWavvWcPRuG3H4H+8mIjjtgK154uUW7nx2KieO2oTnX3+X7//zcca/Mo2vXPIwB44YwtG7bcSf//s8t4x/DYAT99yEtdfoxSd3HsYnd86GYvnNv5+hblBfRgwbwIhhA+af7/A/3s1vDh9hci5JUjkUaquAB4DJFFo+tpxHuQTYAWim0PLu0gp3ZGkJ+l7Lc1BJkrqDw3YZxmG7DFto3TYbZIO8bbzOGvz9+N0W2ef4D27M8R/ceJH1bU7Zd/MO11924vtXIFJJkrSCvgqMB9ZcgWP8nCzJn0qh9jWgbXTZRKFlk84cYIkJenNj/e2L21bX0PQBYGAnA5UkqVsqFAqcfvrpSy132mmnUSgUuj4gSZK0bAq1Q4F64CfA11fgSH8H2qZrKb7D3+mW551p4r44vwR2WcFjSJK0SisUCgsl3qNHjwZg7NixZYlHkiQtojoiHihaHpNSGlO0fCbwbaD/Cp5nO+Apspr0t5fnACuaXHd6NDpJkiRJkspgTkpp5w63FGo/Bkyh0PIghdrRK3ieq4CBFFr+urwHsPZbkiRJkrS62gM4kELtR4HewJoUav9GoeXTy3GstYEPU6h9mqwmvbgP+qGdOcASE/S6hqYDl7B5rU6FKEmSJElSJSq0/B/wf9nr2tHAN5czOQfYL3/eLH+0WWl90K9ZwsFiWU4kSZIkSVI39kNWMEdeWoI+cUVPIEmSJElSxSu0jAXGrsD+hRUNYWnTrNWt6AkkSZIkSeqWCrU/AO6h0HJz/rojiULLjzpzOAeJkyRJkiRp+RTIpmm7OX/dvgV6W9dwE3RJkiRJkrrQX4H78tcX0sV90CVJkiRJUkcKLcdRqN2TQu3GFFqOXdHD9VgJIUmSJEmStLq6DTh5ZRzIBF2SJEmSpOUXK+tANnGXJEmSJGnFDKVQu+ditxZa7ujMQUzQJUmSJElaMYfmj44kOpl7m6BLWqxDjzyaiZNfLfl5n3rkEQB2GbVvyc8NsOGQ9bjy4ovKcm5JkiStklqBmSt6EBN0SYs1cfKrbH/cT0t+3kmNJwGU5dwAj55/alnOK0mSpFXWORRavr6iB3GQOEmSJEmSKoAJuiRJkiRJy+9F4M2VcSCbuEuSJEmStLwKLcNX1qGsQZckSZIkqQKYoEuSJEmSVAFM0CVJkiRJqgAm6JIkSZIkVQATdEmSJEmSKoAJuiRJkiRJFcAEXZIkSZKkCmCCLkmSJElSBTBBlyRJkiSpApigS5IkSZJUAUzQJUmSJEmqACbokiRJkiRVABN0SZIkSZIqgAm6JEmSJEkVwARdkiRJkqQKUF2qE9U1NO0HnAVUAX9ubqxvbLf9KOA7+eK7wBeaG+sfKVV8kiRJkiSVU0lq0OsamqqA3wP7A1sDn6praNq6XbEXgFHNjfXbAz8CxpQiNkmSJEmSKkGpatBHAhOaG+ufB6hraLoUOAh4sq1Ac2P9XUXl7wGGlig2SZIkSZLKrlQJ+hDgpaLlScCuSyj/OeDGjjZExAnACQA1NTVMnTp1ZcUoqZ0Nh2zAwOr3Sn7e6pgHUJZzQ/a+/WzR8mptbQXwGtIKKdfnb7n5+ds9rK7Xb8+aGmbPnl3uMEpuzpy5/t2uRKVK0KODdamjgnUNTXuRJegf6Gh7SmkMefP3fv36pUGDBq2sGCW1M3HyywyY06vk552Tst43b5bh3JC9bz9btLxqamoAvIa0Qsr1+Vtufv52D6vr9Tu7tZWePXuWO4ySq66u8u92JSpVgj4JGFa0PBR4uX2huoam7YE/A/s3N9a/UaLYJEmSJEkqu1Il6PcDm9U1NA0HJgNHAEcWF6hraNoQuAo4urmx/pkSxSVJ6qYOPfJoJk5+teTnfeqRbAKSXUbtW/JzA2w4ZD2uvPiispxbkiStmJIk6M2N9XPqGppOBv5FNs3aec2N9U/UNTSdlG8/F/gBsDZwTl1DE8Cc5sb6nUsRnySp+5k4+VW2P+6nJT/vpMaTAMpyboBHzz+1LOeVJEkrrmTzoDc31t8A3NBu3blFr48Hji9VPJIkSZIkVZKSzIMuSZIkSZKWzARdkiRJkqQKULIm7pIkSVKXeuURuOFbEFXQowoO/B0MHL5g+2NXwH1/gugBvfrDoX+G3mvCWy/CP78Ec2fDZh+GPb+ZlX/zBbipAWZPhzWHwMf/WJ73JWm1YYIuSZKk7mGN9eDTV2bJ9zM3w9ifwcfHLNi+1YGw3Sey17f+BB69DEZ+Hm4pwF6nwka7w18PzMqts3mW7B90NvRfryxvR9LqxwRdkiRJ3UP/dRe8rqqBHu2+6lb3XPC6dQass2X2+tXHsuQcYPOPwIv/g5re0DoTbvwOTJ8Ku54AWx8EL/wX/v0D6NkPBmwIB5/Tte9J0mrFBF2SJEndy+zpcOuP4KAOkueHLoR7/gDVveEDp2Tr0rwF23vXwruvwTuvwquPwpfuhZ5rwF8+DMP3hPHXwd7fg033gXnzFj2+JK0AB4mTJElS9zG3Ff5xHHzg6zB4y0W373QMfPHurDb8f2dl66LoK/GsadBnrewxeGtYc4Osn/p628Ebz8MeX4Gnb4Qrj4dxfyvNe5K02rAGXZJWtqUNUjTxXrj+a/DGc/CVh6F2SLZ+9gy48dvw9otZrcwRf8u+IP71QJg3F2a/C7t/eUH/SUnSwubNg6s+D1vWw1YfW3R766ys6TpkNeWtM7PX622bfTZvuCtM+Dfs1wgDN86awb/3DlT3gdefggHDstr0+l9BSvC7nWDrg7MEXpJWAhN0SVrZljZI0eAt4XP/hosPX3i/2xthm0OyZpPFjroi6zc5axqcu4cJuiQtzvhrs8/dd1+HRy+HdbeGHY+G52+DPb4Kd/0Wnr89K9tnABz0++z1PqfBtV/ORnHfdF9YZ4ts/b6nw98+AfNa4X2fgTUGw+2/hOduzZrFb7yXybmklcoEXZJWtqUNUtS7tuP9nr8d5s6B//4a6vbIRhSGBYMatc6AdbbKXjtIkSQtapuDs0d762+fPY/6dvZob+BwOPb6Rddvsnf2KDbqW9lDkrqAfdAlqau0DVK0+1c6V37Kk9kARMdenzWlfPaWbP28uXD+R+Gc98OWH83WtQ1SdOz1cODZXRO/JEmSSsoEXZK6wtIGKepIn7Vg0w9BBGyyD7z2eLa+RxUcdwN8+cGsdn1Wi4MUSdIKKBQKRMRSH4VCodyhSlrN2MRdkla2pQ1StDh1H4CXH4Zhu2TPm+ydJfpRBT16QE3fbFqg6t7Qo8ZBiiR1O288/ygHjHpfSc71sT13mv/6rkeeAWD3HTZfqMyDt13HAbdd1+WxDB6yEX+5+KouP4+kymeCLkkr29IGKZo6AZq+Dq89Bld+Lhv0bZfj4UMFuPYrMOc9WHtj2PJj8O6rcMXnslr0Oe9lfSerezlIkbrWRYdksxHs+oVF+9q+OwWuPikbTKt2KBxwVnZNvnQf/Ou72ZgLW+yXXeuQddW4vTF7PbohayUiLUbV3Flcd+KmXX6ewpWPc/pVTy6y/vo7Hlpo+bSPb03h0G27PJ4D/jihy88hadVggi5JK9vSBikatCl85tpFtw/YEI65ZuF1a24An71x0bIOUqSudODZ8PxYmPbyotv++2sYcWR2Y+nO38Ajl8D7js2mCDzsomwaqr9/Eraozwbe+vcPsi4akI2lsPFe2Q0nqYwKh25bksRbkpaVfdAlSdLCaocsftsbE2CDHbPXQ96XzSgA2TSAA4ZlrzfYEZr/C288B2ttlE1n1WdA9vrNF7J9xuwFF3wMrvliV74TSZJWKdagSyq7h64Zw7h//nmR9ecdN3Kh5REHHc9OB5/Q5fGUqg/k080v8+zEV5dabrMN12OLug26PB77QKpT1t0aJvwH1t4Enr0ZZr6Vre+7Nrz6GAzaIqt933y/bFvvAQv27V0LM99cMAvBpvtkYzZIkiTABF1SBdjp4BNKknh3Vun6QM7i9E4k6EfuPJDCoV0fj30g1Skf/Abc8C244FpYbzvov362/sDfZn3QSbBWXba+z1rZrANtZk3L1u3xFbjzzKx5/PA9YadjyvBGJEmqPCboklQm9oHUKql3LXx8TPb6ltNh672y14O3gqOvgjmz4bKjYLN9s2T87RezxByy1wM3zgY8dBYCSZIWYYIuSZIWdu2Xs1HZ57yXTfk3umHBLATP3w53/BIiYPgo2PzD2T53nQ3P3JS93v0r0G9Q9nqf0+BvH1/wukcV3P17ZyGQJFWOQu0w4EJgPWAeMIZCy1nlCMUEXZVrSdP83HU2PJ2PbN0yEbY6ED7yE7j6C9nUVb1qod/acNiF0DIZrjoB0tzsy+B+jTBkp0XPJ0nKHPi7Rde1zUKw8ajs0d7uJ2eP9jb/8IIkvo2zEEiSKssc4BsUWh6iUNsfeJBC7b8ptCw6H2MXcxR3Va4Dz4Z9f9Txtt1PhuOassegLbLmkW32/2W2/rALs+Vea8AnL4DP3gQH/Bb+dWpXRy5J3V6hUCAilvooFArlDlWSpCUrtLxCoeWh/PU7wHhgCVOadB1r0FW5ljTNT5vpU7M+jcN2WbDuX6dCdS8Y+XnY9tCsv2SbqhrokV/2L/w3m5+3Z79s/umDz1m58UtSGZRqFgKAj+25oDXSXY88A8DuO2y+UJkHb7uOA267rstjcRYCSdISVEfEA0XLY1JKYzosWaitA3YE7i1BXIswQdeq7bErYJtDFix/+MdZ0/YZb8KFB8IGO8HA4dm2eXOzkYc/+I1s2Wl+JHVDpZuF4HFOv2rRln/X3/HQQsunfXzrkgyG6CwEkqQlmJNS2nmppQq1awBXAl+j0DKty6PqgAm6Vm2PXQ4f/9OC5X5rZ899B2YDD732+IIE/bqvwuYfgU3yEYed5keSlpuzEEiSupVCbQ1Zcv53Ci1la5JlH3StuqZOAALW3mTBuplvZ89zZsNL98LaeS3Szd+D/uvBricuKNtnYDbNz8f/BHf+ZsE0QJIkSZJWH4XaAP4CjKfQ8utyhmINuirXkqb5AXj0Mtj+sIX3ueI4mD0d5rbC9odn8/JOfgju+QMM2w3Or18wurvT/EiSJEmCPYCjgcco1I7L151KoeWGUgdigq7KtaRpfgD2/u6i24++etF1Q3aCH7yx6Hqn+ZEkSZJUaLkTiHKHATZxlyRJkiSpIpiga5XmPLySJEmSugubuKtLfO7IjzNl8oslOZfz8EqSJEnqDkzQ1SWmTH7ReXglSZIkaRmYoGuV5jy8kiRJkroL+6BLkiRJklQBTNAlSZIkSaoAJuiSJEmSJFUAE3RJkiRJkipAyQaJq2to2g84C6gC/tzcWN/YbvuWwPnATsB3mxvrf1Wq2CRJWl4PXTOGcf/88yLrzztu5ELLIw46np0OPqFUYUmSpFVQSRL0uoamKuD3wL7AJOD+uoama5sb64vnx3oT+ApwcClikiRpZdjp4BNMvCVJ0kpRqibuI4EJzY31zzc31s8GLgUOKi7Q3Fg/pbmx/n6gtUQxSZIkSZJUMUrVxH0I8FLR8iRg1+U5UEScAJwAUFNTw9SpU1c8Oq10c+bMZfbs2eUOo+TmzJnbra7JDYdswMDq98odRsn1rKnx+u0GvH5XL16/3YPXb/fg9bt66W7Xb7mVKkGPDtal5TlQSmkMMAagX79+adCgQSsSl7pIdXUVPXv2LHcYJVddXUV3uiYnTn6ZAXN6lTuMkpvd2ur12w14/a5evH67B6/f7sHrd/XS3a7fcitVE/dJwLCi5aHAyyU6tyRJkiRJFa9UNej3A5vVNTQNByYDRwBHlujckiRJkiRVvJIk6M2N9XPqGppOBv5FNs3aec2N9U/UNTSdlG8/t66haT3gAWBNYF5dQ9PXgK2bG+unlSJGSZIkSZLKqWTzoDc31t8A3NBu3blFr18la/ouSZIkSdJqp1R90CVJkiRJ0hKYoEuSJEmSVAFM0CVJkiRJqgAm6JIkSZIkVQATdEmSJEmSKoAJuiRJkiRJFcAEXZIkSZKkCmCCLkmSJElSBTBBlyRJkiSpApigS5IkSZJUAUzQJUmSJEmqACbokiRJkiRVABN0SZIkSZIqgAm6JEmSJEkVwARdkiRJkqQKYIIuSZIkSVIFMEGXJEmSJKkCmKBLkiRJklQBTNAlSZIkSaoAJuiSJEmSJFUAE3RJkiRJkiqACbokSZIkSRXABF2SJEmSpApggi5JkiRJUgUwQZckSZIkqQKYoEuSJEmSVAFM0CVJkiRJqgAm6JIkSZIkVQATdEmSJEmSKoAJuiRJkiRJFcAEXZIkSZKkCmCCLkmSJElSBagudwBaun888BKX3DeRiOD0A7dh2yG187fNap3Ld658lJffnskGA/rw80O3p3dNFS+9OYNvX/Eos+fOY+8tB/OlvTYFYOzTUzjrP88C8LUPbc6ozdcB4Pe3TeDWp6bQs6oHv/jE9gwb2Lf0b1SSJEmSVmPWoFe4lhmtXHBXM5ee8H7OPHwEhWufWGj7FQ9OYpN11uAfJ+3OxoPW4IoHJwHw85ue4pR9N+fKL+zOXc9NZcKUd5k7L9F441NccNxILjhuJD+7YTxz5yUmTHmXu56bypVf2J2vfWgzfn7TU+V4q5IkSZK0WjNBr3APv/QWu9QNpGd1D4YN7Mv02XN5b87c+dvvef4N9t5yMAD7bDWY+154E4AnX5nGyOEDAdhri2z9C1OnM3StvtT2qaG2Tw1D1+rLi29M557n32CvLbJj7Lrx2ox/ZVqJ36UkSZIkyQS9wrXMbKW2T8385f69q2mZ0drh9to+Nbw1YzYAKS04xpr5+paZsxc61pp9qnlrRusi55hXtK8kSZIkqTRM0CtcbZ8aps1akJC/M2sOtX1rOtw+bVYrA/r2BCCChfYZ0LeG2j49FzlWtr6GabPmzF/fo2hfSZIkSVJplGyQuLqGpv2As4Aq4M/NjfWN7bZHvv2jwAzg2ObG+odKFV+l2nHYWpxx8zO0zp3HlHfeo1/PKnpVV83fvuvGazP26dfZZoNaxj79Orvmzdq3Wn9NHnzxTd630UDGPj2F0w7YmuGD+vHSmzN4J0/SX3pzBnVr9yOlxOnXPcnnPjCcB198k63WX7Ms71WSJEmSSq5Qu1CuSqGlcSl7dJmSJOh1DU1VwO+BfYFJwP11DU3XNjfWP1lUbH9gs/yxK/CH/Hm1Vtu3hqN324jD/3g3EcFpB2zNEy+3cOezUzlx1CZ88n1D+dYVj/LJc+9ivdo+/PIT2wPwnY9sybevfITWuYnRm6/DpoP7Z+v325Jjzrtv/uuqHsGmg/uzS91ADv3DXdRUBb84dIeyvV9JkiRJKplC7SK5KoXaaym0PLnkHbtGqWrQRwITmhvrnweoa2i6FDgIKH7TBwEXNjfWJ+CeuoamAXUNTes3N9a/UqIYK9ZhuwzjsF2GLbRumw2yqdZ611Txu0/tuMg+G67dl0tPeP8i6/facjB75YPKFfvKPpvxlX02W0kRS5IkSdIqYSQwgULL8wAUajvKVUumVAn6EOClouVJLFo73lGZIcBCCXpEnACckC+miJi5ckNdZfWmc2MKzANmdXEsANVxx0Nzll6s+4noXp34H7jjlnKHUA7VcdTlXr/dgNfv6sXrt1vw+u0mvH5XL6vA9dsnIh4oWh6TUhqTv+5MrloypUrQO/qNtR8rvDNlyH+QYzooqwoSEQ+klHYudxzS8vD61arM61erMq9frcq8fldZncpDS6VUo7hPAorbaA8FXl6OMpIkSZIkrSwVlYeWqgb9fmCzuoam4cBk4AjgyHZlrgVOzvun7wq02P9ckiRJktSF7gc2o1C7pFy1ZEpSg97cWD8HOBn4FzAeuLy5sf6Juoamk+oamk7Ki90APA9MAP4EfLEUsanL2A1BqzKvX63KvH61KvP61arM63dVVGhZJFel0PJEucKJlMrWvF6SJEmSJOVK1QddkiRJkiQtgQm6JEmSJEkVwARdkiRJkqQKYIIuSZKkkoiIjuYbllYJXr8qBRN0Sas1/9lqVeR1q1VNRPQESI5OrFVQRAyKiH5AbbljUfdngq5l0valMCKqyh2LtLwiYpuI+BX4ZVGrrDUAIsL/46p4EbEl8MeI+ElEbJ2v8yaTVgkRsRVwHfB74NSIWNvrV13Jf+xaJimlFBEHAL+OiPMiYrNyxyR1VtE/1H5A37bkxn+0WlVERI+IGAY8GBF1KaV55Y5JWpKI2Bj4J/AgsBnZXMPzb476+atKFhGDgSuAc8jmOF8HeM/rV13JBF3LJCJGAacBvwG2B06PiJryRiUtXrsaxr758wRga+BLYC26Kl+emPdIKc1LKb0EXAVs17atvNFJS3QQ0JRSOpssOV8rIo6JiB0jorefv6pw6wJPpJQuSindBYwAzoiIX0bEzl6/6gr+U1enFH0BHAl8H9gSaAUaUkqtNnlXJYqI9YBPRsTAiBgC/C0iPpJSehP4MrBtRKxb3iilxYuINQDymvINizY9BxxVtE2qVI8B+0TEUcDtZN899wU+B3wMrIVURZsAvD8iroyIp8haglwBvAz8n98h1BWqyx2AKltERH53cBAwBZgKHE/WxOfTKaWJEXE0sH1EfNs7iaowI4EjyT7rHgf+AXwjIvYjq01fE9gAeK3oWpcqQkSsSdZK6WHgb8D1EXEDcDfwZ+BDEXF0SumicsYpLcW9wFnAjsDTKaXDASLiVGAUcIWfvaok+WBw1SmlFrJB4TYDRgOfSCkdn5d5BtgJmFuuONV9WYOuxWpLWPJk5ryIGAA8DGxM1rzy9YjYFfgWcKv/YFVpUkrXAhcBHwZGpJQuJqt1HAP0AXYFfhoR/bx+VYF6ktXe7A7sRZbMPAIcAFwLTCdLeqyBVEUpGlC2P9CaUjqPrGtcioht8mIPAOtHxBpev6owI4AxEXEccBuwfkrpJrLuGV/Pywwk6yq3VnlCVHcWfifVkkTEXmTJzGdTSv/N120H/JCsifs6wK9TStdZA6lK0f5ajIiDgcOBm8j6Qk7Nu2W8DzgW+E1K6dlyxCotST5A0QHAB4B/pJRuyNd/lgXjKOyXUrq9fFFKC0REVUppbkQcSNbnfE3gt2QJ+aHAFsBTwGeBU1JKTWULVlqMiLgIOAI4KqV0eb5uN+CPZF2MtgO+nlK6rnxRqruyibs6lN/N7gHsQpaMj8vvJJ4E/BU4DKgB1kopTTY5VyXJW37sDewG3JJSuiYiZgFHA3Mj4paU0qvAfRFRIEt+TNBVEYpaL/VKKU2JiIuBAA6NiDVTSpfmNZJExBNktegm6CqrfJyPd1NKLfmN/K8A3yRLyPcFegG3knWV2w74QkrpP35/UKVody1eDLxL1i3uoZTShJTSPRGxL7AN8HZK6WGvX3UFE3QtpO2DJv+wmRsRjwF/J0tsbgF+CXwPuD2l9AQwAxwFW5WhKLHZhaw55SPAlnkf3rOBeWQ3maoj4h9kXxjXJevTK1WE/Bo+EPhCRIwDbkgp/TkiErBXXkP597z4hmSDHZ7l57DKJSI2Iet2cXREvAl8AZiTUhpHdoP/deAM4NiU0p+KkxqvW1WK/LN3d2A4cFtK6caIOA24Ir/pvw2wW0rpl8X7lClcdWMm6JqvKLkZRdbn8e78w2kkMD2l9Ep+h3w2Wd9HqaLk1+/OZDeSPpdSeiBv3j6KrKnl2UAV8EpKaTowPSJGpZTeLVvQUjsRsSnZjaQryPqhFyKiMaX0l4joSTY43FjgNbLP44JfElUueYu70cDlwKvAwWRNgDePiCOBy1JKt0bE/4BtyW6cShUj8iksI2JP4FygmazF0nkppdMjm8noKmBtsqmGpS5lgq758uTmo8AvyPqd/yQibgMuypPzI8g+mE5NKTWXMVRpSarIRlY9HHggb94+F6gn6+/4C1jwDxlvNqmCRMQOwIXAhXlC3g94C/hOXnP+h4i4LqU0OS//c6dZUznl3x3uJutm8QWywTcnko1uvRvZLC9NwH7AJW37lClcab6I6JtSmpEn59sD3wUOTSmNj4ivAgdEBCml0yJic2BeSmmCzdrV1RzFXfNFxFCyEa4/RjaAyyBgAHBMvu1Z4KsppasdcVWVomi04MERMTildC9Zf8e9IuJrAPkgLjcB17ft15bU+E9WlSSl9AjwNPDJvA/6dOCfZEn79yJi7ZTSpKLyJucqq/wzuJnsup0H1OWfq+fn60aRzXl+Ykrpf/kAnVJZ5TMM3BQRbaOwb002Neu+ACmls8imZz0sIg4Fnk0pTci3+b1BXcpR3Fdj+T/VKP6CFxEbko24eh5ZjePOwO/J5o/+fkppdjlilZYkb8b+FaAf0ATcDLxHdu1e01ZrLlWaoq5FOwLrk80T/VxEXEg2fc+hKaXZEdEHGJBSeqWsAUuLERE1wB5kifk3U0pXRsQawPHABsA9ZJ/H3lRSRchnyVgHGJxSui0iPkM2cvv5RSO3f41ssNnHyxepVjfWoK+mIqJPPhbcvIjYNSIOjIgdU0oTyfo8vp1Seh2YTDY1yvkm56pEETEc+D7ZdFMnkk3/dyDwMvBt4KiIqMv7kEkVpWhAuL8AnyHrWvTTlNIxwBvADRHRM6U00+RclaioRd3clNJY4GvAzyLisHx8j/PIumnsTHYTVaoIKaUpwA7Af/LxaP4KXAR8OiI+nZc50+RcpWYf9NVQRNQC10XEl8kGGDoPeBKYHRGvAg3AWhFxE7AJ8OWU0lNlC1gqEhE1KaXW/HUvYA4wM6U0Pl/3DvAHYM+U0j/yf7pvly1gaTHym0Y1ZPNBn5hSuj8itgC+FhHHp5SOjYjryaakerCcsUqLUzQa+7y8Rcg/I6IaODMi/puPYXM2UJNSeqe80UoL5Nfrxfk4NddFxIH5cg3ZjAT/AV6z1YdKzQR9NZSyOUqvIquxmQx8OmVzOW5Fduf7M8CeZCOxTkgp3V+uWKVied/Fz0XE08CbZLXmDcCzEfF54JK8efB/gGH5bi3liVZaVET0ZkGiskFKaVJErE025gdkfXnvIattJKX0sbIEKnVCPnDh3LblvEVI5M3b/5tSmpIPyGliroqUX6+X5TdMr8xbfvw1Iv5tqyWViwn6aiqldGZEvAH8CbgMeBh4AbgD2DWl9Gfy0ValSpFSmhsRtwDPAK8Ao1NKb+YJ+Qjg9xFxLdlIwsfk+zjQhirJaGCb/PP31IjYErgAOCUipua16K8BG0bEmmRTXM5d/OGk0igaL2EHshug/04pvde+XF6mOm8+DOBnsCpS2w2l/Nq+JG/5cV1EDE0pvVzu+LT6sk/maiyldBHwf8DpEbFbSmkW8DawXUQMsM+uKkXRSO1V+Siq/wT6kzX9hWy+6L+TJe57kDUXvqMcsUpLklK6iWymjLOA7+VNJy8FriGrvfkxcA5wbkppmsm5KkWezOxL9vn7BeChiNikfbn8c3pO/j3iYG+SqtIUzyTQdn3mSfpFwCYppTfLFpyENeirvZTSbyLiPbKpJi4CBgJn2GdXlaToC966EfFGSumQiNgWuDMiBqWUxkTEbLKk5o0yhiotou0GU9F1fD4wDRgZEfcCL6WUzomIcWSzaFyXsukCpYoR2TzQnwMOybvF/Rz4S0R8PqX0bF6mKm/pVEs2o8Z3yxiy1KmWH0U16dVtzdrb9itHzJI1pCKldA7wQ2A/4NcppeuLRmWVyiayuc1Pyl/vC1wH3JP3EXuc7Jo9MyJ+RlaLvmn5opUWlQ9qmPIvgLtGxAeAf6WUDgLWBk4F+kbEXsDaKaWbTM5VSfLEpQ9wFLANsD1ASuk7wF3AJXny3tYNaQBwJfCdfFR3qWw62/ID6GHLD1UKE/TVTHGznmIppV+TjXr9YL7sB5Mqwc7A7hFxGnAK2RfEnwLHRMRnUkr3AO8nG8n9iyY2qiQRMZBsmrT1ImI7snE9TiPrVrQX8HmgF3B2vq3Dz2epHIpu1PdNKc0k++y9HNg2IvYGSCmdCtxK1vqOiOgH3AacnlK6s/RRSwtr1/KjHrierOXHZkVl2rf8eLsswUq5MA/rvjo7oEtedv5IrDbrUaXIv+ztTdZnd/OU0l75+oPJpqa6lmw2gnAaFFWiiPgp2TX8HFlLpWbgBGALslYft5MNcNiaUnrcz19Vkog4APgi8B5wE3AVWS1kb2BsSulf7cr3AzZOKT1W6lilYvkNpt5kM718HPhVyuY5b/tc/jBwZErpmXzdALLP5II3l1Ru1qB3Y8s4oMvcvFnPIX45VAUZkFK6juyf5ryI+CZASuka4CLgE8D6JueqNEX9zk8lq3U8GBiU3yS9AhgPfBo4KKX0cN5lw9ZLqhh5d4xTyW4ojQe+nI/Mfj7ZyOwfjmyKwLbykVKabnKucrLlh7oDa9C7sbxZzw+BnxcN6LIrsLgBXW4AvmufMZVTUcuPzcj6nP81pfSziPgocCDwdErpN3nZdVNKr5UzXmlxImIEMCmlNDX//N0XODyl9GxErA8cRtay6clyxim1KW7BkX/mJqAf8A2y2sYXImIdYB4wsO27hFRJbPmhVZ016N2QA7poVVWUnB9AdnPpbuBTEfG9lNINZFNRjYiIb+W7vF6mUKUOtdXe5F2LLmbBTAPfIfuSeGFEbJmPFPwHk3NVkvzz9/15Ej4baAS+BByQJ+f7A78F3jM5VyWy5Ye6A6dZ60aK7nz3TSlNz/vYzCFv1pNSujWldGpEVLNos56v2KxH5ZLfJJqbUnonb83xfeDrwP/IbjKdGxHvpZR+mV+/EwFs2q5Kkyc4Hyb7glgg+5J4c0R8OKX044joTXaTdA9gVhlDleZrN/bBocD7Ukp7RcTdwHZA73zsj58C30opvVumUKVFtLt+1yS7wb8rMJpsDBuAmcAZZC0/5k/HarciVSKbuHczNuvRqiYi+gMnko1i/WrequMm4MSU0ov5zAOfB75FNg3g78sYrrSIiBgGDMlnFSAizmXhrhjnkX1Z/EBK6a28Bv2p8kUsLSoiRgLjUkqzI+JHwLMppQsjYkxeZDBwbkrpJgczVKWJiPcDE4AdyBLxN4FP5l2M9geOIevi6c0lVTybuHcjNuvRqiil9A5wIVmfxhPz1fcDl0fEGvnsAs3AP4CPRDZdlVQR8ibtOwIz85tNkI3Y3rOo2ElkLdYuzj93nyoayEgqq4jokbfsuBK4LSK+BLwGrBMRNSmlE8iu4aNSSjeBtY6qDO0+Rw8FLk8p3ULWPa4nC1p+nAH8zeRcqwoT9FVcuw+npTXrOddmPaokEdEDIL+RNArYNSI+C/yMbITVByLiO8DvyaZUew0wsVHFyD9Hm8i6XVweEaPI5tn9dEQcFBF9gW3JBjysIhtsy89fVZLBKaVZwDeBx4EW4FjgeODbML870YxyBSh1JO9SNDIieqaUvkk25scxKaWTgCeAH5Bdy19PKTV5Y1SrCpu4dwM269GqqGhAuKHAGymlmZFNC/hx4OGU0piI+DjZCMIPkd2A+j1wcEppYvkilzLtRrzuBxwHfAT4P2AN4MfAK8DuwEHAB4GqlNLZ5YlYWlg+W8aVwO/Ixvz4KfA9oAY4E9gQ2JNsNgK/MKpi5Df4ewLPkt0gvZjsBn4v4Lcppda8TJ+U0vTyRSotOweJW0U5oItWdXly/lGyVh+3R8TWKaX9I2IgsHvezPKilNK0iNgZ+DVwnMm5KkHRDab3AWsBLwDnktUy/gJoAOrJ+u3OIxvs8ASy2TWksim6drcHDidr3XE42aCyU4HfAJ8EjiRLbl4qW7DS4g1OKb0aEd8E9iZr+fE1spv6vYGfpJTmRYQtP7TKsYn7KspmPVrV5dNQnQ58Cnga2CgieqeULiObDnBbYEBefApZzfkj5YhVai//DN4P+DtZH/THgD2Aq8nGS/gtsFee3MwBPgsc67RqKrf82v0Y8EtgX2A4cDNZrXkzsA/ZnOeTU0oTyhaotBh5y4+bI+LzZJ+96wLjyAaUnQIcHxHDHMxQqyqbuK+CbNajVVW7JsFbALuRdcn4PnBESun5iBiZUrovItZNKb1WzniljuQ3PNcBziOrsVmfrPZ8dErp9YjoBXyGrKvG/fk+vVJK75UpZGm+iBhMNsPL8fmAhV8C6sgSnX8ApwH/SindVr4opYV10PIDsjGX/k52c3QjspYf/ci+/3pzSassm7ivmmzWo1VS/s91FLApWbPKn5ENYrh5Pr3aB4DvRMQJKaVXyhmrtARVKaUpEXEH8Glgf+DAPDk/CvhPSmkMLPhSaXKuCtJKNmDhYOApYAzZ+B4n5du+m38eV+WzaEhlV9Ty48tk3YomsHDLj8+Stfw4p2xBSiuJTdxXMTbr0aqoXReLWcDnyFp8fJ7sxtIBEXEM2ZfEP5mcq1JFxNZA2xfAoWQ15YellJ6LiB2B75LV5ACO1q7Kk1J6i6ymfHREbJtSagUuB54HdgJOzLsbmZyrYuQtPxqAr6aURpINargO2XeKM8jG/hhfvgillccm7qsAm/WoO4iID5H9I/0f2XznkVL6Q0R8kmwwrenAtSmlf3mDSZWkXdeMHsDtZC1AziabYm08WTej3YHvp5SuLVesUmfks2ecCIwEHgAOAU4m64++GfCzlFJL+SKUFhYRawE3AN9JKd0RETVkN/W3JZuF4HJbfqi7MEFfRXTQrGcc8DZZE7UfAifbrEeVKq9Bv4Rsup7/I5tpoBb4cUrpRf+hqtJFxIfJpqz8IdnNpFPJmgZPBEaRdS96IaV0rzeYtCqIiP7A+8kSnIdTSrdFRBXQP6X0dlmDkzoQEV8nm8LyqpTS4/mN/2PJprN8ATgvpTSrjCFKK4V90FcBRc162g/o8ipZs541sFmPKlREbErWP+xnwECyf6RbkI3evnFEHOQ0gKpE7RLtOWQjXleTTaX2ELBHPrPANcX7mZxrVZBSeoesD+/NAEU3St8uZ1zSElxO1vLjjIjoqOVHL7KWetIqzQR91eCALlolRcQaZP88twMOBZ4D9gIKZDXoI8n68T5VphClxcq7Fu0JzEop3RoRPyNrvfRB4Dhg24h4OqX0n3LGKa0Mfn9QpUspTYqIX7Cg5ceX2rX8sFuGugWbuK8ibNajVVlENJLdYLoDOJosaX8WGJJSerGcsUlLkg9e+HWgERhBdmPpS8D7gK8AF6aU/l22ACVpNWbllLojE/RVhAO6aFWwpL63EXEg2bX6U+BvKaXPlTQ4aTlFxO5kA8ANAk4Azge+A5BSmmOfc0mStLKYoK9CHNBFlSoieqaUZi9mW4+U0ryi5X2BHimlf5UsQKkT2ifa7UZvX4tsDIUxwJrAQSmll8sTqSRJ6q5M0FdhNutRJYiILclqE18G/p5SenJxNYrtEp4AB9RS+UXEIGAmULO0m50R0QfYJKX0eClikyRJq5ce5Q5Ay8/kXOUWERsD/wQeJGu+fjIsSLrbkvAi8z9zUq5EoUodioityOY0/z1wakSs3cF121a2KqU0sy05z+dElyRJWmn8ciFpRRwENKWUziZLzteKiGMiYseI6N2uuXBVPttAbUQcFhE1ZYtaYv4UllcA55A1XV8HeG8JN5ja9qsGKO66IUmStDKYoEtaEY8B+0TEUcDtZJ8p+wKfAz4GWZJTnJwDNwGTUkqt5Qpayq0LPJFSuiildBfZKO1nRMQvI2LnxdxgGgCcGRHrlCdkSZLUnZmgS1oR9wJnATsCT6eUDk8pHU3WH31UW6GixOYq4Ft5MiSV2wTg/RFxZUQ8RdZV4wqy6/f/ImJdWLj1B3ANcHlK6fVyBS1JkrovE3RJy6St2W8+q0BrSuk84DdAioht8mIPAOtHxBoppRQR/YCrgUJK6c6yBC4BEdEvT7Qhm9N8M+BPwJ0ppePzOc2vAmYAc2GhG0zXAN9LKd1R8sAlSdJqwQRdUqflNYkpn9P8SmBsRBwJ9APuA74VEQ3A2cD5KaV38137AF9NKf23LIFLC4wAxkTEccBtwPoppZvIxk/4el5mILA1MAAgHy/hF8Bp3mCSJEldyWnWJC1VRAwB3k0ptUTEdmQ15t8EtiDrc/4/4Elge2A74J8ppf/kte09nHFAlSQiLgKOAI5KKV2er9sN+CPwHNk1/PWU0nVF+6yXUnq1HPFKkqTVhwm6pCWKiE2Aa4GjgTeBbwMbp5T2y7fvDZwBHJtSemRxc6BL5VR8XUbE/sCBwE5kSfqEfP1gYBvg7ZTSw95gkiRJpWYTd0mLlScoo4HLgVeBj5LVMFZHxJF5k/dbyWrQty1boNJS5F0zds9nHHgkpfQF4AbgiogYGBEfBD6TUrotpfRw2z4m55IkqZSqyx2ApMqVJzV3k02h9gVgV2Ai2eBZuwHbR0QTsB9wSds+ZQpXWkRE9EgpzYuIPYFzgWbg0Ig4L6V0ekT0IBsUbm3gtDKGKkmSZIIuafHyGvRm4GlgY6AupfRiRJwPfDp/rAecmFL6X9t0VGULWMpFRN+U0ow8Od8e+C5waEppfER8FTggIkgpnRYRmwPzUkoT7KIhSZLKySbukhYrb+I7A9gLOBK4ICIOTSm1AH8FLgOmALV5TaXJucounwLwpohYK1+1NTCSbEBDUkpnAY8Dh0XEocCzbf3QTc4lSVI5maBLWqy2Oc+BuSmlscDXgJ9FxGH5FGrnAW8BO5NNtSaVXUrpHeATwAYRsVdK6VKya3f/iDgsL/M74CHgaZNySZJUKRzFXVKntDX9zWsczwRGppReyWsra1JKb5Y3QmlhEXEk8Ddgr5TS7fnyEcDlKaW/lTc6SZKkRZmgS+pQR/3Ji5L0wSmlKW0DcJUrRmlxiq7Vw4E/AQemlMZGxGfIumscC7zm9StJkiqJCbqk4mRmB2AY8O+U0nuLKVudUppTvF8pY5U6o617Rn5dfwo4GzgspfSfiNggpfRyeSOUJElalAm6JAAiYl+ymsYngDqyGsfn2pWpSinNjYgBwOiU0jWljlPqrHZJ+tHAH4GhdseQJEmVykHiJJFPM/U54JCUUj1wPfCXiNisqExbcl4LNAFvlyVYaQkioqrtdVvrjrylx0XAJibnkiSpkpmgS6uxyPQBjgK2AbYHSCl9B7gLuCRP3imqOb8S+E4+qrtUNm015BGxQ0R8LCJ6tR83oShJr04pvVK8nyRJUqUxQZdWQ0UJSt+U0kzgp8DlwLYRsTdASulU4FZgYL5PP+A24PSU0p2lj1paWN50fV/gn8AXgIciYpMOivZIKc2JiAERcbDjJkiSpEplgi6thvLE5gDgioi4BjiOrH/uu8C+EfGRvNy3U0r3FO16TErpvyUPWOqAXTMkSVJ3Y4IurYYi4gPAqcAJwHjgyymlKcD5QAI+HBFrF5WPlNL0lNJjZQlYKmLXDEmS1F05iru0miieEi0iPkqWiPcDvgEcmVJ6ISLWAeYBA1NKz5YvWmlRRdMB9kspTY+IXsC3gTWBG1NKt+blfgFclVK6J++acSfwFVt/SJKkSmeCLq1GIuL9wARgB+AM4E3gkymlqRGxP3AM8PmU0rtlDFNarLxrxheB94CbgKvI+p/3BsamlP7Vrnw/YGNbf0iSpFWBTdylbq7diNWHApenlG4B7gZ6Ar0j4mCyhP1vJueqVHbNkCRJ3Z016NJqICJGAuNSSrMj4kfAsymlCyNiTF5kMHBuSumm4qbwUrnZNUOSJK1OTNClbiwiepDVkj8LTAQuBgLoBfw2pdSal+mTUppevkilxbNrhiRJWl3YxF3q3ganlGYB3wQeB1qAY4HjyQbXIqU0D5hRrgCljtg1Q5IkrY6sQZe6qXwu6CuB3wH/A34KfA+oAc4ENgT2BCbZpF2VyK4ZkiRpdWOCLnUjRdNQbQ8cnq/eFfg7sAewEfBJsj68fVJKE8oTqbR4ds2QJEmrq+pyByBp5cmT848BXwbWIuu3ezNZrXkz8FmygbXOKVuQ0tINTim9GhHfBPYm65rxNbIbS72Bn6SU5kWEXTMkSVK3Yh90qRuJiMFAA/DVlNJIsqbt6wCzyPrq/oJseiqpIuVdM26OiM8DjwHrAuOAzwNTgOMjYphN2iVJUndkE3epG4mItYAbgO+klO6IiBrg98C2ZH3RL08pzY2IqpTS3HLGKrWxa4YkSVLGGnSpG0kpvQX8AxgdEdumlFqBy4HngZ2AEyOit8m5KklR14xfAvsCw1m4a8Y+ZF0zJpucS5Kk7sw+6FL3czlwInBGRDwAHAKcTJb0bEY20Nas8oUnLayoa8bxKaWnIuJLQB3wKlnXjDWwa4YkSVoN2MRd6oYioj/wfrKm7Q+nlG6LiCqgf0rp7bIGJ7Vj1wxJkqSMCbq0GjCxUaWLiK+T1ZRflVJ6PCI+BBwLvAK8AJyXUrLlhyRJ6tbsgy6tBkzOtQq4nKzP+RkR8RPgt8B5wFPAhmRdMyRJkro1a9AlSRXBrhmSJGl1Z4IuSapIds2QJEmrGxN0SZIkSZIqgH3QJUmSJEmqACbokiRJkiRVABN0SZIkSZIqgAm6JEmSJEkVwARdkqRuIiJGR0SKiOZyxyJJkpadCbokScshIprzZLj9Y0QZw5oEnAWcV8YYiIix+c/i2HLGIUnSqqa63AFIkrSKux54rmj59XIEERE1KaUJwNfKcX5JkrTirEGXJGnF/CWl9LW2B9AvIqZHxLsRMTwiekbEE3mN8uEARbXtJ0fEcxHxdkT8JSL6tB00Ig6MiPsiYlpEvBgRZ0RE33zb/KbsEVGIiDeAMe2buEdEXdG5vhwRr0bEaxFxdEQcGhETI+L1iGgoOm91RHwrIsbn7+PJiPh80fZCfrwrIuLC/H1OiIgP5dvHAqPy4v/fzv2EaFWFcRz/PkG5cKCF2sKNMxqSggNFhASiEFGElSIEQWBmmwhShKKF/0ARGhBaqFBRkxhCVKBEuHAhRkQuoiLNcqFGtDAmlERkwnpcnHPx5TI0juPkzb4feDn3nPfce8/MLN75veecO1z7bp3KP4AkSbcLA7okSZOzNiLebF6ZeQp4FZgOvA1sBhYC+zPzw9a5m4CjwJ/AC8B2gIh4DDgIDNRyBNgA7G6dPwd4EfgE+H6cca4HjgH3AO8Au4DPgRnAjoiYX/ttA4aAAD4C+ijhf3XrequA2cBxYB7XltV/DPxajw9Tltx/Nc7YJEkSEJl5q8cgSdJ/Tp2lntNuz8yo7x8CHgeSElgXZeaF+l7z4bsiMw9GxNPAAWAkM2dFxGfAE5SA+wNwF/BSvVYf8BBwpNbn16XtRMSy2v5zZvZHRD9wpt5rCSUoX6ZscXs5M/dExNfAA8AzlHD9R73HcD2eCzwJHMvMxXU2fAtwAlgE9AOn6z1mZeZIzyz6msx8fwK/VkmS/tfcgy5J0uSszMwDY7QPUQJ6AO814bzlZC1/rOXMiJhGCb0Aj9ZXIyiBuXGuCefX4WRmXomIS8DdwE+1/WItpwMzKeEcYE3r/Htb9W8zMyPiQk9bH2W2X5Ik3QCXuEuSdJNFxJ3AzlodBTZExNwxui6o5X21HMnMUeBsrb+SmdG8gHmZebzn/NEJDOuvcepQwvWlejzYc987gAdbfa/UcqyleM21/T9DkqQJcAZdkqTJWVuXljfeBZ4F7gc+AL4E9gB7I2JpZv7d0/etiHiKsoQcYF8td1GWuA9FxMOUZemDlP3iA1P0c1BnxHcDrwGHI+JTyqz4Yspe+eev81K/1HJdRAwCw5n53c0eryRJtxsDuiRJk7O8Vf+NEnDPAeuA85QHqj1CeXjcGz19N9e2acBeYCNAZh6KiJXA65SgnsApygPXptpG4HdKGH+Osg/9G6D9gLt/spPyBcVCyhcLXwAGdEmSxuFD4iRJ+pf1PCRuIDPP3sqxSJKk7nBvmCRJkiRJHWBAlyRJkiSpA1ziLkmSJElSBziDLkmSJElSBxjQJUmSJEnqAAO6JEmSJEkdYECXJEmSJKkDDOiSJEmSJHXAVVpek93mp7uhAAAAAElFTkSuQmCC",
86
+ "text/plain": [
87
+ "<Figure size 1008x504 with 2 Axes>"
88
+ ]
89
+ },
90
+ "metadata": {},
91
+ "output_type": "display_data"
92
+ },
93
+ {
94
+ "data": {
95
+ "text/html": [
96
+ "<div>\n",
97
+ "<style scoped>\n",
98
+ " .dataframe tbody tr th:only-of-type {\n",
99
+ " vertical-align: middle;\n",
100
+ " }\n",
101
+ "\n",
102
+ " .dataframe tbody tr th {\n",
103
+ " vertical-align: top;\n",
104
+ " }\n",
105
+ "\n",
106
+ " .dataframe thead th {\n",
107
+ " text-align: right;\n",
108
+ " }\n",
109
+ "</style>\n",
110
+ "<table border=\"1\" class=\"dataframe\">\n",
111
+ " <thead>\n",
112
+ " <tr style=\"text-align: right;\">\n",
113
+ " <th></th>\n",
114
+ " <th>experiment</th>\n",
115
+ " <th>lpips_mean</th>\n",
116
+ " <th>lpips_std</th>\n",
117
+ " <th>time_mean</th>\n",
118
+ " <th>time_std</th>\n",
119
+ " </tr>\n",
120
+ " </thead>\n",
121
+ " <tbody>\n",
122
+ " <tr>\n",
123
+ " <th>0</th>\n",
124
+ " <td>qwen_base</td>\n",
125
+ " <td>0.000000</td>\n",
126
+ " <td>0.000000</td>\n",
127
+ " <td>1.752080</td>\n",
128
+ " <td>0.038048</td>\n",
129
+ " </tr>\n",
130
+ " <tr>\n",
131
+ " <th>1</th>\n",
132
+ " <td>qwen_fp8_weightonly</td>\n",
133
+ " <td>0.250386</td>\n",
134
+ " <td>0.098014</td>\n",
135
+ " <td>2.162742</td>\n",
136
+ " <td>0.025480</td>\n",
137
+ " </tr>\n",
138
+ " <tr>\n",
139
+ " <th>2</th>\n",
140
+ " <td>qwen_int8_weightonly</td>\n",
141
+ " <td>0.194428</td>\n",
142
+ " <td>0.087902</td>\n",
143
+ " <td>1.989593</td>\n",
144
+ " <td>0.028399</td>\n",
145
+ " </tr>\n",
146
+ " <tr>\n",
147
+ " <th>3</th>\n",
148
+ " <td>qwen_fp8</td>\n",
149
+ " <td>0.384760</td>\n",
150
+ " <td>0.092095</td>\n",
151
+ " <td>2.305696</td>\n",
152
+ " <td>0.038131</td>\n",
153
+ " </tr>\n",
154
+ " <tr>\n",
155
+ " <th>4</th>\n",
156
+ " <td>qwen_int8</td>\n",
157
+ " <td>0.609537</td>\n",
158
+ " <td>0.062481</td>\n",
159
+ " <td>9.517996</td>\n",
160
+ " <td>0.055190</td>\n",
161
+ " </tr>\n",
162
+ " </tbody>\n",
163
+ "</table>\n",
164
+ "</div>"
165
+ ],
166
+ "text/plain": [
167
+ " experiment lpips_mean lpips_std time_mean time_std\n",
168
+ "0 qwen_base 0.000000 0.000000 1.752080 0.038048\n",
169
+ "1 qwen_fp8_weightonly 0.250386 0.098014 2.162742 0.025480\n",
170
+ "2 qwen_int8_weightonly 0.194428 0.087902 1.989593 0.028399\n",
171
+ "3 qwen_fp8 0.384760 0.092095 2.305696 0.038131\n",
172
+ "4 qwen_int8 0.609537 0.062481 9.517996 0.055190"
173
+ ]
174
+ },
175
+ "execution_count": 3,
176
+ "metadata": {},
177
+ "output_type": "execute_result"
178
+ }
179
+ ],
180
+ "source": [
181
+ "df_all = compare_sets_with_timing(\n",
182
+ " ExperimentSet.create(\n",
183
+ " \"qwen_base\",\n",
184
+ " \"qwen_fp8_weightonly\",\n",
185
+ " \"qwen_int8_weightonly\",\n",
186
+ " \"qwen_fp8\",\n",
187
+ " \"qwen_int8\",\n",
188
+ " ),\n",
189
+ " profile_target=\"loop\",\n",
190
+ " sort_by=None\n",
191
+ ")\n",
192
+ "\n",
193
+ "df_all\n"
194
+ ]
195
+ },
196
+ {
197
+ "cell_type": "code",
198
+ "execution_count": null,
199
+ "id": "477d7613",
200
+ "metadata": {},
201
+ "outputs": [],
202
+ "source": []
203
+ },
204
+ {
205
+ "cell_type": "code",
206
+ "execution_count": null,
207
+ "id": "2e99efc4",
208
+ "metadata": {},
209
+ "outputs": [],
210
+ "source": []
211
+ },
212
+ {
213
+ "cell_type": "code",
214
+ "execution_count": null,
215
+ "id": "06c65a7a",
216
+ "metadata": {},
217
+ "outputs": [],
218
+ "source": []
219
+ },
220
+ {
221
+ "cell_type": "code",
222
+ "execution_count": null,
223
+ "id": "31dea8be",
224
+ "metadata": {},
225
+ "outputs": [],
226
+ "source": []
227
+ },
228
+ {
229
+ "cell_type": "code",
230
+ "execution_count": null,
231
+ "id": "4efef8a4",
232
+ "metadata": {},
233
+ "outputs": [],
234
+ "source": []
235
+ },
236
+ {
237
+ "cell_type": "code",
238
+ "execution_count": null,
239
+ "id": "15b6d974",
240
+ "metadata": {},
241
+ "outputs": [],
242
+ "source": []
243
+ }
244
+ ],
245
+ "metadata": {
246
+ "kernelspec": {
247
+ "display_name": "Python 3",
248
+ "language": "python",
249
+ "name": "python3"
250
+ },
251
+ "language_info": {
252
+ "codemirror_mode": {
253
+ "name": "ipython",
254
+ "version": 3
255
+ },
256
+ "file_extension": ".py",
257
+ "mimetype": "text/x-python",
258
+ "name": "python",
259
+ "nbconvert_exporter": "python",
260
+ "pygments_lexer": "ipython3",
261
+ "version": "3.10.12"
262
+ }
263
+ },
264
+ "nbformat": 4,
265
+ "nbformat_minor": 5
266
+ }
scripts/sageattn_error.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
scripts/sageattn_eval.ipynb ADDED
@@ -0,0 +1,252 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": 4,
6
+ "id": "e76b6794",
7
+ "metadata": {},
8
+ "outputs": [
9
+ {
10
+ "name": "stdout",
11
+ "output_type": "stream",
12
+ "text": [
13
+ "/home/ubuntu/Qwen-Image-Edit-Angles\n"
14
+ ]
15
+ }
16
+ ],
17
+ "source": [
18
+ "%cd /home/ubuntu/Qwen-Image-Edit-Angles"
19
+ ]
20
+ },
21
+ {
22
+ "cell_type": "code",
23
+ "execution_count": 5,
24
+ "id": "f0f4ce28",
25
+ "metadata": {},
26
+ "outputs": [],
27
+ "source": [
28
+ "from qwenimage.reporting.datamodels import ExperimentSet\n",
29
+ "from qwenimage.reporting.visualize_barplot import compare_sets_with_timing"
30
+ ]
31
+ },
32
+ {
33
+ "cell_type": "code",
34
+ "execution_count": 6,
35
+ "id": "226af1b2",
36
+ "metadata": {},
37
+ "outputs": [
38
+ {
39
+ "name": "stdout",
40
+ "output_type": "stream",
41
+ "text": [
42
+ "Setting up [LPIPS] perceptual loss: trunk [alex], v[0.1], spatial [off]\n"
43
+ ]
44
+ },
45
+ {
46
+ "name": "stderr",
47
+ "output_type": "stream",
48
+ "text": [
49
+ "/home/ubuntu/.local/lib/python3.10/site-packages/torchvision/models/_utils.py:208: UserWarning: The parameter 'pretrained' is deprecated since 0.13 and may be removed in the future, please use 'weights' instead.\n",
50
+ " warnings.warn(\n",
51
+ "/home/ubuntu/.local/lib/python3.10/site-packages/torchvision/models/_utils.py:223: UserWarning: Arguments other than a weight enum or `None` for 'weights' are deprecated since 0.13 and may be removed in the future. The current behavior is equivalent to passing `weights=AlexNet_Weights.IMAGENET1K_V1`. You can also use `weights=AlexNet_Weights.DEFAULT` to get the most up-to-date weights.\n",
52
+ " warnings.warn(msg)\n"
53
+ ]
54
+ },
55
+ {
56
+ "name": "stdout",
57
+ "output_type": "stream",
58
+ "text": [
59
+ "Loading model from: /home/ubuntu/.local/lib/python3.10/site-packages/lpips/weights/v0.1/alex.pth\n"
60
+ ]
61
+ },
62
+ {
63
+ "data": {
64
+ "image/png": "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Xvo08HStsltqvb4auHot2iQiIiIiItIkRA9/yGWPTFip3E58YIXXlx45gOiolXOeyTqIEgOB24ADl61fDhAlp8ePM4gSjxJWJls5QI+SOQnQe9fnSUVERERERGRF0VFbK/DOpiixCfAIcBJR8rO08rZAAVFyXvx8f8K07waXaRb321m/LO4iIiIiIiIi2RMl7gOGAl2JElOBS4HisC15C3AJ0AW4iSgBy5dT6wY8GpcVAfcSJZ/NRpOzlcVdREREREREJHui5PFr2H4acFod5ZMIK4plXUGG9S4HDi8pqxhSUlZR3JANEhEREREREWmOspLFXURERERERKRZiBJnA0cRJfde212zlsVdREREREREpBnoBwxZlx2VxV1EREREREQkD2QUoFeWl37V0A0RERERERERaQK+Byavy46rTRJXUlbxXklZxa/j58eXlFXcnrbtypKyitmr3ltERERERESkmYmSlxMl12kU+pqyuG8H9IyfDwZ+mratNdBxXU4qIiIiIiIiIivKdJk1EREREREREWlAmQTo3uCtEBEREREREWnmMkkS94uSsopTCEPaKSmr+C4ub91grRIRERERERFpZjIJ0FvGPykd056rd11EREREREQkSnQj5HHrBMwBxhIlv1mbQ6wpQB+2Tg0TERERERERaeqiRCFwMnAGsGMd298DbgbuJEpWr+lwqw3QK8tLX1mnRoqIiIiIiIg0fROAfvHzL4CPgblAB2BLYAfgNuC3wOZrOlgmQ9xFREREREREZGUtgAuB+4mS01faGiU2Bo4HzsnkYArQRURERERERNZNv9UOXQ9B+1+JEtdmcjCtgy4iIiIiIiKyLlYbnCd2J0psvcZ6adSDLiIiIiIiIrK+osQtwC7A9sDdhKHtECV+SZS8KZNDrFWAXlJW0QH4GdAe+G9leenotdlfREREREREpInan5A0rg1wLPABUAKcC6x/gF5SVnE/cAjQA0gCLxHuBgBcWlJWcWJleenIdWm5iIiIiIiISBPSHXgGGECYTn4SITncSZkeYE1z0HcE3qwsL50D7E5IEb8UeAKoIWSrExEREREREWnufgC2IwxtXwp8QsjyvijTA6xpiPtGwH/j5/vGj/+uLC89q6Ss4j7goLVprYiIiIiIiEhWRInbgYOBGUTJrevYbsB1hLh2AXAyUfK9eNvweFshcBtRsjyD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OBAYABxPlBhQq9aXwBCi5EDgCmBEre3DiJLbZSM4B/Wgi4iIiIiISNM0GJhIlJwEQJS4HzgMmLCsRpQcnVZ/DNAzi+1biXrQRUREREREpDEqMrN30n5Or7W9BzAl7fXUuGxVTgWeSXvtwPNEiXeJErWP3SDUgy4iIiIiIiKNUZW7r27oudVR5nXWjBLDCAH6HmmluxMlpxMlNgReIEp8QpR8dZ1bmwH1oIuIiIiIiEhTNBXolfa6JzB9pVpRYiBwG3AYUXL28vLk9PhxBvAoYch8g1IPuoiIyFp477ERjH38tpXKbz9lxf+ztzvsNHY4PCuj4URERKRubwObESV6A9OA44ATVqgRJTYBHgFOIkp+llbeFiggSs6Ln+8PXN7QDVaALiIishZ2OPx0Bd7S6OjGkog0S1GyiihxDvAcYZm124mSHxElzoy33wJcAnQBbiJKwPLl1LoBj8ZlRcC9RMlnG7rJCtBFREREmjjdWBKRZitKPg08XavslrTnpwGn1bHfJGDbhm3cyjQHXURERERERCQPKEAXERERERERyQMK0EVERERERETygAJ0ERERERERkTygAF1EREREREQkDyhAFxEREREREckDCtBFRERERERE8oACdBEREREREZE8oABdREREREREJA8oQBcRERERERHJAwrQRURERERERPKAAnQRERERERGRPKAAXURERERERCQPKEAXERERERERyQNFuW6ArN6D70zhvrcmY2ZcduhWbN0jsWzboqXV/Pbh8Uyfs5CNO7bmL0cNpFVxIVO+W8BFD41nSXUNe2+xIWcP6wfAqE9ncN1/PwfgV/v2Z0j/DQC48eWJvPTJDFoUFnDV0QPp1blN9t+oiIiIiIhIM6ce9DyWXLCUO0ZXcv/pu3LtsdsRPfHRCtsfencqfTdox4Nn7kafru146N2pAPzl2U84f7/+PHzWboz+YhYTZ/xAdY1T/swn3HHKYO44ZTD/9/THVNc4E2f8wOgvZvHwWbvxq3034y/PfpKLtyoiIiIiItLsKUDPY+9P+Z5BJZ1pUVRAr85tmL+kmsVV1cu2j5k0m7232BCAfbbckLe+/A6ACV/PZXDvzgAM2zyUfzlrPj07tSHRuphE62J6dmrDV7PnM2bSbIZtHo6xc58ufPz13Cy/SxEREREREQEF6HktuXApidbFy163b1VEcsHSOrcn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",
65
+ "text/plain": [
66
+ "<Figure size 1008x504 with 2 Axes>"
67
+ ]
68
+ },
69
+ "metadata": {},
70
+ "output_type": "display_data"
71
+ },
72
+ {
73
+ "data": {
74
+ "text/html": [
75
+ "<div>\n",
76
+ "<style scoped>\n",
77
+ " .dataframe tbody tr th:only-of-type {\n",
78
+ " vertical-align: middle;\n",
79
+ " }\n",
80
+ "\n",
81
+ " .dataframe tbody tr th {\n",
82
+ " vertical-align: top;\n",
83
+ " }\n",
84
+ "\n",
85
+ " .dataframe thead th {\n",
86
+ " text-align: right;\n",
87
+ " }\n",
88
+ "</style>\n",
89
+ "<table border=\"1\" class=\"dataframe\">\n",
90
+ " <thead>\n",
91
+ " <tr style=\"text-align: right;\">\n",
92
+ " <th></th>\n",
93
+ " <th>experiment</th>\n",
94
+ " <th>lpips_mean</th>\n",
95
+ " <th>lpips_std</th>\n",
96
+ " <th>time_mean</th>\n",
97
+ " <th>time_std</th>\n",
98
+ " </tr>\n",
99
+ " </thead>\n",
100
+ " <tbody>\n",
101
+ " <tr>\n",
102
+ " <th>0</th>\n",
103
+ " <td>qwen_base</td>\n",
104
+ " <td>0.000000</td>\n",
105
+ " <td>0.000000</td>\n",
106
+ " <td>1.752080</td>\n",
107
+ " <td>0.038048</td>\n",
108
+ " </tr>\n",
109
+ " <tr>\n",
110
+ " <th>1</th>\n",
111
+ " <td>qwen_sageattn_qk_int8_pv_fp16_triton</td>\n",
112
+ " <td>0.853700</td>\n",
113
+ " <td>0.112891</td>\n",
114
+ " <td>1.775369</td>\n",
115
+ " <td>0.272377</td>\n",
116
+ " </tr>\n",
117
+ " <tr>\n",
118
+ " <th>2</th>\n",
119
+ " <td>qwen_sageattn_qk_int8_pv_fp16_cuda</td>\n",
120
+ " <td>0.203273</td>\n",
121
+ " <td>0.097512</td>\n",
122
+ " <td>1.777100</td>\n",
123
+ " <td>0.244729</td>\n",
124
+ " </tr>\n",
125
+ " <tr>\n",
126
+ " <th>3</th>\n",
127
+ " <td>qwen_sageattn_qk_int8_pv_fp8_cuda</td>\n",
128
+ " <td>0.201616</td>\n",
129
+ " <td>0.098540</td>\n",
130
+ " <td>1.815426</td>\n",
131
+ " <td>0.075430</td>\n",
132
+ " </tr>\n",
133
+ " <tr>\n",
134
+ " <th>4</th>\n",
135
+ " <td>qwen_sageattn_qk_int8_pv_fp8_cuda_sm90</td>\n",
136
+ " <td>0.839612</td>\n",
137
+ " <td>0.055112</td>\n",
138
+ " <td>1.299148</td>\n",
139
+ " <td>0.068006</td>\n",
140
+ " </tr>\n",
141
+ " </tbody>\n",
142
+ "</table>\n",
143
+ "</div>"
144
+ ],
145
+ "text/plain": [
146
+ " experiment lpips_mean lpips_std time_mean \\\n",
147
+ "0 qwen_base 0.000000 0.000000 1.752080 \n",
148
+ "1 qwen_sageattn_qk_int8_pv_fp16_triton 0.853700 0.112891 1.775369 \n",
149
+ "2 qwen_sageattn_qk_int8_pv_fp16_cuda 0.203273 0.097512 1.777100 \n",
150
+ "3 qwen_sageattn_qk_int8_pv_fp8_cuda 0.201616 0.098540 1.815426 \n",
151
+ "4 qwen_sageattn_qk_int8_pv_fp8_cuda_sm90 0.839612 0.055112 1.299148 \n",
152
+ "\n",
153
+ " time_std \n",
154
+ "0 0.038048 \n",
155
+ "1 0.272377 \n",
156
+ "2 0.244729 \n",
157
+ "3 0.075430 \n",
158
+ "4 0.068006 "
159
+ ]
160
+ },
161
+ "execution_count": 6,
162
+ "metadata": {},
163
+ "output_type": "execute_result"
164
+ }
165
+ ],
166
+ "source": [
167
+ "df_all = compare_sets_with_timing(\n",
168
+ " ExperimentSet.create(\n",
169
+ " \"qwen_base\",\n",
170
+ " \"qwen_sageattn_qk_int8_pv_fp16_triton\",\n",
171
+ " \"qwen_sageattn_qk_int8_pv_fp16_cuda\",\n",
172
+ " \"qwen_sageattn_qk_int8_pv_fp8_cuda\",\n",
173
+ " \"qwen_sageattn_qk_int8_pv_fp8_cuda_sm90\",\n",
174
+ " ),\n",
175
+ " profile_target=\"loop\",\n",
176
+ " sort_by=None\n",
177
+ ")\n",
178
+ "\n",
179
+ "df_all\n"
180
+ ]
181
+ },
182
+ {
183
+ "cell_type": "code",
184
+ "execution_count": null,
185
+ "id": "477d7613",
186
+ "metadata": {},
187
+ "outputs": [],
188
+ "source": []
189
+ },
190
+ {
191
+ "cell_type": "code",
192
+ "execution_count": null,
193
+ "id": "2e99efc4",
194
+ "metadata": {},
195
+ "outputs": [],
196
+ "source": []
197
+ },
198
+ {
199
+ "cell_type": "code",
200
+ "execution_count": null,
201
+ "id": "06c65a7a",
202
+ "metadata": {},
203
+ "outputs": [],
204
+ "source": []
205
+ },
206
+ {
207
+ "cell_type": "code",
208
+ "execution_count": null,
209
+ "id": "31dea8be",
210
+ "metadata": {},
211
+ "outputs": [],
212
+ "source": []
213
+ },
214
+ {
215
+ "cell_type": "code",
216
+ "execution_count": null,
217
+ "id": "4efef8a4",
218
+ "metadata": {},
219
+ "outputs": [],
220
+ "source": []
221
+ },
222
+ {
223
+ "cell_type": "code",
224
+ "execution_count": null,
225
+ "id": "15b6d974",
226
+ "metadata": {},
227
+ "outputs": [],
228
+ "source": []
229
+ }
230
+ ],
231
+ "metadata": {
232
+ "kernelspec": {
233
+ "display_name": "Python 3",
234
+ "language": "python",
235
+ "name": "python3"
236
+ },
237
+ "language_info": {
238
+ "codemirror_mode": {
239
+ "name": "ipython",
240
+ "version": 3
241
+ },
242
+ "file_extension": ".py",
243
+ "mimetype": "text/x-python",
244
+ "name": "python",
245
+ "nbconvert_exporter": "python",
246
+ "pygments_lexer": "ipython3",
247
+ "version": "3.10.12"
248
+ }
249
+ },
250
+ "nbformat": 4,
251
+ "nbformat_minor": 5
252
+ }
scripts/{lpips_compare.ipynb → visualize_report.ipynb} RENAMED
@@ -20,7 +20,7 @@
20
  },
21
  {
22
  "cell_type": "code",
23
- "execution_count": 2,
24
  "id": "f0f4ce28",
25
  "metadata": {},
26
  "outputs": [
@@ -65,95 +65,18 @@
65
  "import torchvision.transforms.v2.functional as TF\n",
66
  "from pydantic import BaseModel\n",
67
  "\n",
68
- "from qwenimage.reporting import ExperimentSet, SetData, compare_lpips\n",
69
  "from qwenimage.experiment import ExperimentConfig\n",
70
  "from qwenimage.experiments.experiments_qwen import ExperimentRegistry"
71
  ]
72
  },
73
  {
74
  "cell_type": "code",
75
- "execution_count": 3,
76
  "id": "6e244007",
77
  "metadata": {},
78
  "outputs": [],
79
- "source": [
80
- "\n",
81
- "\n",
82
- "\n",
83
- "def compare_sets(experiment_set:ExperimentSet, sort_by_mean=False, loss_fn=None):\n",
84
- " original_data = SetData(name=experiment_set.original)\n",
85
- " comparison_data = [SetData(name=comp) for comp in experiment_set.comparisons]\n",
86
- "\n",
87
- " if loss_fn is None:\n",
88
- " loss_fn = lpips.LPIPS(net='alex') # or 'vgg' or 'squeeze'\n",
89
- " if torch.cuda.is_available():\n",
90
- " loss_fn = loss_fn.cuda()\n",
91
- "\n",
92
- " all_set_errors = defaultdict(list)\n",
93
- " for i in range(len(original_data)):\n",
94
- " for comp in comparison_data:\n",
95
- " lpips_error = compare_lpips(loss_fn, original_data[i], comp[i])\n",
96
- " all_set_errors[comp.name].append(lpips_error)\n",
97
- " \n",
98
- " error_stat_list = []\n",
99
- " for name, errors in all_set_errors.items():\n",
100
- " err_mean = statistics.mean(errors)\n",
101
- " err_std = statistics.stdev(errors)\n",
102
- " err_len = len(errors)\n",
103
- " error_stat_list.append({\n",
104
- " 'name': f\"{name}\",\n",
105
- " 'mean': err_mean,\n",
106
- " 'std': err_std,\n",
107
- " 'len': err_len\n",
108
- " })\n",
109
- " \n",
110
- " err_df = pd.DataFrame(error_stat_list)\n",
111
- " report_dir = ExperimentConfig().report_dir\n",
112
- " err_df.to_csv(report_dir / f\"{experiment_set.original}_{'_'.join(experiment_set.comparisons)[:100]}.csv\")\n",
113
- " \n",
114
- " if sort_by_mean:\n",
115
- " err_df = err_df.sort_values('mean', ascending=False)\n",
116
- "\n",
117
- "\n",
118
- " fig, ax = plt.subplots(figsize=(12, 6))\n",
119
- " x_pos = range(len(err_df))\n",
120
- "\n",
121
- " # bar_x = err_df[\"name\"]\n",
122
- " bar_h = err_df[\"mean\"]\n",
123
- " bar_std = err_df[\"std\"]\n",
124
- " bars = ax.bar(\n",
125
- " x_pos, bar_h, yerr=bar_std, \n",
126
- " capsize=12, alpha=0.7, edgecolor='black'\n",
127
- " )\n",
128
- "\n",
129
- " ax.set_xlabel('LPIPS error for experiment type', fontsize=12, fontweight='bold')\n",
130
- " ax.set_ylabel('Error', fontsize=12, fontweight='bold')\n",
131
- " ax.set_title(f\"LPIPS comparison\", \n",
132
- " fontsize=14, fontweight='bold')\n",
133
- " \n",
134
- "\n",
135
- " ax.set_xticks(x_pos)\n",
136
- " ax.set_xticklabels(\n",
137
- " # [row['experiment'] for _, row in plot_data.iterrows()], \n",
138
- " err_df[\"name\"],\n",
139
- " rotation=15, ha='right', fontsize=12\n",
140
- " )\n",
141
- "\n",
142
- " ax.grid(axis='y', alpha=0.3)\n",
143
- "\n",
144
- " \n",
145
- " for i, (idx, row) in enumerate(err_df.iterrows()): \n",
146
- " ax.text(i - 0.2, row['mean'] + 0.01, f\"{row['mean']:.3f}\", \n",
147
- " ha='center', va='bottom', fontsize=12)\n",
148
- " \n",
149
- " plt.tight_layout()\n",
150
- "\n",
151
- " plot_path = report_dir / f\"{experiment_set.original}_{'_'.join(experiment_set.comparisons)[:100]}.png\"\n",
152
- " plt.savefig(plot_path, dpi=300, bbox_inches='tight')\n",
153
- "\n",
154
- " plt.show()\n",
155
- " \n"
156
- ]
157
  },
158
  {
159
  "cell_type": "code",
@@ -369,154 +292,11 @@
369
  },
370
  {
371
  "cell_type": "code",
372
- "execution_count": 7,
373
  "id": "91b0983e",
374
  "metadata": {},
375
  "outputs": [],
376
- "source": [
377
- "from typing import Literal\n",
378
- "\n",
379
- "\n",
380
- "def compare_sets_with_timing(experiment_set: ExperimentSet, profile_target: str = \"loop\", sort_by=\"time\", loss_fn=None, match_strategy:Literal[\"equal\", \"contain\"]=\"equal\"):\n",
381
- " \"\"\"\n",
382
- " Create dual-axis bar plot with LPIPS error (left) and profile time (right) for each experiment.\n",
383
- " \n",
384
- " Args:\n",
385
- " experiment_set: ExperimentSet with original and comparison experiments\n",
386
- " profile_target: Which profile target to plot timing for (e.g., \"loop\", \"run_once\")\n",
387
- " sort_by: Sort experiments by \"time\", \"lpips\", or None\n",
388
- " loss_fn: LPIPS loss function (will create if None)\n",
389
- " \"\"\"\n",
390
- " # Get LPIPS data\n",
391
- " original_data = SetData(name=experiment_set.original)\n",
392
- " comparison_data = [SetData(name=comp) for comp in experiment_set.comparisons]\n",
393
- "\n",
394
- " if loss_fn is None:\n",
395
- " loss_fn = lpips.LPIPS(net='alex')\n",
396
- " if torch.cuda.is_available():\n",
397
- " loss_fn = loss_fn.cuda()\n",
398
- "\n",
399
- " all_set_errors = defaultdict(list)\n",
400
- " for i in range(len(original_data)):\n",
401
- " for comp in comparison_data:\n",
402
- " lpips_error = compare_lpips(loss_fn, original_data[i], comp[i])\n",
403
- " all_set_errors[comp.name].append(lpips_error)\n",
404
- " \n",
405
- " lpips_stats = []\n",
406
- " # Add the original experiment with LPIPS = 0.0 (compared to itself)\n",
407
- " lpips_stats.append({\n",
408
- " 'experiment': experiment_set.original,\n",
409
- " 'lpips_mean': 0.0,\n",
410
- " 'lpips_std': 0.0\n",
411
- " })\n",
412
- " # Add comparison experiments\n",
413
- " for name, errors in all_set_errors.items():\n",
414
- " err_mean = statistics.mean(errors)\n",
415
- " err_std = statistics.stdev(errors)\n",
416
- " lpips_stats.append({\n",
417
- " 'experiment': name,\n",
418
- " 'lpips_mean': err_mean,\n",
419
- " 'lpips_std': err_std\n",
420
- " })\n",
421
- " \n",
422
- " lpips_df = pd.DataFrame(lpips_stats)\n",
423
- " \n",
424
- " # Get timing data\n",
425
- " report_dir = ExperimentConfig().report_dir\n",
426
- " timing_data = []\n",
427
- " # Include original and all comparisons\n",
428
- " all_experiments = [experiment_set.original] + list(experiment_set.comparisons)\n",
429
- " for name in all_experiments:\n",
430
- " csv_path = report_dir / f\"{name}.csv\"\n",
431
- " if csv_path.exists():\n",
432
- " df = pd.read_csv(csv_path, index_col=0)\n",
433
- " if match_strategy == \"equal\":\n",
434
- " target_row = df[df['name'] == profile_target]\n",
435
- " elif match_strategy == \"contain\":\n",
436
- " target_row = df[df['name'].str.contains(profile_target, case=False, na=False)]\n",
437
- " else:\n",
438
- " raise ValueError()\n",
439
- "\n",
440
- " if not target_row.empty:\n",
441
- " timing_data.append({\n",
442
- " 'experiment': name,\n",
443
- " 'time_mean': target_row['mean'].values[0],\n",
444
- " 'time_std': target_row['std'].values[0]\n",
445
- " })\n",
446
- " \n",
447
- " timing_df = pd.DataFrame(timing_data)\n",
448
- " \n",
449
- " # Merge data\n",
450
- " combined_df = pd.merge(lpips_df, timing_df, on='experiment', how='inner')\n",
451
- " \n",
452
- " # Sort if requested\n",
453
- " if sort_by == \"time\":\n",
454
- " combined_df = combined_df.sort_values('time_mean', ascending=False)\n",
455
- " elif sort_by == \"lpips\":\n",
456
- " combined_df = combined_df.sort_values('lpips_mean', ascending=False)\n",
457
- " \n",
458
- " # Create dual-axis plot\n",
459
- " fig, ax1 = plt.subplots(figsize=(14, 7))\n",
460
- " \n",
461
- " x = np.arange(len(combined_df))\n",
462
- " width = 0.35\n",
463
- " \n",
464
- " # Left axis - LPIPS\n",
465
- " ax1.set_xlabel('Experiment', fontsize=12, fontweight='bold')\n",
466
- " ax1.set_ylabel('LPIPS Error', fontsize=12, fontweight='bold', color='tab:blue')\n",
467
- " bars1 = ax1.bar(x - width/2, combined_df['lpips_mean'], width, \n",
468
- " yerr=combined_df['lpips_std'], capsize=5, \n",
469
- " label='LPIPS Error', color='tab:blue', alpha=0.7, edgecolor='black')\n",
470
- " ax1.tick_params(axis='y', labelcolor='tab:blue')\n",
471
- " ax1.grid(axis='y', alpha=0.3)\n",
472
- " \n",
473
- " # Right axis - Time\n",
474
- " ax2 = ax1.twinx()\n",
475
- " ax2.set_ylabel(f'Time (s) - {profile_target}', fontsize=12, fontweight='bold', color='tab:orange')\n",
476
- " bars2 = ax2.bar(x + width/2, combined_df['time_mean'], width,\n",
477
- " yerr=combined_df['time_std'], capsize=5,\n",
478
- " label=f'{profile_target} Time', color='tab:orange', alpha=0.7, edgecolor='black')\n",
479
- " ax2.tick_params(axis='y', labelcolor='tab:orange')\n",
480
- " \n",
481
- " # Align both axes to start at 0\n",
482
- " ax1.set_ylim(bottom=0)\n",
483
- " ax2.set_ylim(bottom=0)\n",
484
- " \n",
485
- " # Set x-axis labels\n",
486
- " ax1.set_xticks(x)\n",
487
- " ax1.set_xticklabels(combined_df['experiment'], rotation=45, ha='right', fontsize=10)\n",
488
- " \n",
489
- " # Add value labels on bars\n",
490
- " for i, row in combined_df.iterrows():\n",
491
- " idx = combined_df.index.get_loc(i)\n",
492
- " # LPIPS value\n",
493
- " ax1.text(idx - width/2, row['lpips_mean'] + row['lpips_std'] + 0.001, \n",
494
- " f\"{row['lpips_mean']:.4f}\", ha='center', va='bottom', \n",
495
- " fontsize=9, color='tab:blue')\n",
496
- " # Time value\n",
497
- " ax2.text(idx + width/2, row['time_mean'] + row['time_std'] + 0.01,\n",
498
- " f\"{row['time_mean']:.3f}s\", ha='center', va='bottom',\n",
499
- " fontsize=9, color='tab:orange')\n",
500
- " \n",
501
- " # Title and legend\n",
502
- " ax1.set_title(f'LPIPS Error vs {profile_target.title()} Time Comparison\\nBaseline: {experiment_set.original}',\n",
503
- " fontsize=14, fontweight='bold', pad=20)\n",
504
- " \n",
505
- " # Combine legends\n",
506
- " lines1, labels1 = ax1.get_legend_handles_labels()\n",
507
- " lines2, labels2 = ax2.get_legend_handles_labels()\n",
508
- " ax1.legend(lines1 + lines2, labels1 + labels2, loc='upper left', fontsize=10)\n",
509
- " \n",
510
- " plt.tight_layout()\n",
511
- " \n",
512
- " # Save plot\n",
513
- " plot_path = report_dir / f\"{experiment_set.original}_dual_axis_{profile_target}.png\"\n",
514
- " plt.savefig(plot_path, dpi=300, bbox_inches='tight')\n",
515
- " \n",
516
- " plt.show()\n",
517
- " \n",
518
- " return combined_df\n"
519
- ]
520
  },
521
  {
522
  "cell_type": "code",
 
20
  },
21
  {
22
  "cell_type": "code",
23
+ "execution_count": null,
24
  "id": "f0f4ce28",
25
  "metadata": {},
26
  "outputs": [
 
65
  "import torchvision.transforms.v2.functional as TF\n",
66
  "from pydantic import BaseModel\n",
67
  "\n",
68
+ "from qwenimage.reporting.visualize_barplot import compare_sets, compare_sets_with_timing\n",
69
  "from qwenimage.experiment import ExperimentConfig\n",
70
  "from qwenimage.experiments.experiments_qwen import ExperimentRegistry"
71
  ]
72
  },
73
  {
74
  "cell_type": "code",
75
+ "execution_count": null,
76
  "id": "6e244007",
77
  "metadata": {},
78
  "outputs": [],
79
+ "source": []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
  },
81
  {
82
  "cell_type": "code",
 
292
  },
293
  {
294
  "cell_type": "code",
295
+ "execution_count": null,
296
  "id": "91b0983e",
297
  "metadata": {},
298
  "outputs": [],
299
+ "source": []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
300
  },
301
  {
302
  "cell_type": "code",