Download utils/visualization.py from ravimohan19/physics-informed-bayesian-optimization: direct link, hf CLI and curl.
- Browser
- Download file 6.28 kB
-
https://huggingface.co/spaces/ravimohan19/physics-informed-bayesian-optimization/resolve/main/utils/visualization.py
- Command line
-
hf download hf://spaces/ravimohan19/physics-informed-bayesian-optimization/utils/visualization.py
-
curl -L -o visualization.py https://huggingface.co/spaces/ravimohan19/physics-informed-bayesian-optimization/resolve/main/utils/visualization.py
6.28 kB
| """Visualization utilities for physics-informed Bayesian optimization.""" | |
| from typing import Callable, Dict, List, Optional, Tuple | |
| import torch | |
| from torch import Tensor | |
| import numpy as np | |
| def plot_convergence( | |
| campaign_df, | |
| maximize: bool = True, | |
| title: str = "Optimization Convergence", | |
| figsize: Tuple[int, int] = (10, 6), | |
| ): | |
| """Plot the optimization convergence curve. | |
| Args: | |
| campaign_df: DataFrame from OptimizationCampaign.to_dataframe(). | |
| maximize: Whether the objective is being maximized. | |
| title: Plot title. | |
| figsize: Figure size. | |
| Returns: | |
| matplotlib Figure. | |
| """ | |
| import matplotlib.pyplot as plt | |
| fig, (ax1, ax2) = plt.subplots(1, 2, figsize=figsize) | |
| objectives = campaign_df["objective"].values | |
| # Left: all observations | |
| ax1.plot(range(len(objectives)), objectives, "o-", alpha=0.6, markersize=4) | |
| ax1.set_xlabel("Experiment Number") | |
| ax1.set_ylabel("Objective") | |
| ax1.set_title("All Observations") | |
| ax1.grid(True, alpha=0.3) | |
| # Right: best-so-far | |
| if maximize: | |
| best_so_far = np.maximum.accumulate(objectives) | |
| else: | |
| best_so_far = np.minimum.accumulate(objectives) | |
| ax2.plot(range(len(best_so_far)), best_so_far, "s-", color="green", markersize=4) | |
| ax2.set_xlabel("Experiment Number") | |
| ax2.set_ylabel("Best Objective") | |
| ax2.set_title("Best So Far") | |
| ax2.grid(True, alpha=0.3) | |
| fig.suptitle(title, fontsize=14) | |
| plt.tight_layout() | |
| return fig | |
| def plot_surrogate_1d( | |
| surrogate, | |
| bounds: Tuple[float, float], | |
| X_observed: Optional[Tensor] = None, | |
| y_observed: Optional[Tensor] = None, | |
| physics_fn: Optional[Callable] = None, | |
| true_fn: Optional[Callable] = None, | |
| n_grid: int = 200, | |
| title: str = "Surrogate Model", | |
| figsize: Tuple[int, int] = (10, 6), | |
| ): | |
| """Plot a 1D surrogate model with confidence intervals. | |
| Args: | |
| surrogate: A SurrogateModel instance. | |
| bounds: (lower, upper) for the 1D input. | |
| X_observed: Observed inputs (n, 1). | |
| y_observed: Observed outputs (n, 1). | |
| physics_fn: Optional physics model for comparison. | |
| true_fn: Optional true function for comparison. | |
| n_grid: Number of grid points. | |
| title: Plot title. | |
| figsize: Figure size. | |
| Returns: | |
| matplotlib Figure. | |
| """ | |
| import matplotlib.pyplot as plt | |
| fig, ax = plt.subplots(figsize=figsize) | |
| X_grid = torch.linspace(bounds[0], bounds[1], n_grid).unsqueeze(-1).to(torch.float64) | |
| mean, var = surrogate.predict(X_grid) | |
| std = var.sqrt() | |
| x_np = X_grid.squeeze().numpy() | |
| mean_np = mean.squeeze().detach().numpy() | |
| std_np = std.squeeze().detach().numpy() | |
| # Surrogate prediction | |
| ax.plot(x_np, mean_np, "b-", label="Surrogate Mean", linewidth=2) | |
| ax.fill_between( | |
| x_np, | |
| mean_np - 2 * std_np, | |
| mean_np + 2 * std_np, | |
| alpha=0.2, | |
| color="blue", | |
| label="95% CI", | |
| ) | |
| # Physics model | |
| if physics_fn is not None: | |
| with torch.no_grad(): | |
| physics_pred = physics_fn(X_grid).squeeze().numpy() | |
| ax.plot(x_np, physics_pred, "r--", label="Physics Model", linewidth=1.5) | |
| # True function | |
| if true_fn is not None: | |
| with torch.no_grad(): | |
| true_pred = true_fn(X_grid).squeeze().numpy() | |
| ax.plot(x_np, true_pred, "k-", label="True Function", linewidth=1.5, alpha=0.7) | |
| # Observations | |
| if X_observed is not None and y_observed is not None: | |
| ax.scatter( | |
| X_observed.squeeze().numpy(), | |
| y_observed.squeeze().numpy(), | |
| c="red", | |
| s=50, | |
| zorder=5, | |
| label="Observations", | |
| edgecolors="black", | |
| ) | |
| ax.set_xlabel("Input") | |
| ax.set_ylabel("Output") | |
| ax.set_title(title) | |
| ax.legend() | |
| ax.grid(True, alpha=0.3) | |
| plt.tight_layout() | |
| return fig | |
| def plot_surrogate_2d( | |
| surrogate, | |
| bounds: Tensor, | |
| param_names: Tuple[str, str] = ("x1", "x2"), | |
| X_observed: Optional[Tensor] = None, | |
| n_grid: int = 50, | |
| title: str = "Surrogate Model (2D)", | |
| figsize: Tuple[int, int] = (12, 5), | |
| ): | |
| """Plot 2D surrogate model as contour plots (mean and uncertainty). | |
| Args: | |
| surrogate: A SurrogateModel instance. | |
| bounds: Tensor of shape (2, 2) with [lower, upper] bounds. | |
| param_names: Names of the two parameters. | |
| X_observed: Observed inputs (n, 2). | |
| n_grid: Grid resolution per dimension. | |
| title: Plot title. | |
| figsize: Figure size. | |
| Returns: | |
| matplotlib Figure. | |
| """ | |
| import matplotlib.pyplot as plt | |
| x1 = torch.linspace(float(bounds[0, 0]), float(bounds[1, 0]), n_grid) | |
| x2 = torch.linspace(float(bounds[0, 1]), float(bounds[1, 1]), n_grid) | |
| X1, X2 = torch.meshgrid(x1, x2, indexing="ij") | |
| X_grid = torch.stack([X1.flatten(), X2.flatten()], dim=-1).to(torch.float64) | |
| mean, var = surrogate.predict(X_grid) | |
| mean_2d = mean.squeeze().reshape(n_grid, n_grid).detach().numpy() | |
| std_2d = var.sqrt().squeeze().reshape(n_grid, n_grid).detach().numpy() | |
| fig, (ax1, ax2) = plt.subplots(1, 2, figsize=figsize) | |
| # Mean | |
| c1 = ax1.contourf( | |
| X1.numpy(), X2.numpy(), mean_2d, levels=20, cmap="viridis" | |
| ) | |
| plt.colorbar(c1, ax=ax1) | |
| ax1.set_xlabel(param_names[0]) | |
| ax1.set_ylabel(param_names[1]) | |
| ax1.set_title("Predicted Mean") | |
| # Uncertainty | |
| c2 = ax2.contourf( | |
| X1.numpy(), X2.numpy(), std_2d, levels=20, cmap="plasma" | |
| ) | |
| plt.colorbar(c2, ax=ax2) | |
| ax2.set_xlabel(param_names[0]) | |
| ax2.set_ylabel(param_names[1]) | |
| ax2.set_title("Predicted Std Dev") | |
| # Overlay observations | |
| if X_observed is not None: | |
| for ax in [ax1, ax2]: | |
| ax.scatter( | |
| X_observed[:, 0].numpy(), | |
| X_observed[:, 1].numpy(), | |
| c="red", | |
| s=30, | |
| edgecolors="white", | |
| zorder=5, | |
| ) | |
| fig.suptitle(title, fontsize=14) | |
| plt.tight_layout() | |
| return fig | |