Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -0,0 +1,125 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Import required libraries
|
| 2 |
+
import numpy as np
|
| 3 |
+
import matplotlib.pyplot as plt
|
| 4 |
+
import streamlit as st
|
| 5 |
+
import sympy as sp
|
| 6 |
+
|
| 7 |
+
# Functions and their derivatives
|
| 8 |
+
def square(x):
|
| 9 |
+
return x**2
|
| 10 |
+
|
| 11 |
+
def derivative_square(x):
|
| 12 |
+
return 2*x
|
| 13 |
+
|
| 14 |
+
def cube(x):
|
| 15 |
+
return x**3
|
| 16 |
+
|
| 17 |
+
def derivative_cube(x):
|
| 18 |
+
return 3 * x**2
|
| 19 |
+
|
| 20 |
+
def sin(x):
|
| 21 |
+
return np.sin(x)
|
| 22 |
+
|
| 23 |
+
def derivative_sin(x):
|
| 24 |
+
return np.cos(x)
|
| 25 |
+
|
| 26 |
+
def inverse(x):
|
| 27 |
+
return 1/x
|
| 28 |
+
|
| 29 |
+
def derivative_inverse(x):
|
| 30 |
+
return - (1 / x **2)
|
| 31 |
+
|
| 32 |
+
def poly(x):
|
| 33 |
+
return x + 2 * (x**2) + (0.4) * x**3
|
| 34 |
+
|
| 35 |
+
def derivative_poly(x):
|
| 36 |
+
return 1 + 4 * x + 1.2 * x**2
|
| 37 |
+
|
| 38 |
+
# Function to calculate the derivative
|
| 39 |
+
def calculate_derivative(func_str):
|
| 40 |
+
x = sp.symbols('x')
|
| 41 |
+
try:
|
| 42 |
+
# Parse the function string into a sympy expression
|
| 43 |
+
func = sp.sympify(func_str)
|
| 44 |
+
# Calculate the derivative
|
| 45 |
+
derivative = sp.diff(func, x)
|
| 46 |
+
return func, derivative
|
| 47 |
+
except sp.SympifyError:
|
| 48 |
+
return None, None
|
| 49 |
+
|
| 50 |
+
# Title
|
| 51 |
+
st.title('Gradient Descent Visualizer')
|
| 52 |
+
st.sidebar.title("It's your turn..")
|
| 53 |
+
|
| 54 |
+
# User input
|
| 55 |
+
function = st.sidebar.selectbox('Pre Defined Functions', ['Square', 'Cube', 'Polynomial', 'sin', '1/x', 'None'])
|
| 56 |
+
starting_point = st.sidebar.number_input('Starting Point', value=5, step=1)
|
| 57 |
+
learning_rate = st.sidebar.number_input('Learning Rate', value=0.1, step=0.01)
|
| 58 |
+
|
| 59 |
+
# Define the selected function and its derivative
|
| 60 |
+
if function == 'Square':
|
| 61 |
+
func = square
|
| 62 |
+
derivative_func = derivative_square
|
| 63 |
+
elif function == 'Cube':
|
| 64 |
+
func = cube
|
| 65 |
+
derivative_func = derivative_cube
|
| 66 |
+
elif function == 'Polynomial':
|
| 67 |
+
func = poly
|
| 68 |
+
derivative_func = derivative_poly
|
| 69 |
+
elif function == 'sin':
|
| 70 |
+
func = sin
|
| 71 |
+
derivative_func = derivative_sin
|
| 72 |
+
elif function == '1/x':
|
| 73 |
+
func = inverse
|
| 74 |
+
derivative_func = derivative_inverse
|
| 75 |
+
elif function == 'None':
|
| 76 |
+
user_func = st.text_input("Enter a function: ")
|
| 77 |
+
func, derivative = calculate_derivative(user_func)
|
| 78 |
+
|
| 79 |
+
# Check if the starting point has changed
|
| 80 |
+
if 'last_starting_point' not in st.session_state or st.session_state.last_starting_point != starting_point:
|
| 81 |
+
st.session_state.path = [starting_point]
|
| 82 |
+
st.session_state.iteration = 0
|
| 83 |
+
st.session_state.last_starting_point = starting_point
|
| 84 |
+
|
| 85 |
+
# Perform one iteration of gradient descent
|
| 86 |
+
if st.sidebar.button('Next Iteration'):
|
| 87 |
+
current_point = st.session_state.path[-1]
|
| 88 |
+
new_point = current_point - learning_rate * derivative_func(current_point)
|
| 89 |
+
st.session_state.path.append(new_point)
|
| 90 |
+
st.session_state.iteration += 1
|
| 91 |
+
|
| 92 |
+
# Create an array of values for plotting
|
| 93 |
+
x_values = np.linspace(-10, 10, 500)
|
| 94 |
+
y_values = func(x_values)
|
| 95 |
+
|
| 96 |
+
# Dynamic scaling based on the function's range
|
| 97 |
+
y_min, y_max = np.min(y_values), np.max(y_values)
|
| 98 |
+
y_padding = (y_max - y_min) * 0.1
|
| 99 |
+
|
| 100 |
+
# Plot the function and the path of points
|
| 101 |
+
plt.figure(figsize=(8, 6))
|
| 102 |
+
plt.plot(x_values, y_values, label=function, color='blue')
|
| 103 |
+
plt.scatter(st.session_state.path, [func(x) for x in st.session_state.path], color='red', zorder=5)
|
| 104 |
+
|
| 105 |
+
# Calculate and plot the tangent line
|
| 106 |
+
current_point = st.session_state.path[-1]
|
| 107 |
+
slope = derivative_func(current_point)
|
| 108 |
+
y_tangent = slope * (x_values - current_point) + func(current_point)
|
| 109 |
+
plt.plot(x_values, y_tangent, '--', color='red')
|
| 110 |
+
|
| 111 |
+
# Set plot limits dynamically
|
| 112 |
+
plt.xlim([-10, 10])
|
| 113 |
+
plt.ylim([y_min - y_padding, y_max + y_padding])
|
| 114 |
+
|
| 115 |
+
# Display the iteration number
|
| 116 |
+
plt.title(f'Iteration: {st.session_state.iteration}')
|
| 117 |
+
|
| 118 |
+
# Labels and legend
|
| 119 |
+
plt.xlabel('x')
|
| 120 |
+
plt.ylabel('y')
|
| 121 |
+
plt.legend()
|
| 122 |
+
plt.grid(True)
|
| 123 |
+
|
| 124 |
+
# Display the plot
|
| 125 |
+
st.pyplot(plt)
|