ritikraj2425 commited on
Commit
deb87d4
·
1 Parent(s): 3fa3abf

Testing minimal interface

Browse files
Files changed (1) hide show
  1. app.py +45 -283
app.py CHANGED
@@ -3,17 +3,16 @@ import torch
3
  import torch.nn.functional as F
4
  import time
5
  from tokenizers import Tokenizer
6
- import json
7
  from train2 import MaskedDiffusionModel
8
 
9
  MAX_SEQ_LENGTH = 64
10
 
11
  def load_model_and_tokenizer():
12
  device = torch.device("cpu")
 
13
  tokenizer = Tokenizer.from_file("subword_tokenizer2.json")
14
  vocab = tokenizer.get_vocab()
15
- id2word = {int(v): k for k, v in vocab.items()}
16
-
17
  model = MaskedDiffusionModel(
18
  vocab_size=len(vocab),
19
  d_model=256,
@@ -23,17 +22,20 @@ def load_model_and_tokenizer():
23
  dropout=0.2
24
  ).to(device)
25
 
26
- # Load weights (removing weights_only for better compatibility)
27
- state_dict = torch.load("diffusion_model_between.pth", map_location=device)
28
- model.load_state_dict(state_dict)
 
 
 
 
29
  model.eval()
30
- return model, tokenizer, id2word, device
31
 
32
- model, tokenizer, id2word, device = load_model_and_tokenizer()
33
 
34
  def decode_with_masks(tensor, is_final=False):
35
  eos_id = tokenizer.token_to_id("[EOS]")
36
- # Only truncate at EOS on the very final step, otherwise the text jumps around during refinement!
37
  if is_final:
38
  eos_indices = (tensor == eos_id).nonzero(as_tuple=True)[0]
39
  if len(eos_indices) > 0:
@@ -45,40 +47,27 @@ def decode_with_masks(tensor, is_final=False):
45
  filtered_ids = [tid for tid in tensor.tolist() if tid not in special_ids]
46
  if not filtered_ids: return ""
47
 
48
- # Decode WITHOUT skipping special tokens so [MASK] is visible
49
  text = tokenizer.decode(filtered_ids, skip_special_tokens=False).strip()
50
-
51
- # Stylize the raw [MASK] token
52
  text = text.replace("[MASK]", "█")
53
 
54
- # Text formatting correction
55
  for p in [".", ",", "?", "!", "'", ":"]:
56
  text = text.replace(f" {p}", p)
57
 
58
  return text.strip()
59
 
60
- def generate_step_by_step(history):
61
  try:
62
- if not history:
63
- return []
64
-
65
- prompt = history[-1][0]
66
- print(f"Generating for prompt: {prompt}")
67
-
68
- steps = 20
69
- temp = 0.2
70
  top_k = 10
71
 
72
  bos_id = tokenizer.token_to_id("[BOS]")
73
  eos_id = tokenizer.token_to_id("[EOS]")
74
  mask_id = tokenizer.token_to_id("[MASK]")
75
  pad_id = tokenizer.token_to_id("[PAD]")
76
- unk_id = tokenizer.token_to_id("[UNK]")
77
- special_ids = {bos_id, eos_id, mask_id, pad_id, unk_id}
78
-
79
- formatted_prompt = f"user: {prompt.lower().strip()} bot:"
80
  input_ids = tokenizer.encode(formatted_prompt).ids
81
-
82
  max_resp = min(40, MAX_SEQ_LENGTH - len(input_ids) - 2)
83
 
84
  sequence = [bos_id] + input_ids + [mask_id] * max_resp + [eos_id]
@@ -91,292 +80,65 @@ def generate_step_by_step(history):
91
  num_masks = len(mask_indices)
92
 
93
  running_confidence = torch.zeros(num_masks, device=device)
94
-
95
- def get_output(seq_tensor, is_final=False):
96
- response_ids = seq_tensor[0][response_start:response_end]
97
- return decode_with_masks(response_ids, is_final)
98
-
99
- out_text = get_output(seq_tensor, is_final=False)
100
- history[-1][1] = out_text
101
- yield history
102
-
103
  current_seq = seq_tensor.squeeze(0).clone()
104
 
105
- # Pre-calculate penalty indices once
106
- vocab_size = model.fc_out.out_features
107
-
108
  for step in range(1, steps + 1):
