joel-woodfield commited on
Commit
9357e05
·
1 Parent(s): 7b67454

Add old code from gradio version

Browse files
old_code/README.md ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Optimization Trajectory
3
+ emoji: 🦀
4
+ colorFrom: red
5
+ colorTo: purple
6
+ sdk: gradio
7
+ sdk_version: 5.46.0
8
+ app_file: optimisation.py
9
+ pinned: false
10
+ ---
11
+
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
old_code/bivariate.py ADDED
@@ -0,0 +1,603 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import io
2
+
3
+ import gradio as gr
4
+ import matplotlib.colors as mcolors
5
+ import matplotlib.pyplot as plt
6
+ import numexpr
7
+ import numpy as np
8
+ from PIL import Image
9
+
10
+ import logging
11
+ logging.basicConfig(
12
+ level=logging.INFO, # set minimum level to capture (DEBUG, INFO, WARNING, ERROR, CRITICAL)
13
+ format="%(asctime)s [%(levelname)s] %(message)s", # log format
14
+ )
15
+ logger = logging.getLogger("ELVIS")
16
+
17
+ from optimisers import (
18
+ get_gradient_2d,
19
+ get_hessian_2d,
20
+ get_gd_trajectory_2d,
21
+ get_nesterov_trajectory_2d,
22
+ get_adagrad_trajectory_2d,
23
+ get_rmsprop_trajectory_2d,
24
+ get_adadelta_trajectory_2d,
25
+ get_adam_trajectory_2d,
26
+ get_newton_trajectory_2d,
27
+ )
28
+
29
+
30
+ def format_gradient(xx, yy):
31
+ return f"[{xx}, {yy}]"
32
+
33
+
34
+ def format_hessian(xx, xy, yx, yy):
35
+ return f"[[{xx}, {xy}], [{yx}, {yy}]]"
36
+
37
+
38
+ class Bivariate:
39
+ DEFAULT_FUNCTION = "x**2 + 9 * y**2"
40
+ DEFAULT_INIT_X = 0.5
41
+ DEFAULT_INIT_Y = 0.5
42
+
43
+ DEFAULT_OPTIMISER = "Gradient Descent"
44
+ DEFAULT_NUM_STEPS = 20
45
+ DEFAULT_LEARNING_RATE = 0.1
46
+ DEFAULT_MOMENTUM = 0
47
+
48
+ DEFAULT_EPS = 1e-8
49
+ DEFAULT_RHO_RMSPROP = 0.99
50
+ DEFAULT_RHO_ADADELTA = 0.9
51
+ DEFAULT_EPS_ADADELTA = 1e-2
52
+ DEFAULT_RHO1_ADAM = 0.9
53
+ DEFAULT_RHO2_ADAM = 0.999
54
+
55
+
56
+ def __init__(self, width=1200, height=900):
57
+ self.width = width
58
+ self.height = height
59
+
60
+ self.function = self.DEFAULT_FUNCTION
61
+ self.initial_x = self.DEFAULT_INIT_X
62
+ self.initial_y = self.DEFAULT_INIT_Y
63
+
64
+ # common optimisation hyperparameters
65
+ self.optimiser_type = self.DEFAULT_OPTIMISER
66
+ self.num_steps = self.DEFAULT_NUM_STEPS
67
+ self.learning_rate = self.DEFAULT_LEARNING_RATE
68
+
69
+ # gradient descent and nesterov only
70
+ self.momentum = self.DEFAULT_MOMENTUM
71
+
72
+ # adaptive gradients
73
+ self.rho_rmsprop = self.DEFAULT_RHO_RMSPROP
74
+ self.rho_adadelta = self.DEFAULT_RHO_ADADELTA
75
+ self.rho1_adam = self.DEFAULT_RHO1_ADAM
76
+ self.rho2_adam = self.DEFAULT_RHO2_ADAM
77
+ self.eps = self.DEFAULT_EPS
78
+ self.eps_adadelta = self.DEFAULT_EPS_ADADELTA
79
+
80
+ self.trajectory_x, self.trajectory_y, self.trajectory_z = self.get_optimisation_trajectory()
81
+ self.trajectory_idx = 0
82
+ self.plots = []
83
+ self.generate_plots()
84
+
85
+ def get_optimisation_trajectory(self):
86
+ if self.optimiser_type == "Gradient Descent":
87
+ return get_gd_trajectory_2d(
88
+ self.function,
89
+ self.initial_x,
90
+ self.initial_y,
91
+ self.learning_rate,
92
+ self.momentum,
93
+ self.num_steps,
94
+ )
95
+ elif self.optimiser_type == "Nesterov":
96
+ return get_nesterov_trajectory_2d(
97
+ self.function,
98
+ self.initial_x,
99
+ self.initial_y,
100
+ self.learning_rate,
101
+ self.momentum,
102
+ self.num_steps,
103
+ )
104
+ elif self.optimiser_type == "AdaGrad":
105
+ return get_adagrad_trajectory_2d(
106
+ self.function,
107
+ self.initial_x,
108
+ self.initial_y,
109
+ self.learning_rate,
110
+ self.eps,
111
+ self.num_steps,
112
+ )
113
+ elif self.optimiser_type == "RMSProp":
114
+ return get_rmsprop_trajectory_2d(
115
+ self.function,
116
+ self.initial_x,
117
+ self.initial_y,
118
+ self.learning_rate,
119
+ self.rho_rmsprop,
120
+ self.eps,
121
+ self.num_steps,
122
+ )
123
+ elif self.optimiser_type == "AdaDelta":
124
+ return get_adadelta_trajectory_2d(
125
+ self.function,
126
+ self.initial_x,
127
+ self.initial_y,
128
+ self.learning_rate,
129
+ self.rho_adadelta,
130
+ self.eps_adadelta,
131
+ self.num_steps,
132
+ )
133
+ elif self.optimiser_type == "Adam":
134
+ return get_adam_trajectory_2d(
135
+ self.function,
136
+ self.initial_x,
137
+ self.initial_y,
138
+ self.learning_rate,
139
+ self.rho1_adam,
140
+ self.rho2_adam,
141
+ self.eps,
142
+ self.num_steps,
143
+ )
144
+ elif self.optimiser_type == "Newton":
145
+ return get_newton_trajectory_2d(
146
+ self.function,
147
+ self.initial_x,
148
+ self.initial_y,
149
+ self.num_steps,
150
+ )
151
+ else:
152
+ raise ValueError(f"Unknown optimiser type: {self.optimiser_type}")
153
+
154
+ def generate_plots(self):
155
+ self.plots.clear()
156
+
157
+ fig, ax = plt.subplots()
158
+ cbar = None
159
+
160
+ # precompute for [-1, 1] domain
161
+ x = np.linspace(-1, 1, 100)
162
+ y = np.linspace(-1, 1, 100)
163
+ xx, yy = np.meshgrid(x, y)
164
+
165
+ try:
166
+ zz = numexpr.evaluate(self.function, local_dict={'x': xx, 'y': yy})
167
+ except Exception as e:
168
+ logger.error("Error evaluating function '%s': %s", function, e)
169
+ zz = np.zeros_like(xx)
170
+
171
+ norm = mcolors.Normalize(vmin=zz.min(), vmax=zz.max())
172
+
173
+ for idx in range(self.num_steps):
174
+ x_radius = np.maximum(np.abs(np.min(self.trajectory_x[:idx + 1])), np.abs(np.max(self.trajectory_x[:idx + 1])))
175
+ y_radius = np.maximum(np.abs(np.min(self.trajectory_y[:idx + 1])), np.abs(np.max(self.trajectory_y[:idx + 1])))
176
+ radius = np.maximum(x_radius, y_radius)
177
+
178
+ if radius > 1:
179
+ x = np.linspace(-1.2 * radius, 1.2 * radius, 100)
180
+ y = np.linspace(-1.2 * radius, 1.2 * radius, 100)
181
+
182
+ xx, yy = np.meshgrid(x, y)
183
+
184
+ try:
185
+ zz = numexpr.evaluate(self.function, local_dict={'x': xx, 'y': yy})
186
+ except Exception as e:
187
+ logger.error("Error evaluating function '%s': %s", function, e)
188
+ zz = np.zeros_like(xx)
189
+
190
+ ax.clear()
191
+ countour = ax.contourf(xx, yy, zz, levels=50, cmap='viridis', norm=norm)
192
+ ax.plot(self.trajectory_x[:idx + 1], self.trajectory_y[:idx + 1], marker='o', color='indianred')
193
+ ax.plot(self.trajectory_x[idx], self.trajectory_y[idx], marker='o', color='red')
194
+
195
+ if cbar is None:
196
+ cbar = fig.colorbar(countour, ax=ax)
197
+ else:
198
+ cbar.update_normal(countour)
199
+
200
+ ax.set_xlabel("x")
201
+ ax.set_ylabel("y")
202
+ cbar.set_label("f(x, y)")
203
+
204
+ buf = io.BytesIO()
205
+ fig.savefig(buf, format="png", bbox_inches="tight", pad_inches=0)
206
+ plt.close(fig)
207
+ buf.seek(0)
208
+ img = Image.open(buf)
209
+
210
+ self.plots.append(img)
211
+
212
+ def update_plot(self):
213
+ plot = self.plots[self.trajectory_idx]
214
+ self.plot = plot
215
+ return plot
216
+
217
+ def handle_trajectory_change(self):
218
+ self.trajectory_x, self.trajectory_y, self.trajectory_z = self.get_optimisation_trajectory()
219
+ self.trajectory_idx = 0
220
+ self.generate_plots()
221
+ self.update_plot()
222
+
223
+ def handle_slider_change(self, trajectory_idx):
224
+ self.trajectory_idx = trajectory_idx
225
+ return self.update_plot()
226
+
227
+ def handle_trajectory_button(self):
228
+ if self.trajectory_idx < self.num_steps - 1:
229
+ self.trajectory_idx += 1
230
+ # plot is updated from slider changing
231
+ return self.trajectory_idx
232
+
233
+ def handle_function_change(self, function):
234
+ self.function = function
235
+ self.handle_trajectory_change()
236
+
237
+ gradient = get_gradient_2d(function)
238
+ hessian = get_hessian_2d(function)
239
+ return format_gradient(*gradient), format_hessian(*hessian), self.trajectory_idx, self.plot
240
+
241
+ def handle_learning_rate_change(self, learning_rate):
242
+ self.learning_rate = learning_rate
243
+ self.handle_trajectory_change()
244
+ return self.trajectory_idx, self.plot
245
+
246
+ def handle_momentum_change(self, momentum):
247
+ self.momentum = momentum
248
+ self.handle_trajectory_change()
249
+ return self.trajectory_idx, self.plot
250
+
251
+ def handle_rho_rmsprop_change(self, rho_rmsprop):
252
+ self.rho_rmsprop = rho_rmsprop
253
+ self.handle_trajectory_change()
254
+ return self.trajectory_idx, self.plot
255
+
256
+ def handle_rho_adadelta_change(self, rho_adadelta):
257
+ self.rho_adadelta = rho_adadelta
258
+ self.handle_trajectory_change()
259
+ return self.trajectory_idx, self.plot
260
+
261
+ def handle_rho1_adam_change(self, rho1_adam):
262
+ self.rho1_adam = rho1_adam
263
+ self.handle_trajectory_change()
264
+ return self.trajectory_idx, self.plot
265
+
266
+ def handle_rho2_adam_change(self, rho2_adam):
267
+ self.rho2_adam = rho2_adam
268
+ self.handle_trajectory_change()
269
+ return self.trajectory_idx, self.plot
270
+
271
+ def handle_eps_change(self, eps):
272
+ self.eps = eps
273
+ self.handle_trajectory_change()
274
+ return self.trajectory_idx, self.plot
275
+
276
+ def handle_eps_adadelta_change(self, eps_adadelta):
277
+ self.eps_adadelta = eps_adadelta
278
+ self.handle_trajectory_change()
279
+ return self.trajectory_idx, self.plot
280
+
281
+ def handle_initial_x_change(self, initial_x):
282
+ self.initial_x = initial_x
283
+ self.handle_trajectory_change()
284
+ return self.trajectory_idx, self.plot
285
+
286
+ def handle_initial_y_change(self, initial_y):
287
+ self.initial_y = initial_y
288
+ self.handle_trajectory_change()
289
+ return self.trajectory_idx, self.plot
290
+
291
+ def handle_optimiser_change(self, optimiser_type):
292
+ self.optimiser_type = optimiser_type
293
+ self.handle_trajectory_change()
294
+
295
+ if optimiser_type == "Gradient Descent":
296
+ hessian_update = gr.update(visible=False)
297
+ learning_rate_update = gr.update(visible=True)
298
+ momentum_update = gr.update(visible=True)
299
+ rho_rmsprop_update = gr.update(visible=False)
300
+ rho_adadelta_update = gr.update(visible=False)
301
+ rho1_adam_upate = gr.update(visible=False)
302
+ rho2_adam_update = gr.update(visible=False)
303
+ eps_update = gr.update(visible=False)
304
+ eps_adadelta_update = gr.update(visible=False)
305
+ elif optimiser_type == "Newton":
306
+ hessian_update = gr.update(visible=True)
307
+ learning_rate_update = gr.update(visible=False)
308
+ momentum_update = gr.update(visible=False)
309
+ rho_rmsprop_update = gr.update(visible=False)
310
+ rho_adadelta_update = gr.update(visible=False)
311
+ rho1_adam_upate = gr.update(visible=False)
312
+ rho2_adam_update = gr.update(visible=False)
313
+ eps_update = gr.update(visible=False)
314
+ eps_adadelta_update = gr.update(visible=False)
315
+ elif optimiser_type == "Nesterov":
316
+ hessian_update = gr.update(visible=False)
317
+ learning_rate_update = gr.update(visible=True)
318
+ momentum_update = gr.update(visible=True)
319
+ rho_rmsprop_update = gr.update(visible=False)
320
+ rho_adadelta_update = gr.update(visible=False)
321
+ rho1_adam_upate = gr.update(visible=False)
322
+ rho2_adam_update = gr.update(visible=False)
323
+ eps_update = gr.update(visible=False)
324
+ eps_adadelta_update = gr.update(visible=False)
325
+ elif optimiser_type == "AdaGrad":
326
+ hessian_update = gr.update(visible=False)
327
+ learning_rate_update = gr.update(visible=True)
328
+ momentum_update = gr.update(visible=False)
329
+ rho_rmsprop_update = gr.update(visible=False)
330
+ rho_adadelta_update = gr.update(visible=False)
331
+ rho1_adam_upate = gr.update(visible=False)
332
+ rho2_adam_update = gr.update(visible=False)
333
+ eps_update = gr.update(visible=True)
334
+ eps_adadelta_update = gr.update(visible=False)
335
+ elif optimiser_type == "RMSProp":
336
+ hessian_update = gr.update(visible=False)
337
+ learning_rate_update = gr.update(visible=True)
338
+ momentum_update = gr.update(visible=False)
339
+ rho_rmsprop_update = gr.update(visible=True)
340
+ rho_adadelta_update = gr.update(visible=False)
341
+ rho1_adam_upate = gr.update(visible=False)
342
+ rho2_adam_update = gr.update(visible=False)
343
+ eps_update = gr.update(visible=True)
344
+ eps_adadelta_update = gr.update(visible=False)
345
+ elif optimiser_type == "AdaDelta":
346
+ hessian_update = gr.update(visible=False)
347
+ learning_rate_update = gr.update(visible=True)
348
+ momentum_update = gr.update(visible=False)
349
+ rho_rmsprop_update = gr.update(visible=False)
350
+ rho_adadelta_update = gr.update(visible=True)
351
+ rho1_adam_upate = gr.update(visible=False)
352
+ rho2_adam_update = gr.update(visible=False)
353
+ eps_update = gr.update(visible=False)
354
+ eps_adadelta_update = gr.update(visible=True)
355
+ elif optimiser_type == "Adam":
356
+ hessian_update = gr.update(visible=False)
357
+ learning_rate_update = gr.update(visible=True)
358
+ momentum_update = gr.update(visible=False)
359
+ rho_rmsprop_update = gr.update(visible=False)
360
+ rho_adadelta_update = gr.update(visible=False)
361
+ rho1_adam_upate = gr.update(visible=True)
362
+ rho2_adam_update = gr.update(visible=True)
363
+ eps_update = gr.update(visible=True)
364
+ eps_adadelta_update = gr.update(visible=False)
365
+ else:
366
+ raise ValueError(f"Unknown optimiser type: {optimiser_type}")
367
+
368
+ return (
369
+ hessian_update,
370
+ learning_rate_update,
371
+ momentum_update,
372
+ rho_rmsprop_update,
373
+ rho_adadelta_update,
374
+ rho1_adam_upate,
375
+ rho2_adam_update,
376
+ eps_update,
377
+ eps_adadelta_update,
378
+ self.trajectory_idx,
379
+ self.plot,
380
+ )
381
+
382
+ def reset(self):
383
+ self.function = self.DEFAULT_FUNCTION
384
+ self.initial_x = self.DEFAULT_INIT_X
385
+ self.initial_y = self.DEFAULT_INIT_Y
386
+
387
+ self.num_steps = self.DEFAULT_NUM_STEPS
388
+ self.optimiser_type = self.DEFAULT_OPTIMISER
389
+ self.learning_rate = self.DEFAULT_LEARNING_RATE
390
+
391
+ # gradient descent and nesterov only
392
+ self.momentum = self.DEFAULT_MOMENTUM
393
+
394
+ # adaptive gradients
395
+ self.rho_rmsprop = self.DEFAULT_RHO_RMSPROP
396
+ self.rho_adadelta = self.DEFAULT_RHO_ADADELTA
397
+ self.rho1_adam = self.DEFAULT_RHO1_ADAM
398
+ self.rho2_adam = self.DEFAULT_RHO2_ADAM
399
+ self.eps = self.DEFAULT_EPS
400
+ self.eps_adadelta = self.DEFAULT_EPS_ADADELTA
401
+
402
+ self.trajectory_x, self.trajectory_y, self.trajectory_z = self.get_optimisation_trajectory()
403
+ self.trajectory_idx = 0
404
+
405
+ self.plots = []
406
+ self.generate_plots()
407
+
408
+ def build(self):
409
+ with gr.Tab("Bivariate"):
410
+ with gr.Row():
411
+ with gr.Column(scale=2):
412
+ self.plot = gr.Image(
413
+ value=self.update_plot(),
414
+ container=True,
415
+ )
416
+
417
+ with gr.Column(scale=1):
418
+ with gr.Tab("Settings"):
419
+ function = gr.Textbox(
420
+ label="Function",
421
+ value=self.function,
422
+ interactive=True,
423
+ container=True,
424
+ )
425
+ gradient = gr.Textbox(
426
+ label="Gradient",
427
+ value=format_gradient(*get_gradient_2d(self.function)),
428
+ interactive=False,
429
+ container=True,
430
+ )
431
+ hessian = gr.Textbox(
432
+ label="Hessian",
433
+ value=format_hessian(*get_hessian_2d(self.function)),
434
+ interactive=False,
435
+ container=True,
436
+ visible=False,
437
+ )
438
+
439
+ with gr.Row():
440
+ optimiser_type = gr.Dropdown(
441
+ label="Optimiser",
442
+ choices=["Gradient Descent", "Nesterov", "AdaGrad", "RMSProp", "AdaDelta", "Adam", "Newton"],
443
+ value=self.optimiser_type,
444
+ interactive=True,
445
+ container=True,
446
+ )
447
+
448
+ with gr.Row():
449
+ initial_x = gr.Number(
450
+ label="Initial x",
451
+ value=self.initial_x,
452
+ interactive=True,
453
+ container=True,
454
+ )
455
+ initial_y = gr.Number(
456
+ label="Initial y",
457
+ value=self.initial_y,
458
+ interactive=True,
459
+ container=True,
460
+ )
461
+
462
+ # hyperparameter row
463
+ with gr.Row():
464
+ learning_rate = gr.Number(
465
+ label="Learning Rate",
466
+ value=self.learning_rate,
467
+ interactive=True,
468
+ container=True,
469
+ )
470
+ momentum = gr.Number(
471
+ label="Momentum",
472
+ value=self.momentum,
473
+ interactive=True,
474
+ container=True,
475
+ )
476
+ rho_rmsprop = gr.Number(
477
+ label="rho",
478
+ value=self.DEFAULT_RHO_RMSPROP,
479
+ interactive=True,
480
+ container=True,
481
+ visible=False,
482
+ )
483
+ rho_adadelta = gr.Number(
484
+ label="rho",
485
+ value=self.DEFAULT_RHO_ADADELTA,
486
+ interactive=True,
487
+ container=True,
488
+ visible=False,
489
+ )
490
+ rho1_adam = gr.Number(
491
+ label="rho1",
492
+ value=self.DEFAULT_RHO1_ADAM,
493
+ interactive=True,
494
+ container=True,
495
+ visible=False,
496
+ )
497
+ rho2_adam = gr.Number(
498
+ label="rho2",
499
+ value=self.DEFAULT_RHO2_ADAM,
500
+ interactive=True,
501
+ container=True,
502
+ visible=False,
503
+ )
504
+ eps = gr.Number(
505
+ label="Epsilon",
506
+ value=self.eps,
507
+ interactive=True,
508
+ container=True,
509
+ visible=False,
510
+ )
511
+ eps_adadelta = gr.Number(
512
+ label="Epsilon",
513
+ value=self.eps_adadelta,
514
+ interactive=True,
515
+ container=True,
516
+ visible=False,
517
+ )
518
+
519
+ with gr.Tab("Trajectory"):
520
+ trajectory_slider = gr.Slider(
521
+ label="Optimisation step",
522
+ minimum=0,
523
+ maximum=self.num_steps - 1,
524
+ step=1,
525
+ value=0,
526
+ interactive=True,
527
+ )
528
+
529
+ trajectory_button = gr.Button("Optimisation step")
530
+
531
+ function.submit(
532
+ self.handle_function_change,
533
+ inputs=[function],
534
+ outputs=[gradient, hessian, trajectory_slider, self.plot],
535
+ )
536
+
537
+ optimiser_type.change(
538
+ self.handle_optimiser_change,
539
+ inputs=[optimiser_type],
540
+ outputs=[hessian, learning_rate, momentum, rho_rmsprop, rho_adadelta, rho1_adam, rho2_adam, eps, eps_adadelta, trajectory_slider, self.plot],
541
+ )
542
+
543
+ initial_x.submit(
544
+ self.handle_initial_x_change,
545
+ inputs=[initial_x],
546
+ outputs=[trajectory_slider, self.plot],
547
+ )
548
+ initial_y.submit(
549
+ self.handle_initial_y_change,
550
+ inputs=[initial_y],
551
+ outputs=[trajectory_slider, self.plot],
552
+ )
553
+
554
+ learning_rate.submit(
555
+ self.handle_learning_rate_change,
556
+ inputs=[learning_rate],
557
+ outputs=[trajectory_slider, self.plot],
558
+ )
559
+ momentum.submit(
560
+ self.handle_momentum_change,
561
+ inputs=[momentum],
562
+ outputs=[trajectory_slider, self.plot],
563
+ )
564
+ rho_rmsprop.submit(
565
+ self.handle_rho_rmsprop_change,
566
+ inputs=[rho_rmsprop],
567
+ outputs=[trajectory_slider, self.plot],
568
+ )
569
+ rho_adadelta.submit(
570
+ self.handle_rho_adadelta_change,
571
+ inputs=[rho_adadelta],
572
+ outputs=[trajectory_slider, self.plot],
573
+ )
574
+ rho1_adam.submit(
575
+ self.handle_rho1_adam_change,
576
+ inputs=[rho1_adam],
577
+ outputs=[trajectory_slider, self.plot],
578
+ )
579
+ rho2_adam.submit(
580
+ self.handle_rho2_adam_change,
581
+ inputs=[rho2_adam],
582
+ outputs=[trajectory_slider, self.plot],
583
+ )
584
+ eps.submit(
585
+ self.handle_eps_change,
586
+ inputs=[eps],
587
+ outputs=[trajectory_slider, self.plot],
588
+ )
589
+ eps_adadelta.submit(
590
+ self.handle_eps_adadelta_change,
591
+ inputs=[eps_adadelta],
592
+ outputs=[trajectory_slider, self.plot],
593
+ )
594
+
595
+ trajectory_slider.change(
596
+ self.handle_slider_change,
597
+ inputs=[trajectory_slider],
598
+ outputs=[self.plot],
599
+ )
600
+ trajectory_button.click(
601
+ self.handle_trajectory_button,
602
+ outputs=[trajectory_slider],
603
+ )
old_code/optimisation.py ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+
3
+ from bivariate import Bivariate
4
+ from univariate import Univariate
5
+
6
+ class Optimisation:
7
+ def __init__(self, width=1200, height=900):
8
+ self.width = width
9
+ self.height = height
10
+ self.univariate = Univariate(width, height)
11
+ self.bivariate = Bivariate(width, height)
12
+
13
+ def on_load(self):
14
+ self.univariate.reset()
15
+ self.bivariate.reset()
16
+
17
+ def launch(self):
18
+ with gr.Blocks() as demo:
19
+ gr.HTML("<div style='text-align:left; font-size:40px; font-weight: bold;'>Optimisation trajectory visualizer</div>")
20
+ self.univariate.build()
21
+ self.bivariate.build()
22
+ demo.load(self.on_load)
23
+
24
+ demo.launch()
25
+
26
+ visualizer = Optimisation(width=1200, height=900)
27
+ visualizer.launch()
old_code/optimisers.py ADDED
@@ -0,0 +1,312 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numexpr
2
+ import numpy as np
3
+ import sympy
4
+
5
+ def get_gradient_1d(function):
6
+ x = sympy.symbols('x')
7
+ expr = sympy.sympify(function)
8
+ grad_x = sympy.diff(expr, x)
9
+ return grad_x
10
+
11
+
12
+ def get_hessian_1d(function):
13
+ x = sympy.symbols('x')
14
+ expr = sympy.sympify(function)
15
+ hess_x = sympy.diff(expr, x, 2)
16
+ return hess_x
17
+
18
+
19
+ def get_gradient_2d(function):
20
+ x, y = sympy.symbols('x y')
21
+ expr = sympy.sympify(function)
22
+ grad_x = sympy.diff(expr, x)
23
+ grad_y = sympy.diff(expr, y)
24
+ return grad_x, grad_y
25
+
26
+
27
+ def get_hessian_2d(function):
28
+ x, y = sympy.symbols('x y')
29
+ expr = sympy.sympify(function)
30
+ hess_xx = sympy.diff(expr, x, 2)
31
+ hess_yy = sympy.diff(expr, y, 2)
32
+ hess_xy = sympy.diff(expr, x, y)
33
+ hess_yx = sympy.diff(expr, y, x)
34
+ return hess_xx, hess_xy, hess_yx, hess_yy
35
+
36
+
37
+ def get_optimizer_trajectory_1d(function, initial_x, optimiser_type, learning_rate, momentum, num_steps):
38
+ if optimiser_type == "Gradient Descent":
39
+ return get_gd_trajectory_1d(function, initial_x, learning_rate, momentum, num_steps)
40
+ elif optimiser_type == "Newton":
41
+ return get_newton_trajectory_1d(function, initial_x, num_steps)
42
+ else:
43
+ raise ValueError(f"Unsupported optimiser type: {optimiser_type}")
44
+
45
+
46
+ def get_gd_trajectory_1d(function, initial_x, learning_rate, momentum, num_steps):
47
+ grad_x = get_gradient_1d(function)
48
+
49
+ trajectory_x = np.zeros(num_steps + 1)
50
+ trajectory_y = np.zeros(num_steps + 1)
51
+ trajectory_x[0] = initial_x
52
+ trajectory_y[0] = numexpr.evaluate(function, local_dict={'x': initial_x})
53
+
54
+ for i in range(num_steps):
55
+ grad_x_val = float(grad_x.evalf(subs={'x': trajectory_x[i]}))
56
+ if i == 0:
57
+ momentum_x = 0
58
+ else:
59
+ momentum_x = momentum * (trajectory_x[i] - trajectory_x[i - 1])
60
+
61
+ trajectory_x[i + 1] = trajectory_x[i] - learning_rate * grad_x_val + momentum_x
62
+ trajectory_y[i + 1] = numexpr.evaluate(function, local_dict={'x': trajectory_x[i + 1]})
63
+
64
+ return trajectory_x, trajectory_y
65
+
66
+
67
+ def get_newton_trajectory_1d(function, initial_x, num_steps):
68
+ grad_x = get_gradient_1d(function)
69
+ hess_x = get_hessian_1d(function)
70
+
71
+ trajectory_x = np.zeros(num_steps + 1)
72
+ trajectory_y = np.zeros(num_steps + 1)
73
+ trajectory_x[0] = initial_x
74
+ trajectory_y[0] = numexpr.evaluate(function, local_dict={'x': initial_x})
75
+
76
+ for i in range(num_steps):
77
+ grad_x_val = float(grad_x.evalf(subs={'x': trajectory_x[i]}))
78
+ hess_x_val = float(hess_x.evalf(subs={'x': trajectory_x[i]}))
79
+
80
+ if hess_x_val == 0:
81
+ break
82
+ trajectory_x[i + 1] = trajectory_x[i] - grad_x_val / hess_x_val
83
+ trajectory_y[i + 1] = numexpr.evaluate(function, local_dict={'x': trajectory_x[i + 1]})
84
+
85
+ return trajectory_x, trajectory_y
86
+
87
+
88
+ def get_gd_trajectory_2d(function, initial_x, initial_y, learning_rate, momentum, num_steps):
89
+ grad_x, grad_y = get_gradient_2d(function)
90
+
91
+ trajectory_x = np.zeros(num_steps + 1)
92
+ trajectory_y = np.zeros(num_steps + 1)
93
+ trajectory_z = np.zeros(num_steps + 1)
94
+ trajectory_x[0] = initial_x
95
+ trajectory_y[0] = initial_y
96
+ trajectory_z[0] = numexpr.evaluate(function, local_dict={'x': initial_x, 'y': initial_y})
97
+
98
+ for i in range(num_steps):
99
+ grad_x_val = float(grad_x.evalf(subs={'x': trajectory_x[i], 'y': trajectory_y[i]}))
100
+ grad_y_val = float(grad_y.evalf(subs={'x': trajectory_x[i], 'y': trajectory_y[i]}))
101
+
102
+ if i == 0:
103
+ momentum_x = 0
104
+ momentum_y = 0
105
+ else:
106
+ momentum_x = momentum * (trajectory_x[i] - trajectory_x[i - 1])
107
+ momentum_y = momentum * (trajectory_y[i] - trajectory_y[i - 1])
108
+
109
+ trajectory_x[i + 1] = trajectory_x[i] - learning_rate * grad_x_val + momentum_x
110
+ trajectory_y[i + 1] = trajectory_y[i] - learning_rate * grad_y_val + momentum_y
111
+ trajectory_z[i + 1] = numexpr.evaluate(function, local_dict={'x': trajectory_x[i + 1], 'y': trajectory_y[i + 1]})
112
+
113
+ return trajectory_x, trajectory_y, trajectory_z
114
+
115
+
116
+ def get_nesterov_trajectory_2d(function, initial_x, initial_y, learning_rate, momentum, num_steps):
117
+ grad_x, grad_y = get_gradient_2d(function)
118
+
119
+ trajectory_x = np.zeros(num_steps + 1)
120
+ trajectory_y = np.zeros(num_steps + 1)
121
+ trajectory_z = np.zeros(num_steps + 1)
122
+ trajectory_x[0] = initial_x
123
+ trajectory_y[0] = initial_y
124
+ trajectory_z[0] = numexpr.evaluate(function, local_dict={'x': initial_x, 'y': initial_y})
125
+
126
+ for i in range(num_steps):
127
+ if i == 0:
128
+ momentum_x = 0
129
+ momentum_y = 0
130
+ else:
131
+ momentum_x = momentum * (trajectory_x[i] - trajectory_x[i - 1])
132
+ momentum_y = momentum * (trajectory_y[i] - trajectory_y[i - 1])
133
+
134
+ x = trajectory_x[i] + momentum_x
135
+ y = trajectory_y[i] + momentum_y
136
+ grad_x_val = float(grad_x.evalf(subs={'x': x, 'y': y}))
137
+ grad_y_val = float(grad_y.evalf(subs={'x': x, 'y': y}))
138
+
139
+ trajectory_x[i + 1] = trajectory_x[i] - learning_rate * grad_x_val
140
+ trajectory_y[i + 1] = trajectory_y[i] - learning_rate * grad_y_val
141
+ trajectory_z[i + 1] = numexpr.evaluate(function, local_dict={'x': trajectory_x[i + 1], 'y': trajectory_y[i + 1]})
142
+
143
+ return trajectory_x, trajectory_y, trajectory_z
144
+
145
+
146
+ def get_adam_trajectory_2d(function, initial_x, initial_y, learning_rate, rho1, rho2, epsilon, num_steps):
147
+ grad_x, grad_y = get_gradient_2d(function)
148
+
149
+ trajectory_x = np.zeros(num_steps + 1)
150
+ trajectory_y = np.zeros(num_steps + 1)
151
+ trajectory_z = np.zeros(num_steps + 1)
152
+ trajectory_x[0] = initial_x
153
+ trajectory_y[0] = initial_y
154
+ trajectory_z[0] = numexpr.evaluate(function, local_dict={'x': initial_x, 'y': initial_y})
155
+
156
+ m_x, m_y = 0, 0
157
+ v_x, v_y = 0, 0
158
+ epsilon = 1e-8
159
+
160
+ for i in range(num_steps):
161
+ grad_x_val = float(grad_x.evalf(subs={'x': trajectory_x[i], 'y': trajectory_y[i]}))
162
+ grad_y_val = float(grad_y.evalf(subs={'x': trajectory_x[i], 'y': trajectory_y[i]}))
163
+
164
+ m_x = rho1 * m_x + (1 - rho1) * grad_x_val
165
+ m_y = rho1 * m_y + (1 - rho1) * grad_y_val
166
+
167
+ v_x = rho2 * v_x + (1 - rho2) * (grad_x_val ** 2)
168
+ v_y = rho2 * v_y + (1 - rho2) * (grad_y_val ** 2)
169
+
170
+ m_hat_x = m_x / (1 - rho1 ** (i + 1))
171
+ m_hat_y = m_y / (1 - rho1 ** (i + 1))
172
+
173
+ v_hat_x = v_x / (1 - rho2 ** (i + 1))
174
+ v_hat_y = v_y / (1 - rho2 ** (i + 1))
175
+
176
+ trajectory_x[i + 1] = trajectory_x[i] - learning_rate * m_hat_x / np.sqrt(v_hat_x + epsilon)
177
+ trajectory_y[i + 1] = trajectory_y[i] - learning_rate * m_hat_y / np.sqrt(v_hat_y + epsilon)
178
+ trajectory_z[i + 1] = numexpr.evaluate(function, local_dict={'x': trajectory_x[i + 1], 'y': trajectory_y[i + 1]})
179
+
180
+ return trajectory_x, trajectory_y, trajectory_z
181
+
182
+
183
+ def get_newton_trajectory_2d(function, initial_x, initial_y, num_steps):
184
+ grad_x, grad_y = get_gradient_2d(function)
185
+ hess_xx, hess_xy, hess_yx, hess_yy = get_hessian_2d(function)
186
+
187
+ trajectory_x = np.zeros(num_steps + 1)
188
+ trajectory_y = np.zeros(num_steps + 1)
189
+ trajectory_z = np.zeros(num_steps + 1)
190
+ trajectory_x[0] = initial_x
191
+ trajectory_y[0] = initial_y
192
+ trajectory_z[0] = numexpr.evaluate(function, local_dict={'x': initial_x, 'y': initial_y})
193
+
194
+ for i in range(num_steps):
195
+ grad_x_val = float(grad_x.evalf(subs={'x': trajectory_x[i], 'y': trajectory_y[i]}))
196
+ grad_y_val = float(grad_y.evalf(subs={'x': trajectory_x[i], 'y': trajectory_y[i]}))
197
+
198
+ hess_xx_val = float(hess_xx.evalf(subs={'x': trajectory_x[i], 'y': trajectory_y[i]}))
199
+ hess_xy_val = float(hess_xy.evalf(subs={'x': trajectory_x[i], 'y': trajectory_y[i]}))
200
+ hess_yx_val = float(hess_yx.evalf(subs={'x': trajectory_x[i], 'y': trajectory_y[i]}))
201
+ hess_yy_val = float(hess_yy.evalf(subs={'x': trajectory_x[i], 'y': trajectory_y[i]}))
202
+
203
+ hessian_matrix = np.array(
204
+ [
205
+ [hess_xx_val, hess_xy_val],
206
+ [hess_yx_val, hess_yy_val]
207
+ ],
208
+ )
209
+
210
+ gradient_vector = np.array([grad_x_val, grad_y_val])
211
+
212
+ try:
213
+ hessian_inv = np.linalg.inv(hessian_matrix)
214
+ except np.linalg.LinAlgError:
215
+ break
216
+
217
+ step = hessian_inv @ gradient_vector
218
+
219
+ trajectory_x[i + 1] = trajectory_x[i] - step[0]
220
+ trajectory_y[i + 1] = trajectory_y[i] - step[1]
221
+ trajectory_z[i + 1] = numexpr.evaluate(function, local_dict={'x': trajectory_x[i + 1], 'y': trajectory_y[i + 1]})
222
+
223
+ return trajectory_x, trajectory_y, trajectory_z
224
+
225
+
226
+ def get_adagrad_trajectory_2d(function, initial_x, initial_y, learning_rate, epsilon, num_steps):
227
+ grad_x, grad_y = get_gradient_2d(function)
228
+
229
+ trajectory_x = np.zeros(num_steps + 1)
230
+ trajectory_y = np.zeros(num_steps + 1)
231
+ trajectory_z = np.zeros(num_steps + 1)
232
+ trajectory_x[0] = initial_x
233
+ trajectory_y[0] = initial_y
234
+ trajectory_z[0] = numexpr.evaluate(function, local_dict={'x': initial_x, 'y': initial_y})
235
+
236
+ v_x = 0
237
+ v_y = 0
238
+
239
+ for i in range(num_steps):
240
+ grad_x_val = float(grad_x.evalf(subs={'x': trajectory_x[i], 'y': trajectory_y[i]}))
241
+ grad_y_val = float(grad_y.evalf(subs={'x': trajectory_x[i], 'y': trajectory_y[i]}))
242
+
243
+ v_x += grad_x_val ** 2
244
+ v_y += grad_y_val ** 2
245
+
246
+ trajectory_x[i + 1] = trajectory_x[i] - learning_rate / np.sqrt(v_x + epsilon) * grad_x_val
247
+ trajectory_y[i + 1] = trajectory_y[i] - learning_rate / np.sqrt(v_y + epsilon) * grad_y_val
248
+ trajectory_z[i + 1] = numexpr.evaluate(function, local_dict={'x': trajectory_x[i + 1], 'y': trajectory_y[i + 1]})
249
+
250
+ return trajectory_x, trajectory_y, trajectory_z
251
+
252
+
253
+ def get_rmsprop_trajectory_2d(function, initial_x, initial_y, learning_rate, rho, epsilon, num_steps):
254
+ grad_x, grad_y = get_gradient_2d(function)
255
+
256
+ trajectory_x = np.zeros(num_steps + 1)
257
+ trajectory_y = np.zeros(num_steps + 1)
258
+ trajectory_z = np.zeros(num_steps + 1)
259
+ trajectory_x[0] = initial_x
260
+ trajectory_y[0] = initial_y
261
+ trajectory_z[0] = numexpr.evaluate(function, local_dict={'x': initial_x, 'y': initial_y})
262
+
263
+ v_x = 0
264
+ v_y = 0
265
+
266
+ for i in range(num_steps):
267
+ grad_x_val = float(grad_x.evalf(subs={'x': trajectory_x[i], 'y': trajectory_y[i]}))
268
+ grad_y_val = float(grad_y.evalf(subs={'x': trajectory_x[i], 'y': trajectory_y[i]}))
269
+
270
+ v_x = rho * v_x + (1 - rho) * (grad_x_val ** 2)
271
+ v_y = rho * v_y + (1 - rho) * (grad_y_val ** 2)
272
+
273
+ trajectory_x[i + 1] = trajectory_x[i] - learning_rate / np.sqrt(v_x + epsilon) * grad_x_val
274
+ trajectory_y[i + 1] = trajectory_y[i] - learning_rate / np.sqrt(v_y + epsilon) * grad_y_val
275
+ trajectory_z[i + 1] = numexpr.evaluate(function, local_dict={'x': trajectory_x[i + 1], 'y': trajectory_y[i + 1]})
276
+
277
+ return trajectory_x, trajectory_y, trajectory_z
278
+
279
+
280
+ def get_adadelta_trajectory_2d(function, initial_x, initial_y, learning_rate, rho, epsilon, num_steps):
281
+ grad_x, grad_y = get_gradient_2d(function)
282
+
283
+ trajectory_x = np.zeros(num_steps + 1)
284
+ trajectory_y = np.zeros(num_steps + 1)
285
+ trajectory_z = np.zeros(num_steps + 1)
286
+ trajectory_x[0] = initial_x
287
+ trajectory_y[0] = initial_y
288
+ trajectory_z[0] = numexpr.evaluate(function, local_dict={'x': initial_x, 'y': initial_y})
289
+
290
+ v_x = 0
291
+ v_y = 0
292
+ s_x = 0
293
+ s_y = 0
294
+
295
+ for i in range(num_steps):
296
+ grad_x_val = float(grad_x.evalf(subs={'x': trajectory_x[i], 'y': trajectory_y[i]}))
297
+ grad_y_val = float(grad_y.evalf(subs={'x': trajectory_x[i], 'y': trajectory_y[i]}))
298
+
299
+ v_x = rho * v_x + (1 - rho) * (grad_x_val ** 2)
300
+ v_y = rho * v_y + (1 - rho) * (grad_y_val ** 2)
301
+
302
+ del_x = np.sqrt(s_x + epsilon) / np.sqrt(v_x + epsilon) * grad_x_val
303
+ del_y = np.sqrt(s_y + epsilon) / np.sqrt(v_y + epsilon) * grad_y_val
304
+
305
+ s_x = rho * s_x + (1 - rho) * del_x ** 2
306
+ s_y = rho * s_y + (1 - rho) * del_y ** 2
307
+
308
+ trajectory_x[i + 1] = trajectory_x[i] - learning_rate * del_x
309
+ trajectory_y[i + 1] = trajectory_y[i] - learning_rate * del_y
310
+ trajectory_z[i + 1] = numexpr.evaluate(function, local_dict={'x': trajectory_x[i + 1], 'y': trajectory_y[i + 1]})
311
+
312
+ return trajectory_x, trajectory_y, trajectory_z
old_code/requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ matplotlib
2
+ mpu
3
+ numexpr
4
+ numpy
5
+ pandas
6
+ pillow
7
+ plotly
8
+ scikit-learn
9
+ sympy
old_code/univariate.py ADDED
@@ -0,0 +1,261 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import io
2
+
3
+ import gradio as gr
4
+ import matplotlib.pyplot as plt
5
+ import numexpr
6
+ import numpy as np
7
+ from PIL import Image
8
+
9
+ import logging
10
+ logging.basicConfig(
11
+ level=logging.INFO, # set minimum level to capture (DEBUG, INFO, WARNING, ERROR, CRITICAL)
12
+ format="%(asctime)s [%(levelname)s] %(message)s", # log format
13
+ )
14
+ logger = logging.getLogger("ELVIS")
15
+
16
+ from optimisers import get_gradient_1d, get_hessian_1d, get_optimizer_trajectory_1d
17
+
18
+
19
+ class Univariate:
20
+ DEFAULT_UNIVARIATE = "x ** 2"
21
+ DEFAULT_INIT_X = 0.5
22
+
23
+ def __init__(self, width, height):
24
+ self.canvas_width = width
25
+ self.canvas_height = height
26
+
27
+ self.optimiser_type = "Gradient Descent"
28
+ self.learning_rate = 0.1
29
+ self.num_steps = 20
30
+ self.momentum = 0
31
+
32
+ self.function = self.DEFAULT_UNIVARIATE
33
+
34
+ self.initial_x = self.DEFAULT_INIT_X
35
+
36
+ self.trajectory_x, self.trajectory_y = get_optimizer_trajectory_1d(
37
+ self.DEFAULT_UNIVARIATE,
38
+ self.DEFAULT_INIT_X,
39
+ self.optimiser_type,
40
+ self.learning_rate,
41
+ self.momentum,
42
+ self.num_steps,
43
+ )
44
+
45
+ self.trajectory_idx = 0
46
+ self.plots = []
47
+ self.generate_plots()
48
+
49
+ def generate_plots(self):
50
+ self.plots.clear()
51
+
52
+ fig, ax = plt.subplots()
53
+
54
+ for idx in range(self.num_steps):
55
+ traj_x_min = np.min(self.trajectory_x[:idx + 1])
56
+ traj_x_max = np.max(self.trajectory_x[:idx + 1])
57
+ x_radius = np.maximum(np.abs(traj_x_min), np.abs(traj_x_max))
58
+
59
+ if x_radius > 1:
60
+ x = np.linspace(-1.2 * x_radius, 1.2 * x_radius, 100)
61
+ else:
62
+ x = np.linspace(-1, 1, 100)
63
+
64
+ try:
65
+ y = numexpr.evaluate(self.function, local_dict={'x': x})
66
+ except Exception as e:
67
+ logger.error("Error evaluating function '%s': %s", function, e)
68
+ y = np.zeros_like(x)
69
+
70
+ ax.clear()
71
+ ax.plot(x, y)
72
+ ax.set_xlabel("x")
73
+ ax.set_ylabel("f(x)")
74
+ ax.plot(self.trajectory_x[:idx + 1], self.trajectory_y[:idx + 1], marker='o', color='indianred')
75
+ ax.plot(self.trajectory_x[idx], self.trajectory_y[idx], marker='o', color='red')
76
+
77
+ buf = io.BytesIO()
78
+ fig.savefig(buf, format="png", bbox_inches="tight", pad_inches=0)
79
+ plt.close(fig)
80
+ buf.seek(0)
81
+ img = Image.open(buf)
82
+
83
+ # Append the generated plot to the list
84
+ self.plots.append(img)
85
+
86
+ def update_plot(self):
87
+ plot = self.plots[self.trajectory_idx]
88
+ self.univariate_plot = plot
89
+ return plot
90
+
91
+ def update_optimiser_type(self, optimiser_type):
92
+ self.optimiser_type = optimiser_type
93
+
94
+ def update_trajectory(self):
95
+ trajectory_x, trajectory_y = get_optimizer_trajectory_1d(
96
+ self.function,
97
+ self.initial_x,
98
+ self.optimiser_type,
99
+ self.learning_rate,
100
+ self.momentum,
101
+ self.num_steps,
102
+ )
103
+ self.trajectory_x = trajectory_x
104
+ self.trajectory_y = trajectory_y
105
+
106
+ def update_trajectory_slider(self, trajectory_idx):
107
+ self.trajectory_idx = trajectory_idx
108
+
109
+ def update_learning_rate(self, learning_rate):
110
+ self.learning_rate = learning_rate
111
+
112
+ def update_initial_x(self, initial_x):
113
+ self.initial_x = initial_x
114
+
115
+ def update_function(self, function):
116
+ self.function = function
117
+
118
+ def show_relevant_params(self, optimiser_type):
119
+ if optimiser_type == "Gradient Descent":
120
+ learning_rate = gr.update(visible=True)
121
+ hessian = gr.update(visible=False)
122
+ momentum = gr.update(visible=True)
123
+ else:
124
+ learning_rate = gr.update(visible=False)
125
+ hessian = gr.update(visible=True)
126
+ momentum = gr.update(visible=False)
127
+ return hessian, learning_rate, momentum
128
+
129
+ def handle_trajectory_change(self):
130
+ self.update_trajectory()
131
+ self.generate_plots()
132
+
133
+ self.handle_slider_change(0) # reset slider
134
+ self.update_plot()
135
+
136
+ def handle_optimiser_type_change(self, optimiser_type):
137
+ self.update_optimiser_type(optimiser_type)
138
+ self.handle_trajectory_change()
139
+ hessian_update, learning_rate_update, momentum_update = self.show_relevant_params(optimiser_type)
140
+ return self.trajectory_idx, hessian_update, learning_rate_update, momentum_update, self.univariate_plot
141
+
142
+ def handle_learning_rate_change(self, learning_rate):
143
+ self.update_learning_rate(learning_rate)
144
+ self.handle_trajectory_change()
145
+ return self.trajectory_idx, self.univariate_plot
146
+
147
+ def handle_momentum_change(self, momentum):
148
+ self.momentum = momentum
149
+ self.handle_trajectory_change()
150
+ return self.trajectory_idx, self.univariate_plot
151
+
152
+ def handle_slider_change(self, trajectory_idx):
153
+ self.update_trajectory_slider(trajectory_idx)
154
+ self.update_plot()
155
+ return self.univariate_plot
156
+
157
+ def handle_trajectory_button(self):
158
+ if self.trajectory_idx < self.num_steps - 1:
159
+ self.trajectory_idx += 1
160
+ # plot is updated from slider changing
161
+ return self.trajectory_idx
162
+
163
+ def handle_initial_x_change(self, initial_x):
164
+ self.update_initial_x(initial_x)
165
+ self.handle_trajectory_change()
166
+ return self.trajectory_idx, self.univariate_plot
167
+
168
+ def handle_function_change(self, function):
169
+ self.update_function(function)
170
+ self.handle_trajectory_change()
171
+ gradient = f"{get_gradient_1d(function)}"
172
+ hessian = f"{get_hessian_1d(function)}"
173
+ return self.trajectory_idx, gradient, hessian, self.univariate_plot
174
+
175
+ def reset(self):
176
+ self.optimiser_type = "Gradient Descent"
177
+ self.learning_rate = 0.1
178
+ self.num_steps = 20
179
+
180
+ self.function = self.DEFAULT_UNIVARIATE
181
+
182
+ self.initial_x = self.DEFAULT_INIT_X
183
+
184
+ self.trajectory_x, self.trajectory_y = get_optimizer_trajectory_1d(
185
+ self.DEFAULT_UNIVARIATE,
186
+ self.DEFAULT_INIT_X,
187
+ self.optimiser_type,
188
+ self.learning_rate,
189
+ self.momentum,
190
+ self.num_steps,
191
+ )
192
+
193
+ self.trajectory_idx = 0
194
+ self.plots = []
195
+ self.generate_plots()
196
+
197
+ def build(self):
198
+ with gr.Tab("Univariate"):
199
+ with gr.Row():
200
+ with gr.Column(scale=2):
201
+ self.univariate_plot = gr.Image(
202
+ value=self.update_plot(),
203
+ container=True,
204
+ )
205
+
206
+ with gr.Column(scale=1):
207
+ with gr.Tab("Settings"):
208
+ function = gr.Textbox(label="Function", value=self.DEFAULT_UNIVARIATE, interactive=True)
209
+ gradient = gr.Textbox(
210
+ label="Derivative",
211
+ value=f"{get_gradient_1d(self.DEFAULT_UNIVARIATE)}",
212
+ interactive=False,
213
+ )
214
+ hessian = gr.Textbox(
215
+ label="Second Derivative",
216
+ value=f"{get_hessian_1d(self.DEFAULT_UNIVARIATE)}",
217
+ interactive=False,
218
+ visible=False,
219
+ )
220
+
221
+ optimiser_type = gr.Dropdown(
222
+ label="Optimiser",
223
+ choices=["Gradient Descent", "Newton"],
224
+ value="Gradient Descent",
225
+ interactive=True,
226
+ )
227
+
228
+ initial_x = gr.Number(label="Initial X", value=self.DEFAULT_INIT_X, interactive=True)
229
+
230
+ with gr.Row():
231
+ learning_rate = gr.Number(label="Learning Rate", value=self.learning_rate, interactive=True)
232
+ momentum = gr.Number(label="Momentum", value=self.momentum, interactive=True)
233
+
234
+ with gr.Tab("Optimize"):
235
+ trajectory_slider = gr.Slider(
236
+ label="Optimisation Step",
237
+ minimum=0,
238
+ maximum=self.num_steps - 1,
239
+ step=1,
240
+ value=0,
241
+ interactive=True,
242
+ )
243
+
244
+ trajectory_button = gr.Button("Optimisation Step")
245
+
246
+ function.submit(self.handle_function_change, inputs=[function], outputs=[trajectory_slider, gradient, hessian, self.univariate_plot])
247
+
248
+ initial_x.submit(self.handle_initial_x_change, inputs=[initial_x], outputs=[trajectory_slider, self.univariate_plot])
249
+
250
+ learning_rate.submit(self.handle_learning_rate_change, inputs=[learning_rate], outputs=[trajectory_slider, self.univariate_plot])
251
+ momentum.submit(self.handle_momentum_change, inputs=[momentum], outputs=[trajectory_slider, self.univariate_plot])
252
+
253
+ optimiser_type.change(
254
+ self.handle_optimiser_type_change,
255
+ inputs=[optimiser_type],
256
+ outputs=[trajectory_slider, hessian, learning_rate, momentum, self.univariate_plot]
257
+ )
258
+
259
+ trajectory_slider.change(self.handle_slider_change, inputs=[trajectory_slider], outputs=[self.univariate_plot])
260
+ trajectory_button.click(self.handle_trajectory_button, outputs=[trajectory_slider])
261
+
old_code/usage.md ADDED
@@ -0,0 +1 @@
 
 
1
+ **Quick start**