Learning the posterior p(structure | spectrum) for multilayer thin-film stacks
Krish Garg, B.Tech Engineering Physics, IIT Roorkee PHC-300 Course Project — Supervisor: Prof. Anirban Mitra
Inverse photonic design — finding a multilayer structure that produces a target reflectance spectrum — is fundamentally ill-posed: many structurally distinct designs can realize the same optical response. Classical optimization methods (L-BFGS, Differential Evolution) find a single solution, discarding the rich solution manifold. We frame inverse design as posterior inference p(structure | spectrum) and compare three generative modeling approaches: conditional variational autoencoders (cVAE), conditional normalizing flows (CNF), and conditional denoising diffusion probabilistic models (DDPM). We introduce a hybrid pipeline combining generative sampling with local L-BFGS refinement, achieving accuracy that matches or exceeds Differential Evolution (MSE = 1.15e-05 vs 3.14e-05) while producing diverse solutions 44x faster. We evaluate all methods on a 50,000-sample dataset of 5-layer stacks using spectral MSE, best-of-N scaling, MMD, coverage/precision, classifier-free guidance sweeps, and solution degeneracy analysis.
| Method | Best-of-N MSE | Diversity | Coverage | Time (s) |
|---|---|---|---|---|
| Tandem (MLP) | 2.86e-02 | 0 | 0.135 | 18 |
| cVAE | 4.66e-03 | 0.63 | 0.712 | 17 |
| CNF (RealNVP) | 4.87e-03 | 1.12 | 0.771 | 18 |
| DDPM | 4.44e-03 | 1.09 | 0.740 | 824 |
| cVAE + Refinement | 1.15e-05 | 0.63 | — | 123 |
| DDPM + Refinement | 2.85e-05 | 1.09 | — | 314 |
| L-BFGS (20 restarts) | 3.31e-04 | 0 | — | 345 |
| Differential Evolution | 3.14e-05 | 0 | — | 5439 |
Central finding: Generative models provide diverse initializations that, when locally refined, converge to multiple distinct high-quality solutions — achieving both the accuracy of global optimizers and the diversity of generative sampling, in a fraction of the time.
inverse_photonic_design/
├── configs/default.yaml # All hyperparameters
├── scripts/
│ ├── run_pipeline.py # Full end-to-end pipeline
│ └── train.py # Training routines (4 models)
├── src/
│ ├── physics/
│ │ ├── tmm.py # Transfer Matrix Method (vectorized)
│ │ └── materials.py # Material database
│ ├── models/
│ │ ├── common.py # Shared components (ResidualBlock, etc.)
│ │ ├── cvae.py # Conditional VAE with free bits
│ │ ├── cnf.py # Conditional Normalizing Flow (RealNVP)
│ │ ├── diffusion.py # Conditional DDPM + DDIM + CFG
│ │ └── tandem.py # Deterministic MLP baseline
│ ├── baselines/
│ │ ├── optimization.py # L-BFGS-B, Differential Evolution
│ │ └── refinement.py # Post-hoc L-BFGS refinement
│ ├── data/generator.py # Dataset generation
│ ├── evaluation/metrics.py # MMD, coverage, precision, degeneracy
│ └── visualization/plots.py # All figure generation
└── tests/test_tmm.py # 10 physics validation tests
The Transfer Matrix Method (TMM) computes reflectance spectra for arbitrary multilayer dielectric stacks:
- Vectorized over wavelengths using np.einsum (50,000 structures x 100 wavelengths in 14 seconds)
- Validated against analytical Bragg mirror theory (error < 1e-6) and energy conservation (|R+T-1| < 1e-15)
- Supports s- and p-polarization with numerical guards
- Encoder q(z|x,c), Decoder p(x|z,c) with spectral FiLM conditioning
- Free bits (Kingma et al., 2016): minimum KL of 0.1 nats/dim prevents posterior collapse
- Beta = 0.05 with 30-epoch linear warmup
- RealNVP architecture with alternating even/odd masks and ActNorm
- Soft clamping: s = 2 * tanh(s/2) bounds exp(s) to [0.14, 7.4] for numerical stability
- Dedicated learning rate (5e-4), weight decay (1e-4), and gradient clipping (0.5)
- Cosine noise schedule, sinusoidal time embedding, FiLM conditioning
- Classifier-free guidance with 10% conditional dropout during training
- DDIM sampling for fast inference (50 steps)
- Generates N diverse candidates, selects top-K by spectral MSE, refines each with L-BFGS
- Preserves diversity (different starting points converge to different local optima)
- 22-596x MSE improvement over raw generative samples
- Spectral MSE / Best-of-N MSE: Reconstruction accuracy with sample budget scaling
- MMD (multi-bandwidth Gaussian kernel): Distribution distance to reference posterior
- Coverage / Precision (Kynkaanniemi et al., 2019): k-NN based posterior quality
- Solution diversity: Mean pairwise L2 distance among generated structures
- Classifier-free guidance sweep: Accuracy-diversity tradeoff (w in {0, 0.5, 1, 1.5, 2, 3, 5})
- Degeneracy analysis: PCA + adaptive DBSCAN clustering of valid solution manifolds
cd inverse_photonic_design
python -m venv venv
# Windows: .\venv\Scripts\Activate
# Linux: source venv/bin/activate
pip install torch --index-url https://download.pytorch.org/whl/cu126
pip install -r requirements.txt
python -m pytest tests/ -v # 10/10 physics tests
python scripts/run_pipeline.py # Full pipeline (~4.5 hours on RTX 3060)The pipeline produces:
figures/— Publication-quality figures (Bragg validation, spectrum reconstructions, model comparison, best-of-N scaling, guidance sweep, degeneracy analysis, latent space t-SNE, posterior collapse diagnosis)outputs/— Trained model checkpoints and per-model evaluation JSONs with confidence intervalsdata/— Generated dataset with metadata
- Python >= 3.10
- PyTorch >= 2.0 (CUDA recommended)
- NumPy, SciPy, scikit-learn, matplotlib, PyYAML
All random seeds are fixed (torch, numpy, random, CUDA). Config and seed are saved to outputs/config_used.yaml and outputs/seed.txt. The full pipeline is deterministic given the same hardware.