vedaco commited on
Commit
7fed78f
·
verified ·
1 Parent(s): 3304074

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +231 -0
app.py ADDED
@@ -0,0 +1,231 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ AKASHA - Gradio Demo for Hugging Face Spaces
3
+ https://huggingface.co/spaces/vedaco/AKASHA
4
+ """
5
+
6
+ import gradio as gr
7
+ import tensorflow as tf
8
+ import numpy as np
9
+ import os
10
+ import json
11
+ from PIL import Image
12
+
13
+ os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3"
14
+
15
+
16
+ # ── Load model ──────────────────────────────────────────────
17
+
18
+ def load_model():
19
+ config_path = "config.json"
20
+ if os.path.exists(config_path):
21
+ with open(config_path, "r") as f:
22
+ config = json.load(f)
23
+ else:
24
+ from akasha.utils import create_default_config
25
+ config = create_default_config()
26
+
27
+ from akasha.tokenizer import VQVAE
28
+ from akasha.model import AKASHAModel
29
+
30
+ # Build VQVAE
31
+ vqvae = VQVAE(config)
32
+ img_size = config["model"]["tokenizer"]["image_size"]
33
+ dummy = tf.zeros([1, img_size, img_size, 3])
34
+ vqvae(dummy)
35
+
36
+ vqvae_path = "vqvae.weights.h5"
37
+ if os.path.exists(vqvae_path):
38
+ vqvae.load_weights(vqvae_path)
39
+ print("✅ VQVAE weights loaded")
40
+ else:
41
+ print("⚠️ VQVAE weights not found — using random weights (demo mode)")
42
+
43
+ # Build Transformer
44
+ model = AKASHAModel(config)
45
+ model.set_vqvae(vqvae)
46
+
47
+ bos = config["model"]["tokenizer"]["num_tokens"]
48
+ dummy_tok = tf.cast(tf.fill([1, 10], bos), tf.int32)
49
+ model.transformer(dummy_tok)
50
+
51
+ transformer_path = "transformer.weights.h5"
52
+ if os.path.exists(transformer_path):
53
+ model.transformer.load_weights(transformer_path)
54
+ print("✅ Transformer weights loaded")
55
+ else:
56
+ print("⚠️ Transformer weights not found — using random weights (demo mode)")
57
+
58
+ return model, config
59
+
60
+
61
+ print("🚀 Loading AKASHA model...")
62
+ try:
63
+ model, config = load_model()
64
+ MODEL_LOADED = True
65
+ print("✅ AKASHA ready!")
66
+ except Exception as e:
67
+ print(f"❌ Failed to load model: {e}")
68
+ MODEL_LOADED = False
69
+ model, config = None, None
70
+
71
+
72
+ # ── Generation function ─────────────────────────────────────
73
+
74
+ def generate_images(num_images, temperature, top_k, top_p, seed, progress=gr.Progress()):
75
+ if not MODEL_LOADED:
76
+ return None, "❌ Model not loaded. Check logs."
77
+
78
+ if seed >= 0:
79
+ tf.random.set_seed(int(seed))
80
+ np.random.seed(int(seed))
81
+
82
+ num_images = int(num_images)
83
+ top_k = int(top_k)
84
+
85
+ def progress_cb(step, total):
86
+ progress(step / total, desc=f"Token {step}/{total}")
87
+
88
+ try:
89
+ images, tokens = model.generate(
90
+ num_images=num_images,
91
+ temperature=temperature,
92
+ top_k=top_k,
93
+ top_p=top_p,
94
+ callback=progress_cb,
95
+ )
96
+
97
+ pil_images = []
98
+ for i in range(num_images):
99
+ img = images[i].numpy()
100
+ img = (img * 255).clip(0, 255).astype(np.uint8)
101
+ pil_images.append(Image.fromarray(img))
102
+
103
+ info = (
104
+ f"✅ Generated {num_images} image(s) | "
105
+ f"temp={temperature} | top_k={top_k} | top_p={top_p}"
106
+ )
107
+ if seed >= 0:
108
+ info += f" | seed={int(seed)}"
109
+ return pil_images, info
110
+
111
+ except Exception as e:
112
+ return None, f"❌ Generation failed: {str(e)}"
113
+
114
+
115
+ # ── Reconstruction function ─────────────────────────────────
116
+
117
+ def reconstruct_image(input_image, progress=gr.Progress()):
118
+ if not MODEL_LOADED:
119
+ return None, "❌ Model not loaded."
120
+ if input_image is None:
121
+ return None, "Please upload an image."
122
+
123
+ try:
124
+ img_size = config["model"]["tokenizer"]["image_size"]
125
+ img = tf.image.resize(input_image, [img_size, img_size])
126
+ img = tf.cast(img, tf.float32) / 255.0
127
+ img = tf.expand_dims(img, 0)
128
+
129
+ reconstructed, tokens, vq_loss = model.vqvae(img, training=False)
130
+
131
+ recon = reconstructed[0].numpy()
132
+ recon = (recon * 255).clip(0, 255).astype(np.uint8)
133
+
134
+ n_tokens = int(tokens.shape[1] * tokens.shape[2])
135
+ unique = len(np.unique(tokens.numpy()))
136
+ codebook_size = config["model"]["tokenizer"]["num_tokens"]
137
+ info = (
138
+ f"Tokens: {n_tokens} | "
139
+ f"Unique codes: {unique}/{codebook_size} | "
140
+ f"VQ Loss: {float(vq_loss):.4f}"
141
+ )
142
+ return Image.fromarray(recon), info
143
+
144
+ except Exception as e:
145
+ return None, f"❌ Reconstruction failed: {str(e)}"
146
+
147
+
148
+ # ── Build UI ────────────────────────────────────────────────
149
+
150
+ css = """
151
+ .gradio-container { max-width: 1000px !important; }
152
+ h1 { text-align: center; }
153
+ """
154
+
155
+ with gr.Blocks(title="AKASHA — Image Generation", theme=gr.themes.Soft(), css=css) as demo:
156
+
157
+ gr.Markdown("""
158
+ # 🎨 AKASHA — Autoregressive Image Generation
159
+ Generate images **token-by-token** using a transformer that predicts the next image token.
160
+
161
+ Built with **TensorFlow** · Trained on **Lightning AI** · by [vedaco](https://huggingface.co/vedaco)
162
+ """)
163
+
164
+ with gr.Tabs():
165
+
166
+ # ── Tab: Generate ────────────────────────────────────
167
+ with gr.TabItem("🖼️ Generate"):
168
+ with gr.Row():
169
+ with gr.Column(scale=1):
170
+ num_images = gr.Slider(1, 16, value=4, step=1, label="Number of images")
171
+ temperature = gr.Slider(0.1, 2.0, value=0.9, step=0.05, label="Temperature",
172
+ info="Higher → more diverse")
173
+ top_k = gr.Slider(1, 1024, value=100, step=1, label="Top-K")
174
+ top_p = gr.Slider(0.1, 1.0, value=0.95, step=0.05, label="Top-P")
175
+ seed = gr.Number(value=-1, label="Seed (-1 = random)", precision=0)
176
+ gen_btn = gr.Button("🎨 Generate", variant="primary", size="lg")
177
+
178
+ with gr.Column(scale=2):
179
+ gallery = gr.Gallery(label="Generated Images", columns=2, height=512)
180
+ gen_info = gr.Textbox(label="Info", interactive=False)
181
+
182
+ gen_btn.click(
183
+ generate_images,
184
+ inputs=[num_images, temperature, top_k, top_p, seed],
185
+ outputs=[gallery, gen_info],
186
+ )
187
+
188
+ # ── Tab: Reconstruct ─────────────────────────────────
189
+ with gr.TabItem("🔄 Reconstruct (VQVAE)"):
190
+ gr.Markdown("Upload an image to see how the VQVAE tokenizer encodes & decodes it.")
191
+ with gr.Row():
192
+ input_img = gr.Image(label="Input", type="numpy")
193
+ output_img = gr.Image(label="Reconstructed")
194
+ recon_info = gr.Textbox(label="Info", interactive=False)
195
+ recon_btn = gr.Button("🔄 Reconstruct", variant="primary")
196
+ recon_btn.click(reconstruct_image, inputs=[input_img], outputs=[output_img, recon_info])
197
+
198
+ # ── Tab: About ────────────────────────────────────────
199
+ with gr.TabItem("ℹ️ About"):
200
+ if config:
201
+ tok = config["model"]["tokenizer"]
202
+ trans = config["model"]["transformer"]
203
+ grid = tok["image_size"] // tok["patch_size"]
204
+ gr.Markdown(f"""
205
+ ## Architecture
206
+
207
+ | Component | Value |
208
+ |-----------|-------|
209
+ | Image size | {tok['image_size']}×{tok['image_size']} |
210
+ | Grid | {grid}×{grid} = {grid*grid} tokens |
211
+ | Codebook | {tok['num_tokens']} codes × {tok['codebook_dim']}d |
212
+ | Transformer | {trans['num_layers']} layers, {trans['d_model']}d, {trans['num_heads']} heads |
213
+ | FFN dim | {trans['d_ff']} |
214
+ | Position encoding | RoPE |
215
+ | Activation | SwiGLU |
216
+ | Normalization | RMSNorm |
217
+
218
+ ## How it works
219
+
220
+ 1. **VQVAE Encoder** compresses a 256×256 image into a {grid}×{grid} grid of discrete tokens
221
+ 2. The grid is flattened into a sequence of **{grid*grid} tokens**
222
+ 3. A **causal transformer** is trained to predict the next token
223
+ 4. At generation time, tokens are sampled one-by-one and decoded with the **VQVAE Decoder**
224
+ """)
225
+ else:
226
+ gr.Markdown("Config not available.")
227
+
228
+ gr.Markdown("---\nMade with ❤️ by [vedaco](https://huggingface.co/vedaco) · TensorFlow · Lightning AI")
229
+
230
+ if __name__ == "__main__":
231
+ demo.launch(server_name="0.0.0.0", server_port=7860)