109
  t_val = max(1.0 - step / steps, 0.05)
110
  t = torch.tensor([t_val], device=device)
111
- pad_mask = (seq_tensor == pad_id)
112
 
113
  with torch.no_grad():
114
- logits = model(seq_tensor, t, src_key_padding_mask=pad_mask)
115
-
116
  response_logits = logits[0, mask_indices]
117
 
118
- # Optimized Vectorized Repetition Penalty
119
  if step > 1:
120
- prev_pred = current_seq[mask_indices]
121
- # Get counts only for tokens present in context to avoid giant loops
122
- unique_tokens, counts = torch.unique(prev_pred, return_counts=True)
123
  for i, tok_id in enumerate(unique_tokens):
124
  t_id = tok_id.item()
125
- if t_id not in special_ids and counts[i] > 1:
126
- penalty = 5.0 ** (counts[i].item() - 1)
127
- response_logits[:, t_id] = torch.where(
128
- response_logits[:, t_id] < 0,
129
- response_logits[:, t_id] * penalty,
130
- response_logits[:, t_id] / penalty
131
- )
132
 
133
  if top_k > 0:
134
- top_k_vals, _ = torch.topk(response_logits, top_k, dim=-1)
135
- min_top_k = top_k_vals[:, -1].unsqueeze(-1)
136
- response_logits = response_logits.masked_fill(response_logits < min_top_k, float('-inf'))
137
-
138
- probs = F.softmax(response_logits / max(temp, 1e-6), dim=-1)
139
 
140
- # Nan protection and sampling
141
- if torch.isnan(probs).any():
142
- print("WARNING: NaNs detected in probabilities, falling back to uniform")
143
- probs = torch.ones_like(probs) / probs.size(-1)
144
-
145
  if step == steps:
146
  predicted = torch.argmax(probs, dim=-1)
147
  else:
148
- try:
149
- predicted = torch.multinomial(probs, 1).squeeze(-1)
150
- except RuntimeError as e:
151
- print(f"Sampling error: {e}")
152
- predicted = torch.argmax(probs, dim=-1) # fallback to greedy
153
-
154
- true_probs = F.softmax(response_logits, dim=-1)
155
- confidences = true_probs[torch.arange(num_masks), predicted]
156
 
 
157
  running_confidence = 0.7 * running_confidence + 0.3 * confidences
158
 
159
  for i, idx in enumerate(mask_indices):
160
  current_seq[idx] = predicted[i]
161
 
162
  if step < steps:
163
- target_revealed = int(num_masks * step / steps)
164
- num_remask = num_masks - target_revealed
165
- if num_remask > 0:
166
- _, low_idx = torch.topk(running_confidence, k=num_remask, largest=False)
167
  for li in low_idx:
168
  current_seq[mask_indices[li]] = mask_id
169
-
170
  seq_tensor = current_seq.unsqueeze(0)
171
- out_text = get_output(seq_tensor, is_final=(step == steps))
 
172
 
173
- history[-1][1] = out_text
174
- yield history
175
- time.sleep(0.02)
176
  except Exception as e:
