noamkay commited on
Commit
696adac
·
1 Parent(s): cf55d9b

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +4 -606
app.py CHANGED
@@ -1,609 +1,7 @@
1
- # !pip install gradio
2
-
3
- from sklearn.model_selection import train_test_split
4
- from sklearn.preprocessing import StandardScaler
5
- from torch.utils.data import TensorDataset, DataLoader
6
- import torch.nn as nn
7
- import torch.optim as optim
8
- import torch
9
- # Visualize the simulated data
10
- import matplotlib.pyplot as plt
11
- import plotly.graph_objs as go
12
- import IPython
13
- import numpy as np
14
- from graphviz import Digraph
15
- import copy
16
- import plotly.graph_objs as go
17
- import torch
18
- import numpy as np
19
- import colorsys
20
- from functools import partial
21
- import gradio as gr # may requeire session restart
22
- import os
23
- import uuid
24
- from contextlib import contextmanager
25
- NETWORK_ORIENTAION = 'h' # 'h' for horizontal 'v' for vertical
26
- TEMP_DIR = "/content/temp"
27
- if not os.path.exists(TEMP_DIR):
28
- os.makedirs(TEMP_DIR)
29
-
30
- """## functions"""
31
-
32
- # @title generate data
33
-
34
- def simulate_clusters(noise=0.3,data_points=1000):
35
- assert data_points%4==0, 'Data points should be dived by 4'
36
- # Set random seed for reproducibility
37
- np.random.seed(0)
38
-
39
- # Define means and covariances for the Gaussian distributions
40
- means = [(-1, -1), (-1, 1), (1, -1), (1, 1)]
41
- covs = [np.eye(2) * noise for _ in means] # Small covariance for tight clusters
42
-
43
- # Generate samples for each cluster
44
- cluster_samples = []
45
- for mean, cov in zip(means, covs):
46
- samples = np.random.multivariate_normal(mean, cov, data_points//4)
47
- cluster_samples.append(samples)
48
-
49
- # Concatenate all samples and create labels
50
- X = np.vstack(cluster_samples)
51
- y = np.array([i//(data_points//4) for i in range(data_points)]) # Assign labels based on cluster index
52
- # Clusters [(-1, -1), (1, 1)] have label 0, and [(-1, 1), (1, -1)] have label 1.
53
- y_adjusted = np.array([0 if i in [0, 3] else 1 for i in y])
54
-
55
- # Split the adjusted dataset
56
- X_train_adj, X_test_adj, y_train_adj, y_test_adj = train_test_split(X, y_adjusted, test_size=0.2, random_state=42)
57
-
58
- # Normalize the features
59
- scaler_adj = StandardScaler()
60
- X_train_scaled_adj = scaler_adj.fit_transform(X_train_adj)
61
- X_test_scaled_adj = scaler_adj.transform(X_test_adj)
62
-
63
- # Convert to PyTorch tensors
64
- X_train_tensor_adj = torch.tensor(X_train_scaled_adj, dtype=torch.float32)
65
- y_train_tensor_adj = torch.tensor(y_train_adj, dtype=torch.long)
66
- X_test_tensor_adj = torch.tensor(X_test_scaled_adj, dtype=torch.float32)
67
- y_test_tensor_adj = torch.tensor(y_test_adj, dtype=torch.long)
68
-
69
- return X_train_tensor_adj,y_train_tensor_adj,X_test_tensor_adj,y_test_tensor_adj
70
-
71
- # @title plotting network with activation
72
- def get_color(activation, base_color=False):
73
- if base_color:
74
- # Convert base color from hex to RGB
75
- r_base, g_base, b_base = int(base_color[1:3], 16), int(base_color[3:5], 16), int(base_color[5:7], 16)
76
-
77
- # Interpolate between the base color and white based on activation
78
- r = r_base + (255 - r_base) * (1 - activation)
79
- g = g_base + (255 - g_base) * (1 - activation)
80
- b = b_base + (255 - b_base) * (1 - activation)
81
-
82
- return f'#{int(r):02x}{int(g):02x}{int(b):02x}'
83
-
84
-
85
- else:
86
- if activation > 0:
87
- return f"#0000FF{int(activation * 255):02X}" # Blue with varying intensity
88
- return "#E0E0E0" # Light gray for inactive neurons
89
-
90
-
91
- rd = lambda activation: ("\n"+"{:.2f}".format(torch.round(activation,decimals=2).item())) if activation!=1 else ''
92
- #sigmoid = lambda x: 1 / (1 + torch.exp(-x)) if x!=1 else 1
93
- softmax = lambda x: torch.exp(x) / torch.sum(torch.exp(x), axis=0) if all(x!=1) else x
94
-
95
-
96
- rd = lambda activation: ("\n"+"{:.2f}".format(torch.round(activation,decimals=2).item())) if activation!=1 else ''
97
- def visualize_network_with_weights(model, activations=False, norm='net', decision_boundary_images=None, width=1, height=1):
98
- dot = Digraph()
99
- if NETWORK_ORIENTAION=='h':
100
- dot.attr(rankdir='LR')
101
- pos_color = "blue"
102
- neg_color = "orange"
103
- layers_weights = {}
104
- max_weight = 0
105
- number_of_layer = 3
106
- # Colors for different layers
107
- input_color, hidden_color, output_color1,output_color2 = '#90EE90','#D3D3D3', '#FFB6C1' , '#ADD8E6' # light grey, light green,light red, light blue
108
-
109
- # Extract weights for each layer and calculate max weight for normalization
110
- for name, layer in model.named_children():
111
- if isinstance(layer, torch.nn.Linear):
112
- layer_weight = layer.weight.cpu().data.numpy()
113
- layers_weights[name] = layer_weight
114
- max_weight = max(max_weight, np.abs(layer_weight).max())
115
- output_layer_name = name #this evantually save the output layer name
116
- # Initialize activations if not provided
117
- if not activations:
118
- activations = {layer: [1] * weight.shape[0] for layer, weight in layers_weights.items()}
119
-
120
- # Normalize weights for visualization purposes
121
- layers_weights_norm = {layer: weight / (np.abs(weight).max() if norm == 'layer' else max_weight)
122
- for layer, weight in layers_weights.items()}
123
- def add_node_with_border(node_id, label, base_color, activation, image_path=None, shape='circle', border_color='black', border_width=1):
124
- fill_color = get_color(activation, base_color)
125
- if image_path:
126
- dot.node(node_id, label, shape='box', style='filled', fillcolor=fill_color, color=border_color, penwidth=str(border_width),imagescale='both', width=str(width), height=str(height), image=image_path, fixedsize='true')
127
- else:
128
- dot.node(node_id, label, shape=shape, style='filled', fillcolor=fill_color, color=border_color, penwidth=str(border_width))
129
- axis_names = ['X','Y']
130
- # Add nodes and edges...
131
- for i in range(layers_weights['fc1'].shape[1]):
132
- add_node_with_border(f'h0_{i}' , f'X{i} - {axis_names[i]} Axis', input_color, 1.0) # Input nodes are always 'active'
133
-
134
- for layer_i in range(1,number_of_layer):
135
- layer_name = 'fc'+str(layer_i)
136
- for i, activation in enumerate(activations[layer_name]):
137
- image_path = decision_boundary_images[layer_name][i] if decision_boundary_images and layer_name in decision_boundary_images and len(decision_boundary_images[layer_name]) > i else None
138
- add_node_with_border(f'h{layer_i}_{i}', f'H{layer_i}_{i}{rd(activation)}', hidden_color, activation, image_path=image_path)
139
- norm_output_activations = softmax(torch.tensor([activations[output_layer_name][0],activations[output_layer_name][1]]))
140
- activation_label1,activation_label2 = norm_output_activations
141
- add_node_with_border(f'h{number_of_layer}_0', f"Y0 - Label 0{rd(activation_label1)}", output_color1, activation_label1,shape='doublecircle')
142
- add_node_with_border(f'h{number_of_layer}_1', f"Y1 - Label 1{rd(activation_label2)}", output_color2, activation_label2,shape='doublecircle')
143
-
144
-
145
- # Adding edges between layers
146
- prev_layer_size = layers_weights[list(layers_weights.keys())[0]].shape[1] # Size of the input layer
147
- prev_layer_name = 'h0'
148
-
149
- for layer_idx, (layer_name, weight_matrix) in enumerate(layers_weights.items(), start=1):
150
- current_layer_size = weight_matrix.shape[0]
151
-
152
- for i in range(prev_layer_size):
153
- for j in range(current_layer_size):
154
- color = pos_color if weight_matrix[j, i] >= 0 else neg_color
155
- dot.edge(f'{prev_layer_name}_{i}', f'h{layer_idx}_{j}', penwidth=str(abs(layers_weights_norm[layer_name][j, i]) * 5), color=color)
156
-
157
- prev_layer_size = current_layer_size
158
- prev_layer_name = f'h{layer_idx}'
159
-
160
- return dot
161
-
162
- # @title Plots (learning curve and decision boundary)
163
- def plot_decision_boundary(model, X_train, y_train, X_test, y_test, show=True, epoch=''):
164
- # Set model to evaluation mode
165
- model.eval()
166
-
167
- # Set min and max values and give it some padding
168
- x_min, x_max = min(X_train[:, 0].min(), X_test[:, 0].min()) - 1, max(X_train[:, 0].max(), X_test[:, 0].max()) + 1
169
- y_min, y_max = min(X_train[:, 1].min(), X_test[:, 1].min()) - 1, max(X_train[:, 1].max(), X_test[:, 1].max()) + 1
170
- h = 0.01
171
-
172
- # Generate a grid of points with distance h between them
173
- xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
174
-
175
- # Flatten the grid so the values match expected input
176
- grid = np.c_[xx.ravel(), yy.ravel()]
177
- grid_tensor = torch.FloatTensor(grid)
178
- with torch.no_grad():
179
- predictions = model(grid_tensor.to(model.device)).argmax(1).to('cpu')
180
- Z = predictions.numpy().reshape(xx.shape)
181
-
182
- # Create the contour plot
183
- contour = go.Contour(
184
- x=np.arange(x_min, x_max, h),
185
- y=np.arange(y_min, y_max, h),
186
- z=Z,
187
- colorscale='RdYlBu', # Light colors for background
188
- showscale=False # Hide the colorbar
189
- )
190
-
191
- # Separate data based on labels
192
- train_0 = X_train[y_train == 0]
193
- train_1 = X_train[y_train == 1]
194
- test_0 = X_test[y_test == 0]
195
- test_1 = X_test[y_test == 1]
196
-
197
- # Create scatter plots for each category
198
- train_0_scatter = go.Scatter(x=train_0[:, 0], y=train_0[:, 1], mode='markers',
199
- marker=dict(color='red', line=dict(color='black', width=1)),
200
- name='Train - Label 0')
201
- train_1_scatter = go.Scatter(x=train_1[:, 0], y=train_1[:, 1], mode='markers',
202
- marker=dict(color='green', line=dict(color='black', width=1)),
203
- name='Train - Label 1')
204
- test_0_scatter = go.Scatter(x=test_0[:, 0], y=test_0[:, 1], mode='markers',
205
- marker=dict(color='rgba(255, 200, 200, 1)', symbol='circle-open', line=dict(color='black', width=1)),
206
- name='Test - Label 0')
207
- test_1_scatter = go.Scatter(x=test_1[:, 0], y=test_1[:, 1], mode='markers',
208
- marker=dict(color='rgba(200, 255, 200, 1)', symbol='circle-open', line=dict(color='black', width=1)),
209
- name='Test - Label 1')
210
-
211
- # Define the layout
212
- layout = go.Layout(
213
- title='Decision Boundary ' + epoch,
214
- xaxis=dict(title='Feature 1'),
215
- yaxis=dict(title='Feature 2'),
216
- showlegend=True
217
- )
218
- # Create the figure and add the contour and scatter plots
219
- fig = go.Figure(data=[contour, train_0_scatter, train_1_scatter, test_0_scatter, test_1_scatter], layout=layout)
220
-
221
- # Show the plot
222
- if show: fig.show()
223
- return fig
224
-
225
-
226
- def generate_learning_curve(loss_hist, loss_val_hist, hidden_units, noise, epochs, lr,metric):
227
- with torch.no_grad():
228
- metric = 'Loss' if metric.lower()=='loss' else "Accuracy"
229
- # Create traces for the training and validation loss
230
- trace_train = go.Scatter(
231
- x=list(range(1, epochs + 1)),
232
- y=loss_hist,
233
- mode='lines',
234
- name=f'Training {metric}'
235
- )
236
- trace_val = go.Scatter(
237
- x=list(range(1, epochs + 1)),
238
- y=loss_val_hist,
239
- mode='lines',
240
- name=f'Validation {metric}'
241
- )
242
-
243
- # Combine traces
244
- data = [trace_train, trace_val]
245
-
246
- # Layout for the plot
247
- layout = go.Layout(
248
- title=f'Learning Curve - Hidden Units: {hidden_units}, Noise: {noise}, Learning Rate: {lr}',
249
- xaxis=dict(title='Epochs'),
250
- yaxis=dict(title=metric),
251
-
252
- )
253
-
254
- # Create the figure and show it
255
- fig = go.Figure(data=data, layout=layout)
256
- return fig
257
-
258
- def save_plot_as_image(fig, remove_axes=True, remove_title=True, remove_colorbar=True, transparent_background=True):
259
- """
260
- Saves a Matplotlib figure as an image and returns the path to the image.
261
- Args:
262
- fig (matplotlib.figure.Figure): The Matplotlib figure to save.
263
- remove_axes (bool): If True, removes the axes from the plot.
264
- remove_title (bool): If True, removes the title and header from the plot.
265
- remove_colorbar (bool): If True, removes the colorbar from the plot.
266
- transparent_background (bool): If True, saves the image with a transparent background.
267
- Returns:
268
- str: Path to the saved image file.
269
- """
270
- # Check if fig is a valid Matplotlib figure
271
- if not isinstance(fig, plt.Figure):
272
- raise ValueError("The provided object is not a Matplotlib figure.")
273
-
274
- # Remove axes if requested
275
- if remove_axes:
276
- for ax in fig.axes:
277
- ax.get_xaxis().set_visible(False)
278
- ax.get_yaxis().set_visible(False)
279
- ax.set_frame_on(False)
280
-
281
- # Remove title and header if requested
282
- if remove_title:
283
- fig.suptitle("")
284
- for ax in fig.axes:
285
- ax.title.set_visible(False)
286
-
287
- # Remove colorbar if requested
288
- if remove_colorbar:
289
- for ax in fig.axes:
290
- if hasattr(ax, 'collections') and ax.collections:
291
- # Check for the presence of a colorbar in this axis
292
- for im in ax.get_images():
293
- if hasattr(im, 'colorbar') and im.colorbar:
294
- im.colorbar.remove()
295
-
296
- # Set transparent background if requested
297
- if transparent_background:
298
- fig.patch.set_alpha(0)
299
- for ax in fig.axes:
300
- ax.patch.set_alpha(0)
301
-
302
-
303
- # Generate a unique filename for the image
304
- filename = f"plot_{uuid.uuid4()}.png"
305
- file_path = os.path.join(TEMP_DIR, filename)
306
-
307
- # Save the figure with a transparent background if requested
308
- fig.savefig(file_path, bbox_inches='tight', pad_inches=0, transparent=transparent_background)
309
-
310
- return file_path
311
-
312
- def plot_neuron_decision_boundaries(model, X, step=0.01):
313
- # Ensure X is a NumPy array
314
- if isinstance(X, torch.Tensor):
315
- X = X.cpu().numpy()
316
- mesh_border_expansion = 0.5 # the mesh is calculted between the highest and lowest values in each axis, with `mesh_border_expansion` additional space
317
- # Generate mesh grid for decision boundaries
318
- x_min, x_max = X[:, 0].min() - mesh_border_expansion , X[:, 0].max() + mesh_border_expansion
319
- y_min, y_max = X[:, 1].min() - mesh_border_expansion , X[:, 1].max() + mesh_border_expansion
320
- xx, yy = np.meshgrid(np.arange(x_min, x_max, step), np.arange(y_min, y_max, step))
321
- mesh_inputs = torch.Tensor(np.c_[xx.ravel(), yy.ravel()])
322
-
323
- model.eval()
324
- figures_dict = {}
325
- layer_outputs = mesh_inputs
326
- with torch.no_grad():
327
- for name, layer in model.named_children():
328
- # Apply the layer
329
- layer_outputs = layer(layer_outputs.to(model.device))
330
-
331
- # Check if the layer is ReLU or the last layer
332
- if isinstance(layer, nn.Linear) or (name == list(model.named_children())[-1][0]):
333
- # Convert to NumPy for plotting
334
- outputs_np = layer_outputs.cpu().numpy()
335
- for neuron_idx in range(outputs_np.shape[1]):
336
- Z = outputs_np[:, neuron_idx].reshape(xx.shape)
337
-
338
- Z_min, Z_max = Z.min(), Z.max()
339
- levels = sorted([Z_min, 0, Z_max]) if Z_min < 0 < Z_max else [Z_min, Z_max]
340
-
341
- fig, ax = plt.subplots()
342
- # ax.contourf(xx, yy, Z, levels=np.linspace(Z.min(), Z.max(), 200), cmap=plt.cm.RdBu, alpha=0.8)
343
- ax.contourf(xx, yy, Z, levels=levels, cmap=plt.cm.RdBu, alpha=0.8)
344
- # ax.set_title(f"Decision boundary of Neuron {neuron_idx+1} in {name}")
345
- # ax.set_xlabel('Feature 1')
346
- # ax.set_ylabel('Feature 2')
347
- plt.show()
348
- plt.close(fig)
349
- if name not in figures_dict:
350
- figures_dict[name]=[]
351
- figures_dict[name] += [fig]
352
-
353
- return figures_dict
354
-
355
-
356
- # plot_neuron_decision_boundaries( fc_model, X_train)
357
-
358
- # step=0.01
359
- # x_min, x_max = X_train[:, 0].min() - 1, X_train[:, 0].max() + 1
360
- # y_min, y_max = X_train[:, 1].min() - 1, X_train[:, 1].max() + 1
361
- # xx, yy = np.meshgrid(np.arange(x_min, x_max, step), np.arange(y_min, y_max, step))
362
- # mesh_inputs = torch.Tensor(np.c_[xx.ravel(), yy.ravel()])
363
- # mesh_inputs
364
-
365
- # @title network architecture and training
366
-
367
- # Global variables to hold model and data
368
- global fc_model_hist, X_train, y_train, X_test, y_test
369
- fc_model_hist, X_train, y_train, X_test, y_test = None, None, None, None, None
370
-
371
- class FCNet(nn.Module):
372
- def __init__(self,hidden_units,device):
373
- super(FCNet, self).__init__()
374
- self.fc1 = nn.Linear(2, hidden_units) # Input layer with 2 features
375
- self.act_func1 = nn.ReLU() # it is important to declare on each relu layer, becuase some of the plotting functions uses model.named_layers() and the ReLU won't be there without explicit declration here
376
- self.fc2 = nn.Linear(hidden_units, hidden_units)
377
- self.act_func2 = nn.ReLU()
378
- self.fc3 = nn.Linear(hidden_units, 2) # Output layer with 2 neurons (for 2 classes)
379
- self.device = device
380
- def forward(self, x):
381
- x = self.act_func1(self.fc1(x))
382
- x = self.act_func2(self.fc2(x))
383
- x = self.fc3(x)
384
- return x
385
- def forward_with_activation(self, x):
386
- inputs = x
387
- x1 = self.act_func1(self.fc1(x))
388
- x2 = self.act_func2(self.fc2(x1))
389
- x3 = self.fc3(x2)
390
- return x,{'inputs':inputs,'fc1':x1,'fc2':x2,'fc3':x3}
391
- def to(self, device):
392
- super().to(device)
393
- self.device = device
394
- return self
395
-
396
- def init_net_and_train(hidden_units = 4,noise = 0.2,epochs = 30,data_points = 1000,lr=0.01,device='cpu',metric='acc'):
397
- global fc_model_hist, X_train, y_train, X_test, y_test
398
- # Simulate the dataset
399
- X_train,y_train,X_test,y_test = simulate_clusters(noise,data_points)
400
-
401
- # Create TensorDataset and DataLoader
402
- train_dataset_adj = TensorDataset(X_train, y_train)
403
- train_loader_adj = DataLoader(train_dataset_adj, batch_size=64, shuffle=True)
404
- test_dataset_adj = TensorDataset(X_test, y_test)
405
- test_loader_adj = DataLoader(test_dataset_adj, batch_size=64, shuffle=True)
406
- # Define a simple Fully Connected network with fewer neurons
407
- # Initialize the simple fully connected neural network
408
- fc_model = FCNet(hidden_units,device=device)
409
- fc_model.to(device)
410
- # Loss and optimizer for the FC network
411
- fc_criterion = nn.CrossEntropyLoss()
412
- fc_optimizer = optim.Adam(fc_model.parameters(), lr=lr)
413
-
414
- # Training loop for the simple FC network
415
- fc_model_hist = []
416
-
417
- # loss_hist = []
418
- # loss_val_hist = []
419
-
420
- # for epoch in range(epochs):
421
- # cur_epoch_loss=torch.tensor(0.,device=fc_model.device)
422
- # inputs_len = 0
423
- # for inputs, labels in train_loader_adj:
424
- # # Forward pass
425
- # outputs = fc_model(inputs.to(device))
426
- # loss = fc_criterion(outputs, labels.to(device))
427
- # cur_epoch_loss+=loss
428
- # inputs_len += labels.shape[0]
429
- # # Backward and optimize
430
- # fc_optimizer.zero_grad()
431
- # loss.backward()
432
- # fc_optimizer.step()
433
- # train_loss = cur_epoch_loss.cpu()/inputs_len
434
- # loss_hist.append(train_loss)
435
- # fc_model_hist.append(copy.deepcopy(fc_model).to('cpu'))
436
- # with torch.no_grad():
437
- # cur_epoch_loss=torch.tensor(0.,device=device)
438
- # inputs_len = 0
439
- # for inputs, labels in test_loader_adj:
440
- # outputs = fc_model(inputs.to(device))
441
- # loss = fc_criterion(outputs, labels.to(device))
442
- # cur_epoch_loss+=loss
443
- # inputs_len += labels.shape[0]
444
- # test_loss = cur_epoch_loss.cpu()/inputs_len
445
- # loss_val_hist.append(test_loss)
446
-
447
- loss_hist = []
448
- loss_val_hist = []
449
- acc_hist = []
450
- acc_val_hist = []
451
-
452
- device = fc_model.device
453
-
454
- for epoch in range(epochs):
455
- fc_model.train() # Set model to training mode
456
- cur_epoch_loss = 0
457
- correct_train = 0
458
- total_train = 0
459
-
460
- for inputs, labels in train_loader_adj:
461
- inputs, labels = inputs.to(device), labels.to(device)
462
- fc_optimizer.zero_grad()
463
- outputs = fc_model(inputs)
464
- loss = fc_criterion(outputs, labels)
465
- loss.backward()
466
- fc_optimizer.step()
467
-
468
- cur_epoch_loss += loss.item() * inputs.size(0)
469
- _, predicted = torch.max(outputs.data, 1)
470
- total_train += labels.size(0)
471
- correct_train += (predicted == labels).sum().item()
472
-
473
- train_loss = cur_epoch_loss / total_train
474
- train_accuracy = correct_train / total_train
475
- loss_hist.append(train_loss)
476
- acc_hist.append(train_accuracy)
477
-
478
- fc_model.eval() # Set model to evaluation mode for validation
479
- fc_model_hist.append(copy.deepcopy(fc_model).to('cpu'))
480
- cur_epoch_loss = 0
481
- correct_test = 0
482
- total_test = 0
483
-
484
- with torch.no_grad():
485
- for inputs, labels in test_loader_adj:
486
- inputs, labels = inputs.to(device), labels.to(device)
487
- outputs = fc_model(inputs)
488
- loss = fc_criterion(outputs, labels)
489
-
490
- cur_epoch_loss += loss.item() * inputs.size(0)
491
- _, predicted = torch.max(outputs.data, 1)
492
- total_test += labels.size(0)
493
- correct_test += (predicted == labels).sum().item()
494
-
495
- test_loss = cur_epoch_loss / total_test
496
- test_accuracy = correct_test / total_test
497
- loss_val_hist.append(test_loss)
498
- acc_val_hist.append(test_accuracy)
499
-
500
-
501
- # print(f'Epoch [{epoch+1}/{epochs}], Train Loss: {train_loss:.4f}, Test Loss: {test_loss:.4f}')
502
-
503
- # return fc_model,fc_model_hist,loss_hist,X_train,y_train,X_test,y_test
504
- if metric=='acc':
505
- reported_metric_train,reported_metric_val = acc_hist,acc_val_hist
506
- else:
507
- reported_metric_train,reported_metric_val = loss_hist,loss_val_hist
508
- return generate_learning_curve(reported_metric_train,reported_metric_val,hidden_units,noise,epochs,lr,metric)
509
-
510
- # @title functions for retriving app images
511
- def get_network_with_inputs(epoch, input_x, input_y,output_type = "HTML"):
512
- if epoch>len(fc_model_hist):
513
- epoch = len(fc_model_hist)
514
- with torch.no_grad():
515
- cur_model = fc_model_hist[epoch - 1]
516
- out, activations = cur_model.forward_with_activation(torch.tensor([input_x, input_y], dtype=torch.float32,device=cur_model.device))
517
- network_dot = visualize_network_with_weights(cur_model, activations=activations)
518
- if output_type=='PNG':
519
- cur_path = f'network_with_weights_activation_{epoch}'
520
- network_dot.render(cur_path, format='png', cleanup=True)
521
- return cur_path + ".png"
522
- else:
523
- svg_content = network_dot.pipe(format='svg').decode('utf-8')
524
- # Create HTML content embedding the SVG
525
- html_content = f'<div style="width:100%; height:100%;">{svg_content}</div>'
526
- return html_content
527
-
528
-
529
- get_plots_as_png = lambda des_list: [save_plot_as_image(plot) for plot in des_list]
530
-
531
-
532
- as_HTML=False
533
-
534
- def generate_images(epoch,net_with_unit_decisions=True):
535
- global fc_model_hist
536
- if epoch>len(fc_model_hist):
537
- epoch = len(fc_model_hist)
538
- fig = plot_decision_boundary(fc_model_hist[epoch-1], X_train, y_train, X_test, y_test, show=False,epoch=f'Epoch:{epoch}')
539
- # network_html = network_dot_paths_list[epoch]
540
- if not net_with_unit_decisions:
541
- network_dot = visualize_network_with_weights(fc_model_hist[epoch-1])
542
- else:
543
- decision_plots = plot_neuron_decision_boundaries(fc_model_hist[epoch-1], X_train)
544
- decision_boundary_images = {k:get_plots_as_png(decision_plots[k]) for k in decision_plots}
545
- network_dot = visualize_network_with_weights(fc_model_hist[epoch-1], activations=False, decision_boundary_images=decision_boundary_images)
546
- if as_HTML:
547
- svg_content = network_dot.pipe(format='svg').decode('utf-8')
548
- network_proccessed = f'<div style="width:100%; height:100%;">{svg_content}</div>'
549
- else:
550
- cur_path = f'{TEMP_DIR}/network_with_weights_activation_{epoch}'
551
- network_dot.render(cur_path, format='png', cleanup=True)
552
- network_proccessed = cur_path+".png"
553
-
554
- return fig, network_proccessed
555
-
556
- @contextmanager
557
- def dummy_context():
558
- yield
559
-
560
  import gradio as gr
561
- """## Launch the app"""
562
-
563
- device ='cuda' if torch.cuda.is_available() else 'cpu'
564
- init_net_and_train_part = partial(init_net_and_train,device=device)
565
-
566
- with gr.Blocks() as iface:
567
-
568
- tab_train = gr.Tab("Network Training")
569
- tab_viz = gr.Tab("Network Visualization")
570
-
571
- with tab_train:
572
- hidden_units_slider = gr.Slider(minimum=1, maximum=10, step=1, value=4, label="number of neurons in hidden layer")
573
- noise_slider = gr.Slider(minimum=0.001, maximum=0.7, step=0.01, value=0.2, label="Noise")
574
- epochs_slider = gr.Slider(minimum=1, maximum=50, step=1, value=30, label="Epochs")
575
- lr_slider = gr.Slider(minimum=0.001, maximum=0.05, step=0.001, value=0.008, label="Learning Rate")
576
- data_points_slider = gr.Slider(minimum=100, maximum=2000, step=4, value=1000, label="Data Points")
577
- train_button = gr.Button("Train Network")
578
- learning_curve = gr.Plot(label="Learning Curve")
579
-
580
- with tab_viz:
581
- with (gr.Row() if NETWORK_ORIENTAION != 'h' else dummy_context()):
582
- with (gr.Column() if NETWORK_ORIENTAION != 'h' else dummy_context()):
583
- with (gr.Row() if NETWORK_ORIENTAION != 'v' else dummy_context()):
584
- epoch_viz_slider = gr.Slider(minimum=1, maximum=50, step=1, value=1, label="Visualize Epoch") # Dynamic update needed here
585
- ner_bounds = gr.Checkbox(label="Invidual neurons decision boundaries")
586
- generate_button = gr.Button("Visualize Network")
587
- plot_output = gr.Plot(label="Decision Boundary")
588
- overall_net_output = gr.Image(type="filepath",label="Network Visualization")
589
- with (gr.Column() if NETWORK_ORIENTAION != 'h' else dummy_context()):
590
- with gr.Row():
591
- input_x = gr.Number(label="Input X")
592
- input_y = gr.Number(label="Input Y")
593
- update_button = gr.Button("Check Input")
594
- net_activity_sample_output = gr.HTML(label="Network Activity for an Input")
595
- # net_activity_sample_output = gr.Image(type="filepath", label="Network Activity for an Input")
596
-
597
- # Set up button click actions
598
- train_button.click(fn=init_net_and_train, inputs=[hidden_units_slider, noise_slider, epochs_slider, data_points_slider, lr_slider], outputs=learning_curve)
599
- generate_button.click(fn=generate_images, inputs=[epoch_viz_slider,ner_bounds], outputs=[plot_output, overall_net_output])
600
- update_button.click(fn=get_network_with_inputs, inputs=[epoch_viz_slider, input_x, input_y], outputs=net_activity_sample_output)
601
-
602
- # # Add Tabs to the interface
603
- # iface.add_tabs(tab_train, tab_viz)
604
 
605
- iface.title = "Neural Network Visualization"
606
- iface.description = "Adjust parameters and train the network to see its performance and visualization."
607
 
608
- if __name__ == "__main__":
609
- iface.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import gradio as gr
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
+ def greet(name):
4
+ return "Hello " + name + "!!"
5
 
6
+ iface = gr.Interface(fn=greet, inputs="text", outputs="text")
7
+ iface.launch()