File size: 7,451 Bytes
eb6584e 43604b6 53f9f3e eb6584e 221faf8 eb6584e 221faf8 eb6584e 43604b6 53f9f3e ad36a58 fce6c09 43604b6 d774735 fce6c09 43604b6 1ad9fc2 43604b6 ad36a58 43604b6 fce6c09 43604b6 3d60772 43604b6 3d60772 d774735 3d60772 eb6584e 1263fa8 eb6584e 3d60772 1263fa8 3d60772 43604b6 221faf8 43604b6 | 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 | import sys
from pathlib import Path
import pandas as pd
import streamlit as st
try:
from common.method_registry import KNOWN_METHODS, SUITABILITY_FAMILIES, family_full_name
from common.leaderboard import _UPDATE_TYPE_ORDER
except ModuleNotFoundError:
sys.path.append(str(Path(__file__).resolve().parent))
from common.method_registry import KNOWN_METHODS, SUITABILITY_FAMILIES, family_full_name
from common.leaderboard import _UPDATE_TYPE_ORDER
st.set_page_config(page_title="Calibration Benchmark", page_icon="π ", layout="wide")
# Sidebar navigation
st.sidebar.title("Navigation")
st.sidebar.page_link("streamlit_app.py", label="Home", icon="π ")
st.sidebar.page_link("pages/OptimizationLeaderboard.py", label="Optimization Leaderboard", icon="π")
st.sidebar.page_link("pages/UQLeaderboard.py", label="UQ Leaderboard", icon="π―")
st.sidebar.page_link("pages/MethodDetails.py", label="Method configurations", icon="π")
st.sidebar.page_link("pages/RawData.py", label="Get Data", icon="π§Ύ")
st.title("Calibration Benchmark")
st.markdown(
"A benchmark comparing parameter-calibration methods on chaotic dynamical systems. "
"Methods are ranked by **forward-model run efficiency** β how many forward-model "
"evaluations are needed, on average across random seeds, to reach a target accuracy."
)
st.markdown(
"The exact implementations of every algorithm benchmarked here are available at "
"[CalibrationLeaderboard.jl](https://github.com/odunbar/CalibrationLeaderboard.jl)."
)
st.divider()
col1, col2 = st.columns(2, gap="large")
with col1:
st.subheader("π Optimization Leaderboard")
st.markdown(
"Ranks methods by mean forward-model runs to reach an **RMSE target** on "
"Lorenz-63 and Lorenz-96 benchmarks. "
"Lower is better; failed runs are tracked separately as a failure rate."
)
st.page_link("pages/OptimizationLeaderboard.py", label="Go to Optimization Leaderboard β")
with col2:
st.subheader("π― UQ Leaderboard")
st.markdown(
"Ranks methods by mean forward-model runs to reach an **uncertainty quantification "
"target**. Same metric and benchmarks as the Optimization Leaderboard, evaluated "
"at a UQ-specific convergence criterion."
)
st.page_link("pages/UQLeaderboard.py", label="Go to UQ Leaderboard β")
st.divider()
st.subheader("Benchmarks")
st.markdown(
"Results are reported on four benchmark configurations of the [Lorenz system]"
"(https://en.wikipedia.org/wiki/Lorenz_system), a standard testbed for "
"data-assimilation and calibration algorithms:"
)
_media = Path(__file__).parent / "media"
st.markdown("- **L63** β Lorenz-63 β 3-variable chaotic attractor; learn 2 parameters, strongly nonlinear.")
st.image(
str(_media / "posterior_ribbons_20_13_k5.png"),
caption="Example prior-posterior & truth. L: Difference to true parameter. R: data-sample/output predictived distribution (state-mean [1:3], state-covariance (diag [4:6] and off-diag [7:9]))",
width=800,
)
st.markdown("- **L96** β Lorenz-96 (40-variable); learn 1-parameter constant forcing.")
st.image(
str(_media / "posterior_ribbons_const-force_12_1_k3.png"),
caption="Example prior-posterior & truth. L: Difference to true parameter. C: parameter-induced forcing of the L96 system. R: data-sample/output predictived distribution ([1:40] state-mean [41:80] state-std)",
width=1200,
)
st.markdown("- **L96_SPATIAL_FORCING** β Lorenz-96 (40-variable) with spatially-varying forcing; learn 40 parameters; moderately correlated prior.")
st.image(
str(_media / "posterior_ribbons_vec-force_65_1_k3.png"),
caption="Example prior-posterior & truth. L: Difference to true parameters. C: parameter-induced forcing of the L96 system. R: data-sample/output predictived distribution ([1:40] state-mean [41:80] state-std)",
width=1200,
)
st.markdown("- **L96_NN_FORCING** β Lorenz-96 (100-variable) with a neural-network forcing; Learn 61 parameters (weights and biases of the network). Reasonable prior given.")
st.image(
str(_media / "posterior_ribbons_flux-force_80_1_k3.png"),
caption="Example prior-posterior & truth. L: Difference to true parameters (weights). C: parameter-induced forcing of the L96 system. R: data-sample/output predictived distribution ([1:100] state-mean [101:200] state-std)",
width=1200,
)
st.subheader("Method taxonomy")
st.markdown(
"Every method carries four independent tags β how it searches, what update "
"mechanism drives each step, what it's built to report, and whether/when it uses "
"a surrogate model. See the **π Method configurations** page to investigate more "
"about any individual configuration."
)
_taxonomy_rows = [
{
"Algorithm": info["abbreviation"],
"Method Goal": info["method_goal"],
"Update Type": info["update_type"],
"Parallelism": info["parallelism"],
"Emulator Use": info["emulator_use"],
"_update_type_order": _UPDATE_TYPE_ORDER.get(info["update_type"], 99),
}
for info in KNOWN_METHODS.values()
]
_taxonomy_df = (
pd.DataFrame(_taxonomy_rows)
.sort_values(["_update_type_order", "Algorithm"])
.drop(columns="_update_type_order")
)
_UPDATE_TYPE_ROW_COLOR = {
"gradient (Kalman)": "#d9f2e6", # pastel green
"gradient (exact)": "#dbe9fa", # pastel blue
"gradient (score)": "#e6dcf5", # pastel purple
"general": "#fde2c8", # pastel orange
}
def _style_taxonomy_rows(df: pd.DataFrame) -> pd.DataFrame:
result = pd.DataFrame("", index=df.index, columns=df.columns)
for row in df.index:
bg = _UPDATE_TYPE_ROW_COLOR.get(df.loc[row, "Update Type"], "")
if bg:
result.loc[row, :] = f"background-color: {bg}; color: #212529"
return result
st.dataframe(
_taxonomy_df.style.apply(_style_taxonomy_rows, axis=None),
hide_index=True,
use_container_width=True,
height=int((len(_taxonomy_df) + 1) * 35.2 + 3),
column_config={
"Algorithm": st.column_config.TextColumn("Algorithm"),
"Method Goal": st.column_config.TextColumn("Method Goal"),
"Update Type": st.column_config.TextColumn("Update Type"),
"Parallelism": st.column_config.TextColumn("Parallelism"),
"Emulator Use": st.column_config.TextColumn("Emulator Use"),
},
)
st.caption(
"Note: Kalman methods are Bayesian in spirit too (they're approximate Gaussian "
"posterior updates) β update type is about mechanism (which kind of gradient β exact, Kalman or score β vs. "
"general), not whether a method is 'Bayesian'."
)
_family_key_rows = [
{"Family": family_full_name(fam), "Algorithms": ", ".join(members)}
for fam, members in SUITABILITY_FAMILIES.items()
]
st.markdown("**Method families** β algorithms of similar construction, used to group the suitability tables and method selectors:")
st.dataframe(
pd.DataFrame(_family_key_rows),
hide_index=True,
use_container_width=True,
height=int((len(_family_key_rows) + 1) * 35.2 + 3),
)
st.subheader("Key metric")
st.markdown(
"The reported metric is the **mean number of forward-model evaluations** required "
"to reach the target, averaged over random seeds. "
"A value of **β1** indicates a failed run (did not reach the target); "
"the **failure rate** shows the fraction of seeds that failed."
)
|