177
- import traceback
178
- error_msg = f"Inference Error: {str(e)}"
179
- print(error_msg)
180
- print(traceback.format_exc())
181
- history[-1][1] = error_msg
182
- yield history
183
-
184
-
185
- custom_css = """
186
- @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;800&family=JetBrains+Mono&display=swap');
187
-
188
- body, .gradio-container {
189
- background-color: #030509 !important;
190
- font-family: 'Inter', sans-serif !important;
191
- color: #ffffff !important;
192
- min-height: 100vh;
193
- margin: 0;
194
- }
195
-
196
- @keyframes float-glow {
197
- 0% { transform: scale(1) translate(0, 0); opacity: 0.5; }
198
- 50% { transform: scale(1.2) translate(-20px, 20px); opacity: 0.8; }
199
- 100% { transform: scale(1) translate(0, 0); opacity: 0.5; }
200
- }
201
-
202
- .bg-mesh-1, .bg-mesh-2 {
203
- position: fixed;
204
- border-radius: 50%;
205
- filter: blur(100px);
206
- z-index: -1;
207
- pointer-events: none;
208
- }
209
- .bg-mesh-1 {
210
- width: 50vw; height: 50vw;
211
- background: radial-gradient(circle, rgba(100, 150, 255, 0.4) 0%, transparent 60%);
212
- top: -10vw; left: -10vw;
213
- animation: float-glow 20s ease-in-out infinite;
214
- }
215
- .bg-mesh-2 {
216
- width: 60vw; height: 60vw;
217
- background: radial-gradient(circle, rgba(50, 100, 250, 0.3) 0%, transparent 60%);
218
- bottom: -20vw; right: -20vw;
219
- animation: float-glow 25s ease-in-out infinite reverse;
220
- }
221
-
222
- .hero-container {
223
- padding: 6vh 5vw 2vh 5vw;
224
- z-index: 10;
225
- }
226
- .hero-brand {
227
- display: inline-flex;
228
- align-items: center;
229
- background: rgba(255, 255, 255, 0.1);
230
- padding: 8px 16px;
231
- border-radius: 20px;
232
- font-size: 0.8rem;
233
- font-weight: 600;
234
- letter-spacing: 1px;
235
- color: #ffffff;
236
- margin-bottom: 2rem;
237
- backdrop-filter: blur(10px);
238
- border: 1px solid rgba(255, 255, 255, 0.15);
239
- }
240
- .hero-title {
241
- font-size: clamp(3rem, 6vw, 6rem);
242
- font-weight: 800;
243
- line-height: 1.0;
244
- letter-spacing: -0.04em;
245
- color: #fff;
246
- margin: 0 0 1rem 0;
247
- }
248
- .hero-description {
249
- font-size: clamp(1rem, 1.2vw, 1.1rem);
250
- color: #9ba3af;
251
- font-weight: 400;
252
- line-height: 1.6;
253
- max-width: 900px;
254
- margin-bottom: 2rem;
255
- background: rgba(10, 15, 25, 0.4);
256
- border-radius: 12px;
257
- backdrop-filter: blur(10px);
258
- }
259
- .app-container {
260
- padding: 0 5vw 10vh 5vw;
261
- z-index: 10;
262
- }
263
- .chatbot-container {
264
- border-radius: 24px !important;
265
- background: rgba(15, 20, 25, 0.6) !important;
266
- backdrop-filter: blur(25px) !important;
267
- border: 1px solid rgba(255, 255, 255, 0.08) !important;
268
- box-shadow: 0 20px 50px rgba(0,0,0,0.5), inset 0 1px 0 rgba(255,255,255,0.1) !important;
269
- }
270
- .message-wrap .user {
271
- background: linear-gradient(135deg, rgba(255,255,255,0.1), rgba(255,255,255,0.05)) !important;
272
- border: 1px solid rgba(255, 255, 255, 0.1) !important;
273
- box-shadow: 0 4px 15px rgba(0,0,0,0.2) !important;
274
- }
275
- .message-wrap .bot {
276
- background: transparent !important;
277
- border: none !important;
278
- }
279
-
280
- /* Fancy Input Row */
281
- #input-container {
282
- background: rgba(20, 25, 30, 0.7);
283
- backdrop-filter: blur(20px);
284
- border-radius: 24px;
285
- border: 1px solid rgba(255, 255, 255, 0.15);
286
- padding: 12px 12px 12px 24px;
287
- margin-top: 20px;
288
- box-shadow: 0 10px 30px rgba(0,0,0,0.3);
289
- transition: all 0.3s ease;
290
- }
291
- #input-container:focus-within {
292
- border-color: rgba(100, 200, 255, 0.5);
293
- box-shadow: 0 0 30px rgba(100, 200, 255, 0.15);
294
- }
295
- #textbox textarea {
296
- font-family: 'Inter', sans-serif !important;
297
- font-size: 1.1rem !important;
298
- color: white !important;
299
- padding: 5px 0 0 0 !important;
300
- }
301
- #textbox textarea::placeholder {
302
- color: rgba(255,255,255,0.4) !important;
303
- }
304
- #submit-btn {
305
- color: #000 !important;
306
- border-radius: 16px !important;
307
- font-weight: 700 !important;
308
- border: none !important;
309
- box-shadow: 0 5px 15px rgba(0, 242, 254, 0.3) !important;
310
- transition: all 0.3s ease !important;
311
- }
312
-
313
- /* Examples Styling */
314
- .gr-examples {
315
- margin-top: 25px !important;
316
- }
317
- .gr-examples h3, .gr-examples .label {
318
- color: rgba(255,255,255,0.6) !important;
319
- font-weight: 500 !important;
320
- font-size: 0.9rem !important;
321
- }
322
- .gr-examples .gallery-item {
323
- background: rgba(255,255,255,0.05) !important;
324
- border: 1px solid rgba(255,255,255,0.1) !important;
325
- color: white !important;
326
- border-radius: 12px !important;
327
- transition: background 0.3s !important;
328
- }
329
- .gr-examples .gallery-item:hover {
330
- background: rgba(255,255,255,0.15) !important;
331
- }
332
- """
333
-
334
- with gr.Blocks(css=custom_css, theme=gr.themes.Base()) as demo:
335
- gr.HTML("""
336
- <div class="bg-mesh-1"></div>
337
- <div class="bg-mesh-2"></div>
338
- """)
339
-
340
- with gr.Column(elem_classes="hero-container"):
341
- gr.HTML("""
342
-
343
- <h1 class="hero-title">PersonaChat MDLM</h1>
344
- <div class="hero-description">
345
- <strong>Architecture:</strong> 17 Million Parameter Masked Discrete Diffusion Language Model<br/><br/>
346
- Unlike traditional autoregressive models (like ChatGPT) that sequentially guess words one-by-one, this model harnesses <strong>Parallel Denoising Generation</strong>. It maps out the entire sequence's layout instantly, then uses progressive <em>Timestep Adaptive Layer Normalization (AdaLN)</em> and <em>EMA Confidence Trajectory</em> to morph static noise into coherent sentences.<br/><br/>
347
- <strong>Trained on:</strong> <code>bavard/personachat_truecased</code> dataset.
348
- </div>
349
- <div class="hero-brand">
350
- DIFFUSION MODEL
351
- </div>
352
- """)
353
-
354
- with gr.Column(elem_classes="app-container"):
355
- chatbot = gr.Chatbot(elem_classes="chatbot-container", height=450, show_label=False)
356
-
357
- with gr.Row(elem_id="input-container"):
358
- msg = gr.Textbox(placeholder="Ask me something about myself...", show_label=False, elem_id="textbox", scale=8, container=False)
359
- submit = gr.Button("Query", elem_id="submit-btn", scale=1)
360
-
361
- gr.Examples(
362
- examples=[
363
- "Hi, how are you doing today?",
364
- "How are you doing?",
365
- "Do you have any pets?",
366
- "What kind of music do you like?"
367
- ],
368
- inputs=msg
369
- )
370
-
371
- def user(user_message, history):
372
- return "", history + [[user_message, None]]
373
-
374
- msg.submit(user, [msg, chatbot], [msg, chatbot], queue=False).then(
375
- generate_step_by_step, chatbot, chatbot
376
- )
377
- submit.click(user, [msg, chatbot], [msg, chatbot], queue=False).then(
378
- generate_step_by_step, chatbot, chatbot
379
- )
380
 
