masterofaudio2077 commited on
Commit
d8eb6d6
Β·
verified Β·
1 Parent(s): 339ca5e

Upload 9 files

Browse files
Files changed (4) hide show
  1. app.py +20 -70
  2. check.py +17 -0
  3. inference.py +91 -79
  4. requirements.txt +1 -0
app.py CHANGED
@@ -1,105 +1,55 @@
1
- """
2
- Gradio app for StyleGAN v1 image generation.
3
- Run: gradio app.py
4
- For Hugging Face Spaces, the Space runs this file.
5
- """
6
  import os
7
  import gradio as gr
8
-
9
- # Backend must be set before any Keras/JAX imports
10
  os.environ["KERAS_BACKEND"] = "jax"
11
 
12
- from inference import load_weights, generate_images, WEIGHTS_PATH, STATE_PATH
13
- from configuration import RESOLUTIONS
14
 
15
- # Load model once at startup
16
  _model_loaded = False
17
 
18
-
19
- def load_model_once(resolution=256):
20
  global _model_loaded
21
  if _model_loaded:
22
  return True
23
- ok = load_weights(resolution=resolution)
24
  if ok:
25
  _model_loaded = True
26
  return ok
27
 
28
-
29
- def generate(n_images, resolution, seed):
30
  n_images = max(1, min(int(n_images), 16))
31
- resolution = int(resolution)
32
  seed = int(seed) if seed is not None and str(seed).strip() else None
33
 
34
- if not load_model_once(resolution):
35
- return (
36
- [],
37
- "No weights found. Add generator weights to the repo:\n"
38
- f"β€’ Keras: {WEIGHTS_PATH}\n"
39
- f"β€’ Or state dict: {STATE_PATH}\n"
40
- "See README for Hugging Face setup.",
41
- )
42
 
43
  try:
44
- images = generate_images(n_images, resolution=resolution, seed=seed)
45
- if not images:
46
  return [], "No images generated."
47
- return images, f"Generated {len(images)} image(s) at {resolution}Γ—{resolution}."
48
  except Exception as e:
49
  import traceback
50
  return [], f"Error: {e}\n{traceback.format_exc()}"
51
 
52
-
53
  def main():
54
- resolutions = [int(r) for r in RESOLUTIONS]
 
 
55
 
56
- with gr.Blocks(
57
- title="StyleGAN v1",
58
- theme=gr.themes.Soft(),
59
- ) as demo:
60
- gr.Markdown("# StyleGAN v1 – Image generation")
61
- gr.Markdown("Choose how many images to generate and the resolution. Then click **Generate**.")
62
-
63
- with gr.Row():
64
- n_images = gr.Slider(
65
- minimum=1,
66
- maximum=16,
67
- value=4,
68
- step=1,
69
- label="Number of images",
70
- )
71
- resolution = gr.Dropdown(
72
- choices=[str(r) for r in resolutions],
73
- value="256",
74
- label="Resolution",
75
- )
76
- seed = gr.Number(
77
- value=None,
78
- label="Random seed (optional)",
79
- precision=0,
80
- )
81
  with gr.Row():
82
- gen_btn = gr.Button("Generate", variant="primary")
83
- status = gr.Textbox(label="Status", interactive=False)
84
- gallery = gr.Gallery(
85
- label="Generated images",
86
- show_label=True,
87
- columns=4,
88
- object_fit="contain",
89
- height="auto",
90
- )
91
 
92
- gen_btn.click(
93
- fn=generate,
94
- inputs=[n_images, resolution, seed],
95
- outputs=[gallery, status],
96
- )
97
 
98
  demo.launch(
99
  server_name="0.0.0.0",
100
  server_port=int(os.environ.get("PORT", 7860)),
101
  )
102
 
103
-
104
  if __name__ == "__main__":
105
- main()
 
 
 
 
 
 
1
  import os
2
  import gradio as gr
 
 
3
  os.environ["KERAS_BACKEND"] = "jax"
4
 
5
+ from inference import load_weights, generate_images, WEIGHTS_H5, CHECKPOINT_PKL
 
6
 
 
7
  _model_loaded = False
8
 
9
+ def load_model_once():
 
10
  global _model_loaded
11
  if _model_loaded:
12
  return True
13
+ ok = load_weights(resolution=256)
14
  if ok:
15
  _model_loaded = True
16
  return ok
17
 
18
+ def generate(n_images, seed):
 
19
  n_images = max(1, min(int(n_images), 16))
 
20
  seed = int(seed) if seed is not None and str(seed).strip() else None
21
 
