Spaces:
Sleeping
Sleeping
File size: 9,905 Bytes
5a1d76f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 | import numpy as np
import matplotlib.pyplot as plt
import gradio as gr
def plot_secant(h):
x = np.linspace(-1, 2, 400)
y = x**2
m = (h**2) / h
fig, axs = plt.subplots(1, 2, figsize=(8, 4))
for ax in axs:
ax.set_xlim(-1, 2)
ax.set_ylim(-1, 4)
ax.set_xticks(np.arange(-1, 3, 1))
ax.set_yticks(np.arange(-1, 5, 1))
ax.grid(True, linestyle='--', linewidth=0.5, color='lightgray')
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
axs[0].plot(x, y, color='black')
axs[0].plot([0, h], [0, h**2], color='red', linewidth=2)
axs[0].scatter([0, h], [0, h**2], color='red', zorder=5)
axs[1].plot(x, m * x, color='red', linewidth=2)
plt.tight_layout()
return fig
def plot_tangent(x0):
x = np.linspace(-1, 2, 400)
y = x**2
m = 2 * x0
y0 = x0**2
fig, axs = plt.subplots(1, 2, figsize=(8, 4))
for ax in axs:
ax.set_xlim(-1, 2)
ax.set_ylim(-1, 4)
ax.set_xticks(np.arange(-1, 3, 1))
ax.set_yticks(np.arange(-1, 5, 1))
ax.grid(True, linestyle='--', linewidth=0.5, color='lightgray')
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
axs[0].plot(x, y, color='black')
axs[0].plot(x, m * (x - x0) + y0, color='red', linewidth=2)
axs[0].scatter([x0], [y0], color='red', zorder=5)
axs[1].plot(x, 2 * x, color='black')
axs[1].scatter([x0], [m], color='red', zorder=5)
plt.tight_layout()
return fig
def plot_gradient_descent(lr, init_x, steps):
n = int(steps)
path = [init_x]
for _ in range(n):
path.append(path[-1] - lr * 2 * path[-1])
xv = np.array(path)
fig, axs = plt.subplots(1, 2, figsize=(8, 4))
x_plot = np.linspace(-2, 2, 400)
axs[0].plot(x_plot, x_plot**2, color='black')
axs[0].plot(xv, xv**2, marker='o', color='red', linewidth=2)
for i in range(n):
axs[0].annotate('', xy=(xv[i+1], xv[i+1]**2), xytext=(xv[i], xv[i]**2), arrowprops=dict(arrowstyle='->', color='red'))
axs[0].set_xlim(-2, 2)
axs[0].set_ylim(-0.5, 5)
axs[0].set_title('Gradient Descent Path')
axs[0].grid(True, linestyle='--', linewidth=0.5, color='lightgray')
axs[1].plot(range(n+1), xv, marker='o', color='red', linewidth=2)
for i in range(n):
axs[1].annotate('', xy=(i+1, xv[i+1]), xytext=(i, xv[i]), arrowprops=dict(arrowstyle='->', color='red'))
axs[1].set_xlim(0, n)
axs[1].set_ylim(xv.min() - 0.5, xv.max() + 0.5)
axs[1].set_xticks(range(0, n+1, max(1, n//5)))
axs[1].set_xlabel('Iteration')
axs[1].set_title('x over Iterations')
axs[1].grid(True, linestyle='--', linewidth=0.5, color='lightgray')
plt.tight_layout()
return fig
def plot_chain_network(x):
y = 2 * x
z = 3 * y
L = 4 * z
fig, ax = plt.subplots(figsize=(6, 2))
ax.axis('off')
pos = {'x': 0.1, 'y': 0.3, 'z': 0.5, 'L': 0.7}
for name in pos:
ax.add_patch(plt.Circle((pos[name], 0.5), 0.05, fill=False))
ax.text(pos[name], 0.5, name, ha='center', va='center')
for src, dst, lbl in [
('x', 'y', r'$\partial y/\partial x=2$'),
('y', 'z', r'$\partial z/\partial y=3$'),
('z', 'L', r'$\partial L/\partial z=4$')
]:
sx, dx = pos[src], pos[dst]
ax.annotate('', xy=(dx, 0.5), xytext=(sx, 0.5), arrowprops=dict(arrowstyle='->'))
ax.text((sx + dx)/2, 0.6, lbl, ha='center', va='center')
ax.text(0.02, 0.15, r'$\frac{\partial L}{\partial x}=4\times3\times2$', transform=ax.transAxes, ha='left')
for name, val in [('x', x), ('y', y), ('z', z), ('L', L)]:
ax.text(pos[name], 0.3, f"{name}={val:.2f}", ha='center')
plt.tight_layout()
return fig
def plot_backprop_dnn(x, w1, w2, t):
a = w1 * x
y = w2 * a
L = 0.5 * (y - t)**2
fig, ax = plt.subplots(figsize=(6, 2))
ax.axis('off')
pos = {'x': 0.1, 'a': 0.3, 'y': 0.5, 'L': 0.7}
for name in pos:
ax.add_patch(plt.Circle((pos[name], 0.5), 0.05, fill=False))
ax.text(pos[name], 0.5, name, ha='center', va='center')
for src, dst, lbl in [
('x', 'a', '∂a/∂x = w₁'),
('a', 'y', '∂y/∂a = w₂'),
('y', 'L', '∂L/∂y = (y - t)')
]:
sx, dx = pos[src], pos[dst]
ax.annotate('', xy=(dx, 0.5), xytext=(sx, 0.5), arrowprops=dict(arrowstyle='->'))
ax.text((sx + dx)/2, 0.6, lbl, ha='center', va='center')
ax.text(0.02, 0.15, '∂L/∂w₂ = (y - t) · a', transform=ax.transAxes, ha='left')
ax.text(0.02, 0.02, '∂L/∂w₁ = (y - t) · w₂ · x', transform=ax.transAxes, ha='left')
plt.tight_layout()
return fig
def update_secant(h): return plot_secant(h), f'**Δx=h={h:.4f}**, slope={(h**2)/h:.4f}'
def update_tangent(x0): return plot_tangent(x0), f'**x={x0:.2f}**, dy/dx={2*x0:.2f}'
def update_gd(lr, init_x, steps): return plot_gradient_descent(lr, init_x, steps), f'lr={lr:.2f}, init={init_x:.2f}, steps={int(steps)}'
def update_chain(x): return plot_chain_network(x), f"**Values:** y={2*x:.2f}, z={3*(2*x):.2f}, L={4*(3*(2*x)):.2f}\n**dL/dx=24**"
def update_bp(x, w1, w2, t): return plot_backprop_dnn(x, w1, w2, t), ''
def load_secant(): return plot_secant(0.01), '**Hint:** try moving the slider!'
def load_tangent(): return plot_tangent(0.0), '**Hint:** try moving the slider!'
def load_gd(): return plot_gradient_descent(0.1, 1.0, 10), '**Hint:** try moving the sliders!'
def load_chain(): return plot_chain_network(1.0), '**Hint:** try moving the slider!'
def load_bp(): return plot_backprop_dnn(0.5, 1.0, 1.0, 0.0), '**Hint:** try moving the sliders!'
def reset_all(): return (
gr.update(value=0.01), gr.update(value=0.0), gr.update(value=0.1),
gr.update(value=1.0), gr.update(value=10),
gr.update(value=1.0), gr.update(value=0.5), gr.update(value=1.0),
gr.update(value=1.0), gr.update(value=0.0)
)
demo = gr.Blocks()
with demo:
gr.HTML('<div style="border:1px solid lightgray; padding:10px; border-radius:5px">')
with gr.Tabs():
with gr.TabItem('Secant Approximation'):
gr.Markdown('''
**Feature:** Explore secant line approximations via Δx/h
- Draws a chord between (x, x²) and (x+h, (x+h)²)
- As h → 0, the chord converges to the true tangent
- Goal: See how (f(x+h)-f(x)) / h approaches the instantaneous derivative
''')
h = gr.Slider(0.001, 1.0, value=0.01, step=0.001, label='h')
p1 = gr.Plot()
m1 = gr.Markdown()
h.change(update_secant, [h], [p1, m1])
with gr.TabItem('Tangent Visualization'):
gr.Markdown('''
**Feature:** Visualize tangent line and instantaneous slope
- Draws the exact tangent at (x, x²)
- Slide x to update both the red line and its numeric slope
- Goal: Grasp the derivative as the “best‐fit” rate of change at one point
''')
x0 = gr.Slider(-1.0, 2.0, value=0.0, step=0.1, label='x')
p2 = gr.Plot()
m2 = gr.Markdown()
x0.change(update_tangent, [x0], [p2, m2])
with gr.TabItem('Gradient Descent'):
gr.Markdown('''
**Feature:** Observe gradient descent on y=x²
- Treats the curve as a valley; you take downhill steps
- Left: path on the curve with arrows; Right: x vs. iteration
- Goal: Feel how step size (learning rate) affects speed and stability toward the minimum
''')
lr = gr.Slider(0.01, 0.5, value=0.1, step=0.01, label='Learning Rate')
init = gr.Slider(-2.0, 2.0, value=1.0, step=0.1, label='Initial x')
st = gr.Slider(1, 50, value=10, step=1, label='Iterations')
pg = gr.Plot()
mg = gr.Markdown()
for inp in [lr, init, st]: inp.change(update_gd, [lr, init, st], [pg, mg])
with gr.TabItem('Chain Rule'):
gr.Markdown('''
**Feature:** Demonstrate the chain rule via a computation graph
- Nodes: x → y=2x → z=3y → L=4z with arrows showing ∂→
- Multiply local slopes 2 × 3 × 4 = 24 for overall dL/dx
- Goal: Visualize why and how partial derivatives combine to yield the total derivative
''')
xs = gr.Slider(0.0, 2.0, value=1.0, step=0.1, label='x')
cp = gr.Plot()
cm = gr.Markdown()
xs.change(update_chain, [xs], [cp, cm])
with gr.TabItem('Backpropagation'):
gr.Markdown('''
**Feature:** Visualize backpropagation derivatives in a simple DNN
- Network: x → a=w₁x → y=w₂a → L=½(y–t)² with local ∂ annotations
- Tweak x, w₁, w₂, or t and watch error gradients flow backward
- Goal: Demystify how output error propagates to compute each weight’s gradient
''')
xb = gr.Slider(-2.0, 2.0, value=0.5, step=0.1, label='x')
w1b = gr.Slider(-2.0, 2.0, value=1.0, step=0.1, label='w1')
w2b = gr.Slider(-2.0, 2.0, value=1.0, step=0.1, label='w2')
tb = gr.Slider(-2.0, 2.0, value=0.0, step=0.1, label='t')
pb = gr.Plot()
mb = gr.Markdown()
for inp in [xb, w1b, w2b, tb]: inp.change(update_bp, [xb, w1b, w2b, tb], [pb, mb])
demo.load(load_secant, [], [p1, m1])
demo.load(load_tangent, [], [p2, m2])
demo.load(load_gd, [], [pg, mg])
demo.load(load_chain, [], [cp, cm])
demo.load(load_bp, [], [pb, mb])
with gr.Row():
reset_btn = gr.Button('Reset to default settings')
gr.HTML("<span style='cursor:help' title='Reset all sliders to defaults.'></span>")
reset_btn.click(reset_all, [], [h, x0, lr, init, st, xs, xb, w1b, w2b, tb])
gr.HTML('</div>')
demo.launch() |