381
  if __name__ == "__main__":
382
  demo.launch()
 
3
  import torch.nn.functional as F
4
  import time
5
  from tokenizers import Tokenizer
 
6
  from train2 import MaskedDiffusionModel
7
 
8
  MAX_SEQ_LENGTH = 64
9
 
10
  def load_model_and_tokenizer():
11
  device = torch.device("cpu")
12
+ # Using the exact same architecture as training
13
  tokenizer = Tokenizer.from_file("subword_tokenizer2.json")
14
  vocab = tokenizer.get_vocab()
15
+
 
16
  model = MaskedDiffusionModel(
17
  vocab_size=len(vocab),
18
  d_model=256,
 
22
  dropout=0.2
23
  ).to(device)
24
 
25
+ # Simplified load
26
+ try:
27
+ state_dict = torch.load("diffusion_model_between.pth", map_location=device)
28
+ model.load_state_dict(state_dict)
29
+ except Exception as e:
30
+ print(f"FAILED TO LOAD MODEL: {e}")
31
+
32
  model.eval()
33
+ return model, tokenizer, device
34
 
35
+ model, tokenizer, device = load_model_and_tokenizer()
36
 
37
  def decode_with_masks(tensor, is_final=False):
38
  eos_id = tokenizer.token_to_id("[EOS]")
 
39
  if is_final:
40
  eos_indices = (tensor == eos_id).nonzero(as_tuple=True)[0]
41
  if len(eos_indices) > 0:
 
