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('