maxsn2200 commited on
Commit
663c79b
·
verified ·
1 Parent(s): a1bc931

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +57 -14
app.py CHANGED
@@ -24,17 +24,51 @@ try:
24
  weights_loaded = True
25
  print("Weights loaded successfully!")
26
  except FileNotFoundError:
27
- print("Warning: model_weights.npz not found. App will run in warning mode.")
28
  except Exception as e:
29
  print(f"Warning: error loading weights: {e}")
30
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  # 3. Predict function
32
  def predict(input_image):
33
  if not weights_loaded:
34
- return {"Error: please upload 'model_weights.npz' to your Space files": 1.0}
35
 
36
  if input_image is None:
37
- return "No image drawn"
38
 
39
  if isinstance(input_image, dict):
40
  img = input_image['composite']
@@ -82,31 +116,40 @@ def predict(input_image):
82
  canvas.paste(resized, (offset_x, offset_y))
83
  arr = np.array(canvas)
84
 
85
- # Normalize
86
  x = (arr / 255.0) - 0.5
87
  x = x[np.newaxis, :, :] # (1, 28, 28)
88
 
89
- # Run forward pass
90
- out1 = conv.forward(x)
91
- out2 = gelu.forward(out1)
92
- out3 = pool.forward(out2)
93
- out4 = flatten.forward(out3[np.newaxis, :, :, :])
94
- logits = dense.forward(out4)[0]
 
95
 
96
  # Softmax probabilities
97
  probs = np.exp(logits - np.max(logits))
98
  probs /= np.sum(probs)
99
 
100
- # Return dictionary of classes and probabilities
101
- return {str(i): float(probs[i]) for i in range(10)}
 
 
 
 
 
102
 
103
  # Gradio Interface layout
104
  demo = gr.Interface(
105
  fn=predict,
106
  inputs=gr.Sketchpad(type="pil", image_mode="L"),
107
- outputs=gr.Label(num_top_classes=3),
 
 
 
 
108
  title="CNN from Scratch - Digit Classifier",
109
- description="Draw a digit in the box to test our scratch-built NumPy model!"
110
  )
111
 
112
  if __name__ == "__main__":
 
24
  weights_loaded = True
25
  print("Weights loaded successfully!")
26
  except FileNotFoundError:
27
+ print("Warning: model_weights.npz not found.")
28
  except Exception as e:
29
  print(f"Warning: error loading weights: {e}")
30
 
31
+ # Helper to stitch feature maps into a nice grid
32
+ def make_grid(feature_maps, cols=4):
33
+ n, h, w = feature_maps.shape
34
+ rows = (n + cols - 1) // cols
35
+
36
+ # Pad borders between filters so they look separate
37
+ padding = 2
38
+ grid_h = rows * h + (rows - 1) * padding
39
+ grid_w = cols * w + (cols - 1) * padding
40
+ grid = np.zeros((grid_h, grid_w), dtype=np.uint8)
41
+
42
+ for idx in range(n):
43
+ r = idx // cols
44
+ c = idx % cols
45
+
46
+ f_map = feature_maps[idx]
47
+ f_min, f_max = f_map.min(), f_map.max()
48
+ # Normalize to [0, 255] for image display
49
+ if f_max > f_min:
50
+ f_map = 255.0 * (f_map - f_min) / (f_max - f_min)
51
+ else:
52
+ f_map = f_map * 0
53
+
54
+ f_map = f_map.astype(np.uint8)
55
+
56
+ y_start = r * (h + padding)
57
+ x_start = c * (w + padding)
58
+ grid[y_start:y_start+h, x_start:x_start+w] = f_map
59
+
60
+ img = Image.fromarray(grid)
61
+ # Scale up using nearest-neighbor to keep pixels clean and sharp
62
+ img = img.resize((grid_w * 12, grid_h * 12), Image.Resampling.NEAREST)
63
+ return img
64
+
65
  # 3. Predict function
66
  def predict(input_image):
67
  if not weights_loaded:
68
+ return {"Error: please upload 'model_weights.npz'": 1.0}, None, None
69
 
70
  if input_image is None:
71
+ return "No image drawn", None, None
72
 
73
  if isinstance(input_image, dict):
74
  img = input_image['composite']
 
116
  canvas.paste(resized, (offset_x, offset_y))
117
  arr = np.array(canvas)
118
 
 
119
  x = (arr / 255.0) - 0.5
120
  x = x[np.newaxis, :, :] # (1, 28, 28)
121
 
122
+ # Forward pass and record intermediate activations
123
+ out_conv = conv.forward(x)
124
+ out_gelu = gelu.forward(out_conv)
125
+ out_pool = pool.forward(out_gelu)
126
+
127
+ out_flat = flatten.forward(out_pool[np.newaxis, :, :, :])
128
+ logits = dense.forward(out_flat)[0]
129
 
130
  # Softmax probabilities
131
  probs = np.exp(logits - np.max(logits))
132
  probs /= np.sum(probs)
133
 
134
+ # Generate feature map grids for visualization
135
+ conv_grid = make_grid(out_conv)
136
+ pool_grid = make_grid(out_pool)
137
+
138
+ # Return dictionary of classes, plus the two grids
139
+ class_probs = {str(i): float(probs[i]) for i in range(10)}
140
+ return class_probs, conv_grid, pool_grid
141
 
142
  # Gradio Interface layout
143
  demo = gr.Interface(
144
  fn=predict,
145
  inputs=gr.Sketchpad(type="pil", image_mode="L"),
146
+ outputs=[
147
+ gr.Label(num_top_classes=3, label="Prediction"),
148
+ gr.Image(label="Layer 1: Convolutional Activations (12 Filters)", type="pil"),
149
+ gr.Image(label="Layer 2: Max Pooling Outputs (Downsampled Features)", type="pil")
150
+ ],
151
  title="CNN from Scratch - Digit Classifier",
152
+ description="Draw a digit in the box to predict its value and see inside the model's 'brain' in real-time!"
153
  )
154
 
155
  if __name__ == "__main__":