EgeEken commited on
Commit
08edfc9
1 Parent(s): 1950f72

pbc3: restore PIL resampling and fix benchmarks

Browse files
Files changed (8) hide show
  1. .gitignore +3 -1
  2. PBC3.py +20 -7
  3. PBC3_animation.py +3 -2
  4. pbc3_benchmark.py +2 -1
  5. pbc3_heads.py +3 -1
  6. pbc3_ops.py +8 -50
  7. pbc3_quick_rd.py +8 -5
  8. server.py +2 -2
.gitignore CHANGED
@@ -13,4 +13,6 @@ hpt_data_val/
13
  *.pt
14
  training_space/results/
15
  training_space/runs/*
16
- !training_space/runs/RL_checkpoint.pt
 
 
 
13
  *.pt
14
  training_space/results/
15
  training_space/runs/*
16
+ !training_space/runs/RL_checkpoint.pt
17
+ pbc3_resampling_benchmark.*
18
+ pbc3_resampling_top_variants_20.*
PBC3.py CHANGED
@@ -162,7 +162,10 @@ class PBC3:
162
  return canvas
163
  out = np.empty((new_h, new_w, ch), dtype=np.int32)
164
  for c in range(ch):
165
- out[:, :, c] = np.rint(ops.bicubic_resample_2d(canvas[:, :, c], new_h, new_w)).astype(np.int32)
 
 
 
166
  return out
167
 
168
  @classmethod
@@ -477,12 +480,22 @@ class PBC3:
477
  return image
478
 
479
 
480
- def preload_numba() -> None:
481
- """## Runs a tiny encode so numba compiles the hot kernels once"""
482
- arr = ((np.arange(16 * 16 * 3, dtype=np.uint16).reshape(16, 16, 3) * 37) % 256).astype(np.uint8)
483
- img = Image.fromarray(arr)
484
- PBC3.compress(img, PBC3Config(patch_count=10, auto_downsample_init=True, learned_filler_enabled=False))
485
- print("[preload] numba kernels compiled")
 
 
 
 
 
 
 
 
 
 
486
 
487
 
488
  if __name__ == "__main__":
 
162
  return canvas
163
  out = np.empty((new_h, new_w, ch), dtype=np.int32)
164
  for c in range(ch):
165
+ layer_arr = np.ascontiguousarray(canvas[:, :, c], dtype=np.float32)
166
+ layer = Image.frombuffer("F", (w, h), layer_arr, "raw", "F", 0, 1)
167
+ layer = layer.resize((new_w, new_h), cls.RESAMPLE_FILTER)
168
+ out[:, :, c] = np.rint(np.asarray(layer, dtype=np.float32)).astype(np.int32)
169
  return out
170
 
171
  @classmethod
 
480
  return image
481
 
482
 
483
+ def preload_numba(model_path: str = "patch_policy.npz") -> None:
484
+ """## Warms the production learned RGB/RGBA encode paths."""
485
+ h, w = 512, 768
486
+ base = np.arange(h * w * 4, dtype=np.uint32).reshape(h, w, 4)
487
+ config = PBC3Config.quality(
488
+ patch_count=50,
489
+ learned_filler_enabled=True,
490
+ learned_filler_model_path=model_path,
491
+ auto_downsample_max_pixels=250_000,
492
+ use_lzma=True,
493
+ compute_final_mse=True,
494
+ )
495
+ for channels in (3, 4):
496
+ arr = ((base[:, :, :channels] * 37 + channels * 19) % 256).astype(np.uint8)
497
+ PBC3.compress(Image.fromarray(arr), config=config)
498
+ print("[preload] production PBC3 paths warmed")
499
 
500
 
501
  if __name__ == "__main__":
PBC3_animation.py CHANGED
@@ -2,6 +2,7 @@ import os
2
  import numpy as np
3
  from PIL import Image, ImageDraw, ImageFont
4
  from PBC3 import PBC3, BitReader
 
5
 
6
 
7
  def _font(size):
@@ -345,7 +346,7 @@ def animate_pbc3(
345
 
346
  tc = target.shape[2] if target is not None else 0
347
  prev_mse = float(np.mean((canvas[:, :, :tc] - target) ** 2)) if target is not None else None
348
- PBC3.apply_grid(canvas[:, :, channel], x, y, pw, ph, cell_size, values)
349
  now_mse = float(np.mean((canvas[:, :, :tc] - target) ** 2)) if target is not None else None
350
  parts = [f"Patch {i}/{patch_count}", f"Stream Size: {current_kb:.2f} KB", f"(+{delta_kb:.2f} KB)"]
351
  if now_mse is not None:
@@ -364,4 +365,4 @@ def animate_pbc3(
364
  output_size,
365
  ))
366
 
367
- return _write_frames(frames, output_path, fps, fallback_to_gif=fallback_to_gif)
 
2
  import numpy as np
3
  from PIL import Image, ImageDraw, ImageFont
4
  from PBC3 import PBC3, BitReader
5
+ import pbc3_ops as ops
6
 
7
 
8
  def _font(size):
 
346
 
347
  tc = target.shape[2] if target is not None else 0
348
  prev_mse = float(np.mean((canvas[:, :, :tc] - target) ** 2)) if target is not None else None
349
+ ops.apply_grid(canvas[:, :, channel], x, y, pw, ph, cell_size, values)
350
  now_mse = float(np.mean((canvas[:, :, :tc] - target) ** 2)) if target is not None else None
351
  parts = [f"Patch {i}/{patch_count}", f"Stream Size: {current_kb:.2f} KB", f"(+{delta_kb:.2f} KB)"]
352
  if now_mse is not None:
 
365
  output_size,
366
  ))
367
 
368
+ return _write_frames(frames, output_path, fps, fallback_to_gif=fallback_to_gif)
pbc3_benchmark.py CHANGED
@@ -9,7 +9,7 @@ import time
9
  import numpy as np
10
  from PIL import Image, ImageOps
11
 
12
- from PBC3 import PBC3
13
  from pbc3_types import PBC3Config
14
 
15
  try:
@@ -216,6 +216,7 @@ def _run(codecs, n_trials):
216
  images = dataset()
217
  if not images:
218
  raise RuntimeError("No images found in hpt_data/")
 
219
  jobs = _jobs(codecs)
220
  total = n_trials * len(jobs) * len(images)
221
  run_id = time.strftime("%Y%m%d_%H%M%S")
 
9
  import numpy as np
10
  from PIL import Image, ImageOps
11
 
12
+ from PBC3 import PBC3, preload_numba
13
  from pbc3_types import PBC3Config
14
 
15
  try:
 
216
  images = dataset()
217
  if not images:
218
  raise RuntimeError("No images found in hpt_data/")
219
+ preload_numba(os.path.join(PROJECT_DIR, "patch_policy.npz"))
220
  jobs = _jobs(codecs)
221
  total = n_trials * len(jobs) * len(images)
222
  run_id = time.strftime("%Y%m%d_%H%M%S")
pbc3_heads.py CHANGED
@@ -153,7 +153,9 @@ class FillerHead:
153
  hidden_residual = target[y:y + bh, x:x + bw, c] - canvas[y:y + bh, x:x + bw, c]
154
  before = target[y:y + bh, x:x + bw, c] - np.clip(canvas[y:y + bh, x:x + bw, c], 0, 255)
155
  before_sse = float(np.sum(before.astype(np.int64) ** 2))
156
- patch, values = ops.make_patch(c, x, y, bw, bh, cell_size, hidden_residual, config, bitcount)
 
 
157
  delta = ops.signed_resample(values, bh, bw).astype(np.int32)
158
  after = target[y:y + bh, x:x + bw, c] - np.clip(canvas[y:y + bh, x:x + bw, c] + delta, 0, 255)
159
  reduction = before_sse - float(np.sum(after.astype(np.int64) ** 2))
 
153
  hidden_residual = target[y:y + bh, x:x + bw, c] - canvas[y:y + bh, x:x + bw, c]
154
  before = target[y:y + bh, x:x + bw, c] - np.clip(canvas[y:y + bh, x:x + bw, c], 0, 255)
155
  before_sse = float(np.sum(before.astype(np.int64) ** 2))
156
+ patch, values = ops.make_patch(
157
+ c, x, y, bw, bh, cell_size, hidden_residual, config, bitcount,
158
+ )
159
  delta = ops.signed_resample(values, bh, bw).astype(np.int32)
160
  after = target[y:y + bh, x:x + bw, c] - np.clip(canvas[y:y + bh, x:x + bw, c] + delta, 0, 255)
161
  reduction = before_sse - float(np.sum(after.astype(np.int64) ** 2))
pbc3_ops.py CHANGED
@@ -12,7 +12,6 @@ PALETTE_GENERATED = 0
12
 
13
  _UINT64_MASK = (1 << 64) - 1
14
  _UINT32_SCALE = 1.0 / 4294967296.0
15
- _RESAMPLE_COEFF_CACHE = {}
16
 
17
 
18
  @njit(inline="always", cache=True)
@@ -49,58 +48,17 @@ class PBC3Rng:
49
  return low + self.next_uint32() % (high - low)
50
 
51
 
52
- def _bicubic_kernel(x):
53
- x = np.abs(np.asarray(x, dtype=np.float64))
54
- out = np.zeros_like(x)
55
- m1 = x < 1.0
56
- m2 = (x >= 1.0) & (x < 2.0)
57
- x1 = x[m1]
58
- x2 = x[m2]
59
- a = -0.5
60
- out[m1] = ((a + 2.0) * x1 - (a + 3.0)) * x1 * x1 + 1.0
61
- out[m2] = (((x2 - 5.0) * x2 + 8.0) * x2 - 4.0) * a
62
- return out
63
-
64
-
65
- def _resample_coeffs(in_size: int, out_size: int) -> np.ndarray:
66
- in_size, out_size = int(in_size), int(out_size)
67
- key = (in_size, out_size)
68
- coeffs = _RESAMPLE_COEFF_CACHE.get(key)
69
- if coeffs is not None:
70
- return coeffs
71
-
72
- scale = in_size / out_size
73
- filterscale = max(scale, 1.0)
74
- support = 2.0 * filterscale
75
- inv_filterscale = 1.0 / filterscale
76
- coeffs = np.zeros((out_size, in_size), dtype=np.float64)
77
-
78
- for xx in range(out_size):
79
- center = (xx + 0.5) * scale
80
- xmin = max(0, int(center - support + 0.5))
81
- xmax = min(in_size, int(center + support + 0.5))
82
- xs = np.arange(xmin, xmax, dtype=np.float64)
83
- weights = _bicubic_kernel((xs - center + 0.5) * inv_filterscale)
84
- total = weights.sum()
85
- if total != 0.0:
86
- weights /= total
87
- coeffs[xx, xmin:xmax] = weights
88
-
89
- _RESAMPLE_COEFF_CACHE[key] = coeffs
90
- return coeffs
91
-
92
-
93
  def bicubic_resample_2d(values, out_h: int, out_w: int) -> np.ndarray:
94
- arr = np.asarray(values, dtype=np.float64)
 
95
  out_h, out_w = int(out_h), int(out_w)
96
  if arr.shape == (out_h, out_w):
97
- return arr.copy()
98
- out = arr
99
- if arr.shape[1] != out_w:
100
- out = out @ _resample_coeffs(arr.shape[1], out_w).T
101
- if arr.shape[0] != out_h:
102
- out = _resample_coeffs(arr.shape[0], out_h) @ out
103
- return out
104
 
105
 
106
  def ceil_div(a: int, b: int) -> int:
 
12
 
13
  _UINT64_MASK = (1 << 64) - 1
14
  _UINT32_SCALE = 1.0 / 4294967296.0
 
15
 
16
 
17
  @njit(inline="always", cache=True)
 
48
  return low + self.next_uint32() % (high - low)
49
 
50
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  def bicubic_resample_2d(values, out_h: int, out_w: int) -> np.ndarray:
52
+ """Resamples a signed grid with the production PIL bicubic filter."""
53
+ arr = np.ascontiguousarray(values, dtype=np.float32)
54
  out_h, out_w = int(out_h), int(out_w)
55
  if arr.shape == (out_h, out_w):
56
+ return arr.astype(np.float64, copy=True)
57
+ return np.asarray(
58
+ Image.frombuffer("F", (arr.shape[1], arr.shape[0]), arr, "raw", "F", 0, 1)
59
+ .resize((out_w, out_h), Image.Resampling.BICUBIC),
60
+ dtype=np.float64,
61
+ )
 
62
 
63
 
64
  def ceil_div(a: int, b: int) -> int:
pbc3_quick_rd.py CHANGED
@@ -7,10 +7,10 @@ import time
7
 
8
  import numpy as np
9
  import optuna
10
- from PIL import Image
11
 
12
  import pbc3_sweep
13
- from PBC3 import PBC3
14
  from pbc3_types import PBC3Config
15
 
16
  RESULTS_PATH = os.path.join(pbc3_sweep.PROJECT_DIR, "pbc3_quick_rd.json")
@@ -110,19 +110,21 @@ def _eval_old_preset_subprocess(name, images, trial):
110
  code = r'''
111
  import json, os, sys, time
112
  import numpy as np
113
- from PIL import Image
114
  sys.path.insert(0, sys.argv[1])
115
  from PBC3 import PBC3
116
  try:
117
  from pbc3_types import PBC3Config
118
  except Exception:
119
  from pbc_types import PBC3Config
 
120
  preset = sys.argv[2]
121
  trial = int(sys.argv[3])
122
  images = json.loads(sys.stdin.read())
 
123
  out = []
124
  for im in images:
125
- img = Image.open(im["path"]).convert("RGB")
126
  arr = np.asarray(img)
127
  pixels = arr.shape[0] * arr.shape[1]
128
  cfg = getattr(PBC3Config, preset)()
@@ -154,6 +156,7 @@ def _run(n_trials, run_old):
154
  images = pbc3_sweep.dataset()
155
  if not images:
156
  raise RuntimeError("No images found in hpt_data/")
 
157
  _log(f"loaded {len(images)} images 路 {n_trials} trial(s)" + (" 路 live old enabled" if run_old else ""))
158
  out = {"created": time.time(), "n_trials": n_trials, "presets": []}
159
  for trial in range(1, n_trials + 1):
@@ -260,4 +263,4 @@ def results(mp_min=None, mp_max=None):
260
  "new_exists": os.path.exists(RESULTS_PATH),
261
  "old_pbc_exists": os.path.exists(os.path.join(OLD_PBC_DIR, "PBC3.py")),
262
  "rows": old["rows"] + live,
263
- }
 
7
 
8
  import numpy as np
9
  import optuna
10
+ from PIL import Image, ImageOps
11
 
12
  import pbc3_sweep
13
+ from PBC3 import PBC3, preload_numba
14
  from pbc3_types import PBC3Config
15
 
16
  RESULTS_PATH = os.path.join(pbc3_sweep.PROJECT_DIR, "pbc3_quick_rd.json")
 
110
  code = r'''
111
  import json, os, sys, time
112
  import numpy as np
113
+ from PIL import Image, ImageOps
114
  sys.path.insert(0, sys.argv[1])
115
  from PBC3 import PBC3
116
  try:
117
  from pbc3_types import PBC3Config
118
  except Exception:
119
  from pbc_types import PBC3Config
120
+ from PBC3 import preload_numba
121
  preset = sys.argv[2]
122
  trial = int(sys.argv[3])
123
  images = json.loads(sys.stdin.read())
124
+ preload_numba()
125
  out = []
126
  for im in images:
127
+ img = ImageOps.exif_transpose(Image.open(im["path"])).convert("RGB")
128
  arr = np.asarray(img)
129
  pixels = arr.shape[0] * arr.shape[1]
130
  cfg = getattr(PBC3Config, preset)()
 
156
  images = pbc3_sweep.dataset()
157
  if not images:
158
  raise RuntimeError("No images found in hpt_data/")
159
+ preload_numba(os.path.join(pbc3_sweep.PROJECT_DIR, "patch_policy.npz"))
160
  _log(f"loaded {len(images)} images 路 {n_trials} trial(s)" + (" 路 live old enabled" if run_old else ""))
161
  out = {"created": time.time(), "n_trials": n_trials, "presets": []}
162
  for trial in range(1, n_trials + 1):
 
263
  "new_exists": os.path.exists(RESULTS_PATH),
264
  "old_pbc_exists": os.path.exists(os.path.join(OLD_PBC_DIR, "PBC3.py")),
265
  "rows": old["rows"] + live,
266
+ }
server.py CHANGED
@@ -929,8 +929,8 @@ BOOT_ID = f"{time.time():.3f}"
929
 
930
  @app.on_event("startup")
931
  def _startup():
932
- print("[startup] preloading Numba JITs...", flush=True)
933
- preload_numba()
934
  print("[startup] done.", flush=True)
935
  print(f"[startup] BOOT_ID={BOOT_ID}", flush=True)
936
 
 
929
 
930
  @app.on_event("startup")
931
  def _startup():
932
+ print("[startup] warming production PBC3 paths...", flush=True)
933
+ preload_numba(os.path.join(_HERE, "patch_policy.npz"))
934
  print("[startup] done.", flush=True)
935
  print(f"[startup] BOOT_ID={BOOT_ID}", flush=True)
936