Harika22 commited on
Commit
ed8f27f
·
verified ·
1 Parent(s): ff061a7

Update pages/Neural_Net_Visualizer.py

Browse files
Files changed (1) hide show
  1. pages/Neural_Net_Visualizer.py +255 -0
pages/Neural_Net_Visualizer.py CHANGED
@@ -0,0 +1,255 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import torch
3
+ import torch.nn as nn
4
+ import torch.optim as optim
5
+ from sklearn.datasets import make_moons, make_circles, make_classification
6
+ from sklearn.model_selection import train_test_split
7
+ from sklearn.preprocessing import StandardScaler
8
+ from sklearn.metrics import accuracy_score
9
+ import numpy as np
10
+ import matplotlib.pyplot as plt
11
+ import pandas as pd
12
+ import time
13
+ import io
14
+
15
+ st.set_page_config(page_title="ANN Visualizer", layout="wide")
16
+
17
+
18
+ st.markdown("""
19
+ <style>
20
+ .main { background-image: linear-gradient(to right, #f8f9fa, #e9ecef); padding: 20px; }
21
+ .stButton>button { color: white; background: linear-gradient(90deg, #1f77b4, #ff7f0e); border: none; border-radius: 12px; padding: 10px 20px; font-weight: bold; }
22
+ .stSlider>div>div>div { background: linear-gradient(to right, #4e54c8, #8f94fb); border-radius: 12px; }
23
+ .css-1v0mbdj, .css-1dp5vir { border-radius: 10px; padding: 10px; background-color: #ffffffcc; }
24
+ </style>
25
+ """, unsafe_allow_html=True)
26
+
27
+ st.title("\U0001F9E0 Interactive ANN Visualizer")
28
+
29
+
30
+ def sidebar_configuration():
31
+ st.sidebar.header("\U0001F527 Configure Your Model")
32
+ dataset = st.sidebar.selectbox("Dataset", ["moons", "circles", "classification"])
33
+ n_samples = st.sidebar.slider("Data Points", 100, 20000, 500, step=100)
34
+ noise = st.sidebar.slider("Noise Level", 0.0, 1.0, 0.2, step=0.05)
35
+ n_hidden = st.sidebar.number_input("Number of Hidden Layers", 1, 10, 2)
36
+
37
+ hidden_layers = []
38
+ activations = []
39
+ dropout_rates = []
40
+ regularizations = []
41
+
42
+ activation_options = ["ReLU", "Tanh", "Sigmoid"]
43
+ reg_options = ["None", "L1", "L2", "L1_L2"]
44
+
45
+ for i in range(n_hidden):
46
+ st.sidebar.markdown(f"### Hidden Layer {i+1}")
47
+ units = st.sidebar.number_input(f"Units (Layer {i+1})", 1, 512, 8, key=f"units_{i}")
48
+ activation = st.sidebar.selectbox(f"Activation (Layer {i+1})", activation_options, key=f"act_{i}")
49
+ dropout = st.sidebar.slider(f"Dropout Rate (Layer {i+1})", 0.0, 0.9, 0.0, 0.05, key=f"drop_{i}")
50
+ reg_type = st.sidebar.selectbox(f"Regularization (Layer {i+1})", reg_options, key=f"reg_{i}")
51
+ reg_strength = st.sidebar.number_input(f"Reg Strength (Layer {i+1})", 0.0001, 1.0, 0.001, format="%f", key=f"reg_strength_{i}") if reg_type != "None" else 0.0
52
+
53
+ hidden_layers.append(units)
54
+ activations.append(activation)
55
+ dropout_rates.append(dropout)
56
+ regularizations.append((reg_type, reg_strength))
57
+
58
+ lr = st.sidebar.number_input("Learning Rate", 0.0001, 1.0, 0.01, format="%f")
59
+ epochs = st.sidebar.slider("Epochs", 100, 5000, 500, step=100)
60
+
61
+ early_stopping = st.sidebar.checkbox("Enable Early Stopping", value=True)
62
+ patience = st.sidebar.slider("Early Stopping Patience", 1, 20, 5) if early_stopping else None
63
+ min_delta = st.sidebar.number_input("Min Delta for Improvement", 0.0001, 0.1, 0.001, format="%f") if early_stopping else None
64
+
65
+ return dataset, n_samples, noise, hidden_layers, activations, dropout_rates, regularizations, lr, epochs, early_stopping, patience, min_delta
66
+
67
+ def generate_dataset(dataset, n_samples, noise):
68
+ if dataset == "moons":
69
+ X, y = make_moons(n_samples=n_samples, noise=noise, random_state=42)
70
+ elif dataset == "circles":
71
+ X, y = make_circles(n_samples=n_samples, noise=noise, factor=0.5, random_state=42)
72
+ else:
73
+ X, y = make_classification(n_samples=n_samples, n_features=2, n_informative=2,
74
+ n_redundant=0, n_clusters_per_class=1, random_state=42)
75
+ return X, y
76
+
77
+
78
+ activation_map = {
79
+ "ReLU": nn.ReLU,
80
+ "Tanh": nn.Tanh,
81
+ "Sigmoid": nn.Sigmoid
82
+ }
83
+
84
+ class CustomLayer(nn.Module):
85
+ def __init__(self, in_dim, out_dim, activation, dropout, reg_type, reg_strength):
86
+ super().__init__()
87
+ self.linear = nn.Linear(in_dim, out_dim)
88
+ self.activation = activation_map[activation]()
89
+ self.dropout = nn.Dropout(dropout)
90
+ self.reg_type = reg_type
91
+ self.reg_strength = reg_strength
92
+
93
+ def forward(self, x):
94
+ x = self.linear(x)
95
+ x = self.activation(x)
96
+ x = self.dropout(x)
97
+ return x
98
+
99
+ def reg_loss(self):
100
+ if self.reg_type == "None":
101
+ return 0
102
+ elif self.reg_type == "L1":
103
+ return self.reg_strength * torch.sum(torch.abs(self.linear.weight))
104
+ elif self.reg_type == "L2":
105
+ return self.reg_strength * torch.sum(self.linear.weight ** 2)
106
+ elif self.reg_type == "L1_L2":
107
+ return self.reg_strength * (torch.sum(torch.abs(self.linear.weight)) + torch.sum(self.linear.weight ** 2))
108
+
109
+ class DynamicANN(nn.Module):
110
+ def __init__(self, input_dim, hidden_layers, activations, dropout_rates, regularizations, output_dim):
111
+ super().__init__()
112
+ self.hidden_layers = nn.ModuleList()
113
+ self.reg_layers = []
114
+
115
+ prev_dim = input_dim
116
+ for units, activation, dropout, (reg_type, reg_strength) in zip(hidden_layers, activations, dropout_rates, regularizations):
117
+ layer = CustomLayer(prev_dim, units, activation, dropout, reg_type, reg_strength)
118
+ self.hidden_layers.append(layer)
119
+ self.reg_layers.append(layer)
120
+ prev_dim = units
121
+
122
+ self.output_layer = nn.Linear(prev_dim, output_dim)
123
+
124
+ def forward(self, x):
125
+ for layer in self.hidden_layers:
126
+ x = layer(x)
127
+ return self.output_layer(x)
128
+
129
+ def total_reg_loss(self):
130
+ return sum(layer.reg_loss() for layer in self.reg_layers)
131
+
132
+
133
+ def train_model(model, criterion, optimizer, X_train, y_train, X_test, y_test, epochs, early_stopping, patience, min_delta):
134
+ train_losses = []
135
+ test_losses = []
136
+
137
+ best_loss = float('inf')
138
+ patience_counter = 0
139
+
140
+ for epoch in range(1, epochs + 1):
141
+ model.train()
142
+ optimizer.zero_grad()
143
+ outputs = model(X_train)
144
+ loss = criterion(outputs, y_train) + model.total_reg_loss()
145
+ loss.backward()
146
+ optimizer.step()
147
+ train_losses.append(loss.item())
148
+
149
+ model.eval()
150
+ with torch.no_grad():
151
+ test_outputs = model(X_test)
152
+ test_loss = criterion(test_outputs, y_test) + model.total_reg_loss()
153
+ test_losses.append(test_loss.item())
154
+
155
+ if early_stopping:
156
+ if test_loss.item() < best_loss - min_delta:
157
+ best_loss = test_loss.item()
158
+ patience_counter = 0
159
+ else:
160
+ patience_counter += 1
161
+ if patience_counter >= patience:
162
+ st.warning(f"Early Stopping at epoch {epoch}")
163
+ break
164
+ yield epoch, train_losses, test_losses
165
+
166
+ def plot_decision_boundary(model, X, y, grid_tensor, xx, yy, title):
167
+ model.eval()
168
+ with torch.no_grad():
169
+ output = model(grid_tensor)
170
+ probs = torch.softmax(output, dim=1)[:, 1].cpu().numpy()
171
+
172
+ probs = probs.reshape(xx.shape)
173
+ fig, ax = plt.subplots(figsize=(6,6))
174
+ ax.contourf(xx, yy, probs, levels=50, cmap='Spectral', alpha=0.8)
175
+ ax.scatter(X[:,0], X[:,1], c=y, edgecolor='k', s=15, cmap='Spectral')
176
+ ax.set_title(title, fontsize=12, fontweight='bold')
177
+ ax.set_xticks([])
178
+ ax.set_yticks([])
179
+ st.pyplot(fig)
180
+ return fig
181
+
182
+
183
+ dataset, n_samples, noise, hidden_layers, activations, dropout_rates, regularizations, lr, epochs, early_stopping, patience, min_delta = sidebar_configuration()
184
+
185
+ start = st.button("\U0001F680 Start Training")
186
+
187
+ if start:
188
+
189
+ X, y = generate_dataset(dataset, n_samples, noise)
190
+ scaler = StandardScaler()
191
+ X = scaler.fit_transform(X)
192
+ X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
193
+
194
+ X_train_tensor = torch.tensor(X_train, dtype=torch.float32)
195
+ y_train_tensor = torch.tensor(y_train, dtype=torch.long)
196
+ X_test_tensor = torch.tensor(X_test, dtype=torch.float32)
197
+ y_test_tensor = torch.tensor(y_test, dtype=torch.long)
198
+
199
+
200
+ model = DynamicANN(X.shape[1], hidden_layers, activations, dropout_rates, regularizations, 2)
201
+ optimizer = optim.Adam(model.parameters(), lr=lr)
202
+ criterion = nn.CrossEntropyLoss()
203
+
204
+ x_min, x_max = X[:,0].min() - 0.5, X[:,0].max() + 0.5
205
+ y_min, y_max = X[:,1].min() - 0.5, X[:,1].max() + 0.5
206
+ xx, yy = np.meshgrid(np.linspace(x_min, x_max, 400), np.linspace(y_min, y_max, 400))
207
+ grid_tensor = torch.tensor(np.c_[xx.ravel(), yy.ravel()], dtype=torch.float32)
208
+
209
+ st.subheader("\U0001F300 Initial Decision Surface")
210
+ plot_decision_boundary(model, X, y, grid_tensor, xx, yy, "Initial Random Decision Surface")
211
+
212
+ st.subheader("\U0001F3CB Training Progress")
213
+ progress_bar = st.progress(0)
214
+ train_losses = []
215
+ test_losses = []
216
+
217
+ for epoch, train_losses, test_losses in train_model(model, criterion, optimizer, X_train_tensor, y_train_tensor, X_test_tensor, y_test_tensor, epochs, early_stopping, patience, min_delta):
218
+ if epoch % (epochs//10) == 0 or epoch == epochs:
219
+ st.markdown(f"### Epoch {epoch}")
220
+ plot_decision_boundary(model, X, y, grid_tensor, xx, yy, f"Decision Surface at Epoch {epoch}")
221
+ progress_bar.progress(epoch/epochs)
222
+
223
+ st.success("Training Complete!")
224
+
225
+ st.subheader("\U0001F4C9 Final Loss Curve")
226
+ fig_loss, ax_loss = plt.subplots()
227
+ ax_loss.plot(train_losses, label='Train Loss', color='blue')
228
+ ax_loss.plot(test_losses, label='Test Loss', color='orange')
229
+ ax_loss.legend()
230
+ ax_loss.grid(True)
231
+ st.pyplot(fig_loss)
232
+
233
+ buf_loss = io.BytesIO()
234
+ fig_loss.savefig(buf_loss, format="png")
235
+ st.download_button("Download Loss Curve", buf_loss.getvalue(), file_name="loss_curve.png", mime="image/png")
236
+
237
+ st.subheader("\U0001F5FA Final Decision Boundary")
238
+ fig_final = plot_decision_boundary(model, X, y, grid_tensor, xx, yy, "Final Decision Surface")
239
+
240
+ buf_final = io.BytesIO()
241
+ fig_final.savefig(buf_final, format="png")
242
+ st.download_button("Download Final Decision Surface", buf_final.getvalue(), file_name="decision_surface.png", mime="image/png")
243
+
244
+ model.eval()
245
+ with torch.no_grad():
246
+ train_preds = model(X_train_tensor).argmax(dim=1).cpu().numpy()
247
+ test_preds = model(X_test_tensor).argmax(dim=1).cpu().numpy()
248
+
249
+ train_acc = accuracy_score(y_train, train_preds)
250
+ test_acc = accuracy_score(y_test, test_preds)
251
+
252
+ st.metric("Train Accuracy", f"{train_acc:.2%}")
253
+ st.metric("Test Accuracy", f"{test_acc:.2%}")
254
+
255
+ st.info("\U0001F501 Adjust Sidebar settings to retrain!")