47
  filtered_ids = [tid for tid in tensor.tolist() if tid not in special_ids]
48
  if not filtered_ids: return ""
49
 
 
50
  text = tokenizer.decode(filtered_ids, skip_special_tokens=False).strip()
 
 
51
  text = text.replace("[MASK]", "█")
52
 
 
53
  for p in [".", ",", "?", "!", "'", ":"]:
54
  text = text.replace(f" {p}", p)
55
 
56
  return text.strip()
57
 
58
+ def predict(message, history):
59
  try:
60
+ steps = 15
61
+ temp = 0.3
 
 
 
 
 
 
62
  top_k = 10
63
 
64
  bos_id = tokenizer.token_to_id("[BOS]")
65
  eos_id = tokenizer.token_to_id("[EOS]")
66
  mask_id = tokenizer.token_to_id("[MASK]")
67
  pad_id = tokenizer.token_to_id("[PAD]")
68
+
69
+ formatted_prompt = f"user: {message.lower().strip()} bot:"
 
 
70
  input_ids = tokenizer.encode(formatted_prompt).ids
 
71
  max_resp = min(40, MAX_SEQ_LENGTH - len(input_ids) - 2)
72
 
73
  sequence = [bos_id] + input_ids + [mask_id] * max_resp + [eos_id]
 
80
  num_masks = len(mask_indices)
81
 
82
  running_confidence = torch.zeros(num_masks, device=device)
 
 
 
 
 
 
 
 
 
83
  current_seq = seq_tensor.squeeze(0).clone()
84
 
85
+ output_text = ""
 
 
86
  for step in range(1, steps + 1):
87
  t_val = max(1.0 - step / steps, 0.05)
88
  t = torch.tensor([t_val], device=device)
 
89
 
90
  with torch.no_grad():
91
+ logits = model(seq_tensor, t, src_key_padding_mask=(seq_tensor == pad_id))
92
+
93
  response_logits = logits[0, mask_indices]
94
 
95
+ # Simple Repetition Penalty
96
  if step > 1:
97
+ unique_tokens, counts = torch.unique(current_seq[mask_indices], return_counts=True)
 
 
98
  for i, tok_id in enumerate(unique_tokens):
99
  t_id = tok_id.item()
100
+ if t_id not in [bos_id, eos_id, mask_id, pad_id] and counts[i] > 1:
101
+ response_logits[:, t_id] /= 2.0
 
 
 
 
 
102
 
103
  if top_k > 0:
104
+ v, _ = torch.topk(response_logits, top_k)
105
+ response_logits[response_logits < v[:, -1].unsqueeze(-1)] = -float('Inf')
106
+
107
+ probs = F.softmax(response_logits / temp, dim=-1)
 
108
 
 
 
 
 
 
109
  if step == steps:
110
  predicted = torch.argmax(probs, dim=-1)
111
  else:
112
+ predicted = torch.multinomial(probs, 1).squeeze(-1)
 
 
 
 
 
 
 
113
 
114
+ confidences = torch.gather(F.softmax(response_logits, dim=-1), 1, predicted.unsqueeze(-1)).squeeze(-1)
115
  running_confidence = 0.7 * running_confidence + 0.3 * confidences
116
 
117
  for i, idx in enumerate(mask_indices):
118
  current_seq[idx] = predicted[i]
119
 
120
  if step < steps:
121
+ target_reveal = int(num_masks * step / steps)
122
+ remask_count = num_masks - target_reveal
123
+ if remask_count > 0:
124
+ _, low_idx = torch.topk(running_confidence, k=remask_count, largest=False)
125
  for li in low_idx:
126
  current_seq[mask_indices[li]] = mask_id
127
+
128
  seq_tensor = current_seq.unsqueeze(0)
129
+ output_text = decode_with_masks(current_seq[response_start:response_end], is_final=(step == steps))
130
+ yield output_text
131
 
 
 
 
132
  except Exception as e:
133
+ yield f"Error: {str(e)}"
134
+
135
+ demo = gr.ChatInterface(
136
+ predict,
137
+ title="PersonaChat MDLM",
138
+ description="Minimal diagnostic interface. If this works, the problem was the CSS/UI complexity.",
139
+ examples=["Hi, how are you?", "What are your hobbies?", "Do you have any pets?"],
140
+ theme="soft"
141
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
142
 
143
  if __name__ == "__main__":
144
  demo.launch()