22
+ if not load_model_once():
23
+ return [], f"No weights found. Put checkpoint.pkl in:\n{os.path.dirname(WEIGHTS_H5)}"
 
 
 
 
 
 
24
 
25
  try:
26
+ images = generate_images(n_images, resolution=256, seed=seed)
27
+ if images is None or len(images) == 0:
28
  return [], "No images generated."
29
+ return images, f"Generated {len(images)} image(s) at 256Γ—256."
30
  except Exception as e:
31
  import traceback
32
  return [], f"Error: {e}\n{traceback.format_exc()}"
33
 
 
34
  def main():
35
+ with gr.Blocks(title="StyleGAN v1", theme=gr.themes.Soft()) as demo:
36
+ gr.Markdown("# StyleGAN v1 – Face Generation")
37
+ gr.Markdown("Generate faces at 256Γ—256. Optionally set a seed for reproducibility.")
38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  with gr.Row():
40
+ n_images = gr.Slider(minimum=1, maximum=16, value=4, step=1, label="Number of images")
41
+ seed = gr.Number(value=None, label="Random seed (optional)", precision=0)
 
 
 
 
 
 
 
42
 
43
+ gen_btn = gr.Button("Generate", variant="primary")
44
+ status = gr.Textbox(label="Status", interactive=False)
45
+ gallery = gr.Gallery(label="Generated images", columns=4, object_fit="contain", height="auto")
46
+
47
+ gen_btn.click(fn=generate, inputs=[n_images, seed], outputs=[gallery, status])
48
 
49
  demo.launch(
50
  server_name="0.0.0.0",
51
  server_port=int(os.environ.get("PORT", 7860)),
52
  )
53
 
 
54
  if __name__ == "__main__":
55
+ main()
check.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import joblib
2
+ import jax.numpy as jnp
3
+ from loading_model import generator
4
+ from inference import _build_model
5
+
6
+ _build_model()
7
+
8
+ # Load checkpoint
9
+ ck = joblib.load("weights/checkpoint.pkl")
10
+
11
+ print("=== CHECKPOINT variables ===")
12
+ for i, w in enumerate(ck["gen_trainable"]):
13
+ print(f" [{i:03d}] shape={str(w.shape):30s}")
14
+
15
+ print("\n=== MODEL variables ===")
16
+ for i, v in enumerate(generator.trainable_variables):
17
+ print(f" [{i:03d}] shape={str(v.shape):30s} name={v.name}")
inference.py CHANGED
@@ -1,7 +1,3 @@
1
- """
2
- StyleGAN v1 inference: load weights and generate images.
3
- Supports Keras .weights.h5 and optional state checkpoint (gen_state).
4
- """
5
  import os
6
  os.environ["KERAS_BACKEND"] = "jax"
7
 
@@ -9,106 +5,122 @@ import numpy as np
9
  import jax
10
  import jax.numpy as jnp
11
 
12
- # Import after backend set
13
  from loading_model import generator
14
  from configuration import LATENT_DIM, RESOLUTIONS
15
 
16
- # Default paths (override with env or put files in repo)
17
- WEIGHTS_DIR = os.environ.get("STYLEGAN_WEIGHTS_DIR", "weights")
18
- WEIGHTS_PATH = os.environ.get("STYLEGAN_WEIGHTS_PATH", os.path.join(WEIGHTS_DIR, "generator.weights.h5"))
19
- STATE_PATH = os.environ.get("STYLEGAN_STATE_PATH", os.path.join(WEIGHTS_DIR, "gen_state.pkl"))
20
 
21
- _gen_state = None
22
  _use_stateless = False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
 
24
 
25
  def _build_model():
26
- """Build generator with a dummy forward pass so weights can be loaded."""
27
- rng = jax.random.PRNGKey(0)
28
- dummy_z = jnp.zeros((1, LATENT_DIM))
29
- _ = generator(dummy_z, 1.0, rng)
 
 
 
 
30
 
31
 
32
  def load_weights(resolution=256):
33
- """
34
- Load generator weights from disk.
35
- Prefer WEIGHTS_PATH (Keras .weights.h5). If not found, try STATE_PATH (gen_state pickle).
36
- """
37
- global _gen_state, _use_stateless
38
  _build_model()
39
 
40
- if os.path.isfile(WEIGHTS_PATH):
41
- generator.load_weights(WEIGHTS_PATH)
 
42
  _use_stateless = False
