Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import numpy as np | |
| import plotly.graph_objs as go | |
| def convex_function(x, y): | |
| return x**2 + y**2 | |
| def non_convex_function(x, y): | |
| return np.sin(x) * np.cos(y) * x * y | |
| def gradient_descent(func, grad_func, start, learning_rate, n_iter): | |
| path = [start] | |
| for _ in range(n_iter): | |
| grad = grad_func(path[-1]) | |
| next_point = path[-1] - learning_rate * grad | |
| path.append(next_point) | |
| return np.array(path) | |
| def stochastic_gradient_descent(func, grad_func, start, learning_rate, n_iter): | |
| path = [start] | |
| for _ in range(n_iter): | |
| grad = grad_func(path[-1]) + np.random.normal(0, 0.1, 2) | |
| next_point = path[-1] - learning_rate * grad | |
| path.append(next_point) | |
| return np.array(path) | |
| def grad_convex(point): | |
| x, y = point | |
| return np.array([2*x, 2*y]) | |
| def grad_non_convex(point): | |
| x, y = point | |
| return np.array([np.cos(x) * np.cos(y) * y + np.sin(x) * np.sin(y) * x, np.cos(x) * np.cos(y) * x - np.sin(x) * np.sin(y) * y]) | |
| def simulated_annealing(func, start, temp, cooling_rate, n_iter): | |
| path = [start] | |
| current_point = start | |
| lowest_point = current_point | |
| for i in range(n_iter): | |
| next_point = current_point + np.random.normal(0, 1, 2) | |
| delta_E = func(next_point[0], next_point[1]) - func(current_point[0], current_point[1]) | |
| if delta_E < 0 or np.exp(-delta_E / temp) > np.random.rand(): | |
| current_point = next_point | |
| if func(current_point[0], current_point[1]) < func(lowest_point[0], lowest_point[1]): | |
| lowest_point = current_point | |
| path.append(current_point) | |
| temp *= cooling_rate | |
| return np.array(path), lowest_point | |
| def plot_3d_surface(func, path, title, alphas=None, lowest_point=None): | |
| x_min, x_max = min(path[:, 0].min(), -6), max(path[:, 0].max(), 6) | |
| y_min, y_max = min(path[:, 1].min(), -6), max(path[:, 1].max(), 6) | |
| x = np.linspace(x_min, x_max, 200) | |
| y = np.linspace(y_min, y_max, 200) | |
| X, Y = np.meshgrid(x, y) | |
| Z = func(X, Y) | |
| fig = go.Figure(data=[go.Surface(z=Z, x=X, y=Y, opacity=0.7)]) | |
| if alphas is None: | |
| alphas = [1.0] * len(path) | |
| for i in range(len(path) - 1): | |
| fig.add_trace(go.Scatter3d( | |
| x=path[i:i+2, 0], | |
| y=path[i:i+2, 1], | |
| z=func(path[i:i+2, 0], path[i:i+2, 1]), | |
| mode='lines', | |
| line=dict(color='orange', width=4), | |
| opacity=alphas[i], | |
| showlegend=False | |
| )) | |
| fig.add_trace(go.Scatter3d( | |
| x=path[:, 0], | |
| y=path[:, 1], | |
| z=func(path[:, 0], path[:, 1]), | |
| mode='markers', | |
| marker=dict(size=4, color='orange', opacity=alphas[-1]), | |
| name='Path' | |
| )) | |
| fig.add_trace(go.Scatter3d( | |
| x=[path[0, 0]], | |
| y=[path[0, 1]], | |
| z=[func(path[0, 0], path[0, 1])], | |
| mode='markers', | |
| marker=dict(size=6, color='green', opacity=alphas[0]), | |
| name='Start' | |
| )) | |
| if lowest_point is not None: | |
| fig.add_trace(go.Scatter3d( | |
| x=[lowest_point[0]], | |
| y=[lowest_point[1]], | |
| z=[func(lowest_point[0], lowest_point[1])], | |
| mode='markers', | |
| marker=dict(size=6, color='red', opacity=alphas[-1]), | |
| name='Lowest Observed' | |
| )) | |
| fig.update_layout(title=title, scene=dict( | |
| xaxis_title='X', | |
| yaxis_title='Y', | |
| zaxis_title='Z')) | |
| return fig | |
| st.title("Convex and Non-Convex SGD Optimization") | |
| tab1, tab2, tab3 = st.tabs(["Gradient Descent", "Stochastic Gradient Descent", "Simulated Annealing"]) | |
| st.sidebar.header("Parameters") | |
| learning_rate = st.sidebar.slider("Learning Rate", 0.01, 1.0, 0.1) | |
| n_iter = st.sidebar.slider("Number of Iterations", 10, 100, 50) | |
| convex_start_x = st.sidebar.slider("Convex Start X", -3.0, 3.0, 2.5) | |
| convex_start_y = st.sidebar.slider("Convex Start Y", -3.0, 3.0, 2.5) | |
| non_convex_start_x = st.sidebar.slider("Non-Convex Start X", -3.0, 3.0, 2.5) | |
| non_convex_start_y = st.sidebar.slider("Non-Convex Start Y", -3.0, 3.0, 2.5) | |
| temp = st.sidebar.slider("Initial Temperature (Simulated Annealing)", 1.0, 10.0, 5.0) | |
| cooling_rate = st.sidebar.slider("Cooling Rate (Simulated Annealing)", 0.8, 0.99, 0.95) | |
| convex_start = np.array([convex_start_x, convex_start_y]) | |
| non_convex_start = np.array([non_convex_start_x, non_convex_start_y]) | |
| with tab1: | |
| st.header("Gradient Descent") | |
| st.write("Visualizing gradient descent on convex and non-convex functions.") | |
| with st.expander("Gradient Descent Algorithm and Math"): | |
| st.markdown(r""" | |
| ### Gradient Descent Algorithm | |
| **Step-by-step Algorithm**: | |
| 1. Initialize starting point $\mathbf{x}_0$. | |
| 2. For each iteration $t$: | |
| - Compute the gradient $\nabla f(\mathbf{x}_t)$. | |
| - Update the current point: $\mathbf{x}_{t+1} = \mathbf{x}_t - \alpha \nabla f(\mathbf{x}_t)$. | |
| **Mathematical Formulation**: | |
| $$ | |
| \mathbf{x}_{t+1} = \mathbf{x}_t - \alpha \nabla f(\mathbf{x}_t) | |
| $$ | |
| where: | |
| - $\mathbf{x}_t$ is the current point. | |
| - $\alpha$ is the learning rate. | |
| - $\nabla f(\mathbf{x}_t)$ is the gradient of the function at $\mathbf{x}_t$. | |
| """) | |
| convex_path_gd = gradient_descent(convex_function, grad_convex, convex_start, learning_rate, n_iter) | |
| non_convex_path_gd = gradient_descent(non_convex_function, grad_non_convex, non_convex_start, learning_rate, n_iter) | |
| st.plotly_chart(plot_3d_surface(convex_function, convex_path_gd, "Convex Function (GD)")) | |
| st.plotly_chart(plot_3d_surface(non_convex_function, non_convex_path_gd, "Non-Convex Function (GD)")) | |
| with tab2: | |
| st.header("Stochastic Gradient Descent") | |
| st.write("Visualizing stochastic gradient descent on convex and non-convex functions.") | |
| with st.expander("Stochastic Gradient Descent Algorithm and Math"): | |
| st.markdown(r""" | |
| ### Stochastic Gradient Descent Algorithm | |
| **Step-by-step Algorithm**: | |
| 1. Initialize starting point $\mathbf{x}_0$. | |
| 2. For each iteration $t$: | |
| - Compute a stochastic approximation of the gradient $\nabla f(\mathbf{x}_t) + \text{noise}$. | |
| - Update the current point: $\mathbf{x}_{t+1} = \mathbf{x}_t - \alpha \left(\nabla f(\mathbf{x}_t) + \text{noise}\right)$. | |
| **Mathematical Formulation**: | |
| $$ | |
| \mathbf{x}_{t+1} = \mathbf{x}_t - \alpha \left(\nabla f(\mathbf{x}_t) + \text{noise}\right) | |
| $$ | |
| where: | |
| - $\mathbf{x}_t$ is the current point. | |
| - $\alpha$ is the learning rate. | |
| - $\nabla f(\mathbf{x}_t)$ is the gradient of the function at $\mathbf{x}_t$. | |
| - $\text{noise}$ is a small random perturbation. | |
| """) | |
| convex_path_sgd = stochastic_gradient_descent(convex_function, grad_convex, convex_start, learning_rate, n_iter) | |
| non_convex_path_sgd = stochastic_gradient_descent(non_convex_function, grad_non_convex, non_convex_start, learning_rate, n_iter) | |
| st.plotly_chart(plot_3d_surface(convex_function, convex_path_sgd, "Convex Function (SGD)")) | |
| st.plotly_chart(plot_3d_surface(non_convex_function, non_convex_path_sgd, "Non-Convex Function (SGD)")) | |
| with tab3: | |
| st.header("Simulated Annealing") | |
| st.write("Visualizing simulated annealing on a non-convex function.") | |
| with st.expander("Simulated Annealing Algorithm and Math"): | |
| st.markdown(r""" | |
| ### Simulated Annealing Algorithm | |
| **Step-by-step Algorithm**: | |
| 1. Initialize starting point $\mathbf{x}_0$ and temperature $T$. | |
| 2. For each iteration $t$: | |
| - Generate a new point $\mathbf{x}'$ in the neighborhood of the current point $\mathbf{x}_t$. | |
| - Compute the change in function value $\Delta E = f(\mathbf{x}') - f(\mathbf{x}_t)$. | |
| - If $\Delta E < 0$, accept the new point $\mathbf{x}_{t+1} = \mathbf{x}'$. | |
| - If $\Delta E \geq 0$, accept the new point with a probability $\exp\left(\frac{-\Delta E}{T}\right)$. | |
| - Update the temperature $T$. | |
| **Mathematical Formulation**: | |
| $$ | |
| \mathbf{x}_{t+1} = | |
| \begin{cases} | |
| \mathbf{x}' & \text{if } \Delta E < 0 \\ | |
| \mathbf{x}' & \text{with probability } \exp\left(\frac{-\Delta E}{T}\right) \text{ if } \Delta E \geq 0 \\ | |
| \mathbf{x}_t & \text{otherwise} | |
| \end{cases} | |
| $$ | |
| where: | |
| - $\mathbf{x}_t$ is the current point. | |
| - $\mathbf{x}'$ is the new point. | |
| - $T$ is the temperature. | |
| - $\Delta E = f(\mathbf{x}') - f(\mathbf{x}_t)$ is the change in function value. | |
| - $\exp\left(\frac{-\Delta E}{T}\right)$ is the acceptance probability. | |
| """) | |
| non_convex_path_sa, lowest_point = simulated_annealing(non_convex_function, non_convex_start, temp, cooling_rate, n_iter) | |
| # Visualizing the path with alpha changing based on iteration | |
| alphas = np.linspace(0.1, 1, len(non_convex_path_sa)) | |
| fig_sa = plot_3d_surface(non_convex_function, non_convex_path_sa, "Non-Convex Function (SA)", alphas=alphas, lowest_point=lowest_point) | |
| # Adding blue points for other iteration's observed minimums | |
| other_mins = non_convex_path_sa[:-1] | |
| fig_sa.add_trace(go.Scatter3d( | |
| x=other_mins[:, 0], | |
| y=other_mins[:, 1], | |
| z=non_convex_function(other_mins[:, 0], other_mins[:, 1]), | |
| mode='markers', | |
| marker=dict(size=4, color='blue'), | |
| name='Observed Minima' | |
| )) | |
| # Adding the final minimum point in red | |
| fig_sa.add_trace(go.Scatter3d( | |
| x=[lowest_point[0]], | |
| y=[lowest_point[1]], | |
| z=[non_convex_function(lowest_point[0], lowest_point[1])], | |
| mode='markers', | |
| marker=dict(size=6, color='red'), | |
| name='Lowest Observed' | |
| )) | |
| # Adding the starting point in green | |
| fig_sa.add_trace(go.Scatter3d( | |
| x=[non_convex_path_sa[0, 0]], | |
| y=[non_convex_path_sa[0, 1]], | |
| z=[non_convex_function(non_convex_path_sa[0, 0], non_convex_path_sa[0, 1])], | |
| mode='markers', | |
| marker=dict(size=6, color='green'), | |
| name='Start' | |
| )) | |
| st.plotly_chart(fig_sa) |