43
- generator.current_resolution = min(resolution, max(RESOLUTIONS))
44
- if resolution not in RESOLUTIONS:
45
- generator.current_resolution = max(r for r in RESOLUTIONS if r <= resolution)
46
- return True
47
-
48
- try:
49
- import pickle
50
- if os.path.isfile(STATE_PATH):
51
- with open(STATE_PATH, "rb") as f:
52
- _gen_state = pickle.load(f)
53
- _use_stateless = True
54
- return True
55
- except Exception:
56
- pass
57
-
58
- return False
59
-
60
-
61
- def generate_images(n_images, resolution=256, seed=None):
62
- """
63
- Generate n_images fake images.
64
- Returns list of numpy arrays (H, W, 3) in [0, 255] uint8 for display.
65
- """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  if seed is None:
67
  seed = int(np.random.randint(0, 2**31))
68
  rng = jax.random.PRNGKey(seed)
69
-
70
  if _use_stateless and _gen_state is not None:
71
- return _generate_stateless(n_images, resolution, rng)
72
- return _generate_keras(n_images, resolution, rng)
73
 
74
 
75
- def _generate_keras(n_images, resolution, rng):
76
- res = min(resolution, max(RESOLUTIONS))
77
- res = max(r for r in RESOLUTIONS if r <= res)
78
- generator.current_resolution = res
79
-
80
  rng, z_key, noise_key = jax.random.split(rng, 3)
81
- z = jax.random.normal(z_key, (n_images, LATENT_DIM))
 
 
 
82
 
83
- out_call = generator(z, 1.0, noise_key)
84
- images = out_call[0] if isinstance(out_call, (list, tuple)) else out_call
85
- images = (np.array(images) + 1.0) / 2.0
86
- images = np.clip(images, 0.0, 1.0)
87
- out = []
88
- for i in range(n_images):
89
- img = (images[i] * 255).astype(np.uint8)
90
- out.append(img)
91
- return out
92
-
93
-
94
- def _generate_stateless(n_images, resolution, rng):
95
- gen_state = _gen_state
96
- res = min(resolution, max(RESOLUTIONS))
97
- res = max(r for r in RESOLUTIONS if r <= res)
98
- # If state was saved with a resolution, we use generator.current_resolution from state
99
- # Otherwise we'd need to store it in gen_state; for now use generator attribute
100
- generator.current_resolution = res
101
 
 
 
102
  rng, z_key, noise_key = jax.random.split(rng, 3)
103
  z = jax.random.normal(z_key, (n_images, LATENT_DIM))
104
-
105
- fake_images, _ = generator.stateless_call(
106
- gen_state["ema_trainable"],
107
- gen_state["non_trainable"],
108
  z,
109
- 1.0,
110
  noise_key,
111
  )
112
- fake_images = (np.array(fake_images) + 1.0) / 2.0
113
- fake_images = np.clip(fake_images, 0.0, 1.0)
114
- return [(fake_images[i] * 255).astype(np.uint8) for i in range(n_images)]
 
 
 
 
 
1
  import os
2
  os.environ["KERAS_BACKEND"] = "jax"
3
 
 
5
  import jax
6
  import jax.numpy as jnp
7
 
 
8
  from loading_model import generator
9
  from configuration import LATENT_DIM, RESOLUTIONS
10
 
11
+ WEIGHTS_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "weights")
12
+ WEIGHTS_H5 = os.path.join(WEIGHTS_DIR, "generator.weights.h5")
13
+ CHECKPOINT_PKL = os.path.join(WEIGHTS_DIR, "checkpoint.pkl")
 
14
 
15
+ _gen_state = None
16
  _use_stateless = False
17
+ _saved_alpha = 1.0
18
+
19
+ TARGET_RES = 256 # hardcoded β€” only generate at 256
20
+
21
+
22
+ def _postprocess(images: np.ndarray) -> list:
23
+ raw_min, raw_max = images.min(), images.max()
24
+ print(f"raw min={raw_min:.3f} max={raw_max:.3f}")
25
+ if raw_min >= -1.5 and raw_max <= 1.5:
26
+ images = (images + 1.0) / 2.0
27
+ images = np.clip(images, 0.0, 1.0)
28
+ return [images[i] for i in range(images.shape[0])]
29
+ else:
30
+ out = []
31
+ for i in range(images.shape[0]):
32
+ img = images[i].astype(np.float32)
33
+ img = (img - img.min()) / (img.max() - img.min() + 1e-8)
34
+ out.append(img)
35
+ return out
36
 
37
 
38
  def _build_model():
39
+ dummy_alpha = jnp.array(1.0)
40
+ dummy_rng = jax.random.PRNGKey(0)
41
+ dummy_z = jnp.zeros((1, LATENT_DIM))
42
+ for res in RESOLUTIONS:
43
+ generator.current_resolution = res
44
+ _ = generator(dummy_z, alpha=dummy_alpha, rng_key=dummy_rng)
45
+ generator.current_resolution = TARGET_RES
46
+ print(f"βœ… Model built β€” trainable: {len(generator.trainable_variables)} non-trainable: {len(generator.non_trainable_variables)}")
47
 
48
 
49
  def load_weights(resolution=256):
50
+ global _gen_state, _use_stateless, _saved_alpha
 
 
 
 
51
  _build_model()
52
 
53
+ if os.path.isfile(WEIGHTS_H5):
54
+ print(f"πŸ“‚ Loading Keras weights: {WEIGHTS_H5}")
55
+ generator.load_weights(WEIGHTS_H5)
56
  _use_stateless = False
57
+ print("βœ… Keras weights loaded.")
58
+
59
+ elif os.path.isfile(CHECKPOINT_PKL):
60
+ print(f"πŸ“‚ Loading checkpoint: {CHECKPOINT_PKL}")
61
+ import joblib
62
+ data = joblib.load(CHECKPOINT_PKL)
63
+ print(f" Keys: {list(data.keys())}")
64
+
65
+ gen_trainable = data["gen_trainable"]
66
+ gen_non_trainable = data.get("gen_non_trainable", [])
67
+ _saved_alpha = float(data.get("alpha", 1.0))
68
+
69
+ print(f" trainable={len(gen_trainable)} non_trainable={len(gen_non_trainable)} alpha={_saved_alpha:.4f}")
70
+
71
+ n_model = len(generator.trainable_variables)
72
+ if len(gen_trainable) != n_model:
73
+ raise ValueError(f"❌ Mismatch β€” checkpoint:{len(gen_trainable)} model:{n_model}")
74
+
75
+ n_non = len(generator.non_trainable_variables)
76
+ _gen_state = {
77
+ "ema_trainable": [jnp.asarray(t) for t in gen_trainable],
78
+ "non_trainable": (
79
+ [jnp.asarray(t) for t in gen_non_trainable[:n_non]]
80
+ if gen_non_trainable
81
+ else [jnp.asarray(v.value) for v in generator.non_trainable_variables]
82
+ ),
83
+ }
84
+ _use_stateless = True
85
+ print("βœ… Checkpoint loaded.")
86
+
87
+ else:
88
+ raise FileNotFoundError(f"❌ No weights found in: {WEIGHTS_DIR}")
89
+
90
+ generator.current_resolution = TARGET_RES
91
+ print(f"πŸ–ΌοΈ Resolution locked to: {TARGET_RES}")
92
+ return True
93
+
94
+
95
+ def generate_images(n_images, resolution=None, seed=None):
96
+ if not _use_stateless and _gen_state is None:
97
+ raise RuntimeError("❌ Call load_weights() first.")
98
  if seed is None:
99
  seed = int(np.random.randint(0, 2**31))
100
  rng = jax.random.PRNGKey(seed)
 
101
  if _use_stateless and _gen_state is not None:
102
+ return _generate_stateless(n_images, rng)
103
+ return _generate_keras(n_images, rng)
104
 
105
 
106
+ def _generate_keras(n_images, rng):
107
+ generator.current_resolution = TARGET_RES
 
 
 
108
  rng, z_key, noise_key = jax.random.split(rng, 3)
109
+ z = jax.random.normal(z_key, (n_images, LATENT_DIM))
110
+ out = generator(z, alpha=1.0, rng_key=noise_key)
111
+ images = out[0] if isinstance(out, (list, tuple)) else out
112
+ return _postprocess(np.array(images))
113
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
 
115
+ def _generate_stateless(n_images, rng):
116
+ generator.current_resolution = TARGET_RES
117
  rng, z_key, noise_key = jax.random.split(rng, 3)
118
  z = jax.random.normal(z_key, (n_images, LATENT_DIM))
119
+ images, _ = generator.stateless_call(
120
+ _gen_state["ema_trainable"],
121
+ _gen_state["non_trainable"],
 
122
  z,
123
+ jnp.array(_saved_alpha),
124
  noise_key,
125
  )
126
+ return _postprocess(np.array(images))
 
 
requirements.txt CHANGED
@@ -4,3 +4,4 @@ keras>=3.0.0
4
  jax>=0.4.0
5
  jaxlib>=0.4.0
6
  numpy>=1.24.0,<2.0.0
 
 
4
  jax>=0.4.0
5
  jaxlib>=0.4.0
6
  numpy>=1.24.0,<2.0.0
7
+ joblib>=1.0.0