VKVlad KulikovPublic / lectures
Information Theory for ML12 / 16

Module 12. Information-theoretic generalization bounds: PAC-Bayes and mutual information

Try each exercise first. Expand worked answers or project guidance when needed; their open state is shared between RU/EN.

Download course files (.zip) 33.9 KB

The archive preserves the folder structure of nine Python solution files shared by RU/EN.

Exercise 1. Proving PAC-Bayes-kl

Reconstruct the proof from Section 12.4.

  1. Start from

    ESenkl⁡(L^S(w)∥L(w))≤2n\mathbb E_S e^{n\operatorname{kl}(\widehat L_S(w)\|L(w))} \le2\sqrt n

    for fixed ww.

  2. Integrate over PP and apply Markov's inequality.

  3. Use the change-of-measure inequality

    EQF≤DKL(Q∥P)+ln⁡EPeF.\mathbb E_QF \le D_{\mathrm{KL}}(Q\|P) + \ln\mathbb E_Pe^F.
  4. Apply joint convexity of binary KL.

  5. Identify exactly where independence of PP from SS is required.

Show answer and solution

Let

FS(w)=nkl⁡(L^S(w)∥L(w)).F_S(w) = n\operatorname{kl} \bigl( \widehat L_S(w)\|L(w) \bigr).

For each fixed ww, Maurer's exponential-moment inequality gives

ESeFS(w)≤2n.\mathbb E_S e^{F_S(w)} \le 2\sqrt n.

Because the prior PP is independent of SS, expectations can be exchanged:

ESEW∼PeFS(W)=EW∼PESeFS(W)≤2n.\mathbb E_S \mathbb E_{W\sim P} e^{F_S(W)} = \mathbb E_{W\sim P} \mathbb E_S e^{F_S(W)} \le 2\sqrt n.

Markov's inequality implies that, with probability at least 1−δ1-\delta,

EW∼PeFS(W)≤2nδ.\mathbb E_{W\sim P} e^{F_S(W)} \le \frac{2\sqrt n}{\delta}.

Fix a sample for which this event holds. For every posterior QQ, the change-of-measure inequality gives

EQFS(W)≤DKL(Q∥P)+ln⁡EPeFS(W).\mathbb E_QF_S(W) \le D_{\mathrm{KL}}(Q\|P) + \ln\mathbb E_Pe^{F_S(W)}.

Therefore,

EQFS(W)≤DKL(Q∥P)+ln⁡2nδ.\mathbb E_QF_S(W) \le D_{\mathrm{KL}}(Q\|P) + \ln\frac{2\sqrt n}{\delta}.

Binary KL is jointly convex, so

nkl⁡(L^S(Q)∥L(Q))=nkl⁡(EQL^S(W)∥EQL(W))≤nEQkl⁡(L^S(W)∥L(W))=EQFS(W).\begin{aligned} &n\operatorname{kl} \bigl( \widehat L_S(Q)\|L(Q) \bigr)\\ &=n\operatorname{kl} \left( \mathbb E_Q\widehat L_S(W) \middle\| \mathbb E_QL(W) \right)\\ &\le n\mathbb E_Q \operatorname{kl} \bigl( \widehat L_S(W)\|L(W) \bigr)\\ &= \mathbb E_QF_S(W). \end{aligned}

Combining the inequalities and dividing by nn gives

kl⁡(L^S(Q)∥L(Q))≤DKL(Q∥P)+ln⁡2nδn.\operatorname{kl} \bigl( \widehat L_S(Q)\|L(Q) \bigr) \le \frac{ D_{\mathrm{KL}}(Q\|P) + \ln\dfrac{2\sqrt n}{\delta} }{n}.

Where independence of the prior is used

The critical equality is

ESEW∼PeFS(W)=EW∼PESeFS(W).\mathbb E_S\mathbb E_{W\sim P}e^{F_S(W)} = \mathbb E_{W\sim P}\mathbb E_Se^{F_S(W)}.

If P=PSP=P_S is chosen from the same sample, then inside the first expectation the law of WW changes together with SS. The fixed-hypothesis exponential-moment inequality can no longer be applied without an additional charge for the data dependence of the prior.

Exercise 2. Zero empirical error

Suppose

kl⁡(0∥L(Q))≤c.\operatorname{kl}(0\|L(Q))\le c.
  1. Show that

    L(Q)≤1−e−c.L(Q)\le1-e^{-c}.
  2. Compare it with

    L(Q)≤c/2.L(Q)\le\sqrt{c/2}.
  3. Evaluate both bounds at c=0.01c=0.01.

  4. Explain why exact inversion matters when training risk is nearly zero.

Show answer and solution

For a=0a=0, binary KL equals

kl⁡(0∥b)=−ln⁡(1−b).\operatorname{kl}(0\|b) = -\ln(1-b).

Hence

−ln⁡(1−L(Q))≤c-\ln(1-L(Q))\le c

implies

ln⁡(1−L(Q))≥−c,\ln(1-L(Q))\ge-c, 1−L(Q)≥e−c,1-L(Q)\ge e^{-c},

and finally

L(Q)≤1−e−c.\boxed{ L(Q)\le1-e^{-c} }.

For small cc,

1−e−c=c−c22+O(c3)≈c.1-e^{-c} =c-\frac{c^2}{2}+O(c^3) \approx c.

Pinsker gives only

L(Q)≤c/2.L(Q) \le \sqrt{c/2}.

At c=0.01c=0.01, for example,

1−e−0.01≈0.00995,1-e^{-0.01} \approx0.00995,

whereas

0.01/2≈0.0707.\sqrt{0.01/2} \approx0.0707.

The difference is almost sevenfold. For models with zero or near-zero training error, the binary-KL bound should therefore not be replaced by its square-root corollary without a reason.

Exercise 3. A Gaussian posterior and L2L_2

For

P=N(0,σP2I),Q=N(μ,σQ2I),P=\mathcal N(0,\sigma_P^2I), \qquad Q=\mathcal N(\mu,\sigma_Q^2I),

derive DKL(Q∥P)D_{\mathrm{KL}}(Q\|P).

  1. Isolate the term proportional to ∥μ∥2\|\mu\|^2.

  2. Explain the role of the variance terms.

  3. Explain why this establishes a connection to L2L_2 regularization but not full equivalence with ordinary deterministic weight decay.

Show answer and solution

For

P=N(0,σP2Id),Q=N(μ,σQ2Id)P=\mathcal N(0,\sigma_P^2I_d), \qquad Q=\mathcal N(\mu,\sigma_Q^2I_d)

the Gaussian KL formula gives

DKL(Q∥P)=12[tr⁡(σP−2Id σQ2Id)+μT(σP−2Id)μ−d+ln⁡det⁡(σP2Id)det⁡(σQ2Id)]=12[dσQ2σP2+∥μ∥2σP2−d+dln⁡σP2σQ2].\begin{aligned} D_{\mathrm{KL}}(Q\|P) &= \frac12 \left[ \operatorname{tr} (\sigma_P^{-2}I_d\,\sigma_Q^2I_d) + \mu^T(\sigma_P^{-2}I_d)\mu -d + \ln\frac{\det(\sigma_P^2I_d)}{\det(\sigma_Q^2I_d)} \right]\\ &= \frac12 \left[ d\frac{\sigma_Q^2}{\sigma_P^2} + \frac{\|\mu\|^2}{\sigma_P^2} -d + d\ln\frac{\sigma_P^2}{\sigma_Q^2} \right]. \end{aligned}

That is,

DKL(Q∥P)=∥μ∥22σP2+d2(σQ2σP2−1+ln⁡σP2σQ2).\boxed{ D_{\mathrm{KL}}(Q\|P) = \frac{\|\mu\|^2}{2\sigma_P^2} + \frac d2 \left( \frac{\sigma_Q^2}{\sigma_P^2} -1 + \ln\frac{\sigma_P^2}{\sigma_Q^2} \right) }.

The first term does have the form of an L2L_2 penalty. But the complete PAC-Bayes objective also contains:

  • a variance term;
  • the empirical Gibbs risk, rather than the loss of a network with mean weights;
  • the scale 1/(λn)1/(\lambda n);
  • a confidence term inside the certificate itself;
  • a validity requirement on the prior.

Ordinary deterministic weight decay is therefore related to the Gaussian PAC-Bayes penalty, but not identical to the whole procedure.

Exercise 4. Adaptive selection and MI

There are MM hypotheses with identical Bernoulli population loss pp. On a sample of size nn, the algorithm selects the hypothesis with the smallest empirical loss.

  1. Why is the winner's expected empirical loss at most pp? Give an example of equality and a sufficient condition for a strict decrease.

  2. If selection is deterministic, why is

    I(W;S)=H(W)≤ln⁡M?I(W;S)=H(W)\le\ln M?
  3. For losses in [0,1][0,1], derive

    ∣Egen⁡∣≤ln⁡M2n.|\mathbb E\operatorname{gen}| \le \sqrt{\frac{\ln M}{2n}}.
  4. What changes under tempered Gibbs selection?

Show answer and solution

Every hypothesis has the same population risk pp, while its empirical risk is random. Taking the minimum cannot increase the expected estimate:

E[min⁡jL^j]≤min⁡jE[L^j]=p.\mathbb E \left[ \min_j\widehat L_j \right] \le \min_j \mathbb E[\widehat L_j] =p.

Equality is possible even when 0<p<10<p<1. Suppose all hypotheses incur the same loss on each observation, with independent Bernoulli(p)(p) losses across observations. Then all L^j\widehat L_j coincide, and their minimum has expectation pp. With a fixed tie-breaking rule, such as choosing the smallest index, WW is constant and I(W;S)=0I(W;S)=0.

A sufficient condition for a strict decrease is M>1M>1, n≥1n\ge1, 0<p<10<p<1, and independent Bernoulli losses across candidates and observations. The event that the first candidate has loss 1 on every observation while the second has loss 0 on every observation then has positive probability. On that event, min⁡jL^j<L^1\min_j\widehat L_j<\widehat L_1; on every other outcome, the minimum is at most L^1\widehat L_1. Its expectation is therefore strictly below pp.

If the selection W=A(S)W=A(S) is deterministic, then

H(W∣S)=0.H(W\mid S)=0.

Consequently,

I(W;S)=H(W)−H(W∣S)=H(W).I(W;S) =H(W)-H(W\mid S) =H(W).

Since WW takes at most MM values,

H(W)≤ln⁡M.H(W) \le \ln M.

For a loss in [0,1][0,1] the MI bound may use σ2=1/4\sigma^2=1/4:

∣Egen⁡∣≤2(1/4)I(W;S)n≤ln⁡M2n.|\mathbb E\operatorname{gen}| \le \sqrt{ \frac{2(1/4)I(W;S)}{n} } \le \sqrt{ \frac{\ln M}{2n} }.

Temperature-controlled Gibbs selection defines the distribution

QS(j)∝exp⁡(−L^j(S)τ).Q_S(j) \propto \exp \left( -\frac{\widehat L_j(S)}{\tau} \right).

As τ→0\tau\to0 it approaches argmin, and as τ→∞\tau\to\infty it approaches an almost uniform choice. Raising the temperature increases

H(W∣S),H(W\mid S),

which lowers

I(W;S)=H(W)−H(W∣S).I(W;S)=H(W)-H(W\mid S).

The price is a less aggressive use of the empirical fit.

Exercise 5. The exact average-KL decomposition

Prove

ESDKL(QS∥P)=I(W;S)+DKL(PW∥P).\mathbb E_S D_{\mathrm{KL}}(Q_S\|P) = I(W;S) + D_{\mathrm{KL}}(P_W\|P).

Then answer the following.

  1. Which PP minimizes the left side on average?

  2. Why is it called an oracle prior?

  3. Under what knowledge would it be theoretically admissible in the standard theorem?

  4. Why can it not be estimated from the same sample without a correction?

Show answer and solution

Let

QS=PW∣S,Q_S=P_{W\mid S},

and let PWP_W be the marginal law of WW. Then

ESDKL(QS∥P)=ES,Wln⁡dQSdP(W)=ES,W[ln⁡dQSdPW(W)+ln⁡dPWdP(W)]=I(W;S)+DKL(PW∥P).\begin{aligned} \mathbb E_S D_{\mathrm{KL}}(Q_S\|P) &= \mathbb E_{S,W} \ln\frac{dQ_S}{dP}(W)\\ &= \mathbb E_{S,W} \left[ \ln\frac{dQ_S}{dP_W}(W) + \ln\frac{dP_W}{dP}(W) \right]\\ &= I(W;S) + D_{\mathrm{KL}}(P_W\|P). \end{aligned}

The second term is nonnegative, so the minimum over PP is attained at

P=PW.\boxed{P=P_W}.

Then

ESDKL(QS∥PW)=I(W;S).\mathbb E_S D_{\mathrm{KL}}(Q_S\|P_W) = I(W;S).

This distribution is called an oracle prior, because building it generally requires the law of the algorithm output over all datasets drawn from the unknown data distribution D\mathcal D.

Unavailability should not be confused with invalidity. If D\mathcal D and the conditional law PW∣SP_{W\mid S} of the algorithm were known, then the marginal

PW(dw)=∫PW∣S=s(dw) PS(ds)P_W(dw) = \int P_{W\mid S=s}(dw)\,P_S(ds)

would be defined before the realized certification sample is observed. In that idealized setting, PWP_W is a fixed and theoretically admissible prior for the standard PAC-Bayes theorem.

In practice D\mathcal D is unknown, which invites estimating PWP_W from the current sample and substituting that estimate into the certificate. This is a different object: the prior then depends on the certification data. It requires a separate argument—sample splitting, a hierarchical construction, a differential-privacy correction, or a theorem designed for data-dependent priors.

Exercise 6. Python: selection bias and a PAC-Bayes certificate

Run

text
M12_generalization_experiments.py

The script performs two experiments.

  1. Adaptive selection among 32 equally good hypotheses:

    • compare selection bias with the MI bound;
    • track the effect of temperature;
    • verify the exact average-KL decomposition.
  2. A stochastic linear classifier:

    • compare empirical Gibbs risk, diagnostic test risk, and the PAC-Bayes-kl certificate;
    • find the posterior variance that minimizes the certificate;
    • compare exact binary-KL inversion with the square-root corollary.

Explain why test risk is not part of the certificate.

Show answer and solution

The script reproduces two experiments.

Part 1. Adaptive selection

For argmin:

I(W;S)≈3.2351 nats,I(W;S) \approx3.2351\text{ nats}, Egen⁡≈0.0874,\mathbb E\operatorname{gen} \approx0.0874,

and the MI bound is about

0.1422.0.1422.

At temperature τ=0.05\tau=0.05:

I(W;S)≈0.3382,I(W;S) \approx0.3382, Egen⁡≈0.0351,\mathbb E\operatorname{gen} \approx0.0351, MI bound≈0.0460.\text{MI bound} \approx0.0460.

At τ=0.5\tau=0.5 both the mutual information and the gap become almost zero, because the algorithm has nearly stopped choosing the winner from the data.

For τ=0.05\tau=0.05 the script also checks

ESKL(QS∥P)=I(W;S)+KL(PW∥P)\mathbb E_S KL(Q_S\|P) = I(W;S)+KL(P_W\|P)

to within Monte Carlo noise.

Part 2. A stochastic linear classifier

The best posterior standard deviation among those tested is

σQ=0.1.\sigma_Q=0.1.

For it:

L^S(Q)≈0.2273,\widehat L_S(Q) \approx0.2273, Ltest(Q)≈0.2254,L_{\mathrm{test}}(Q) \approx0.2254, DKL(Q∥P)≈12.6653 nats,D_{\mathrm{KL}}(Q\|P) \approx12.6653\text{ nats}, PAC-Bayes-kl certificate≈0.2715.\text{PAC-Bayes-kl certificate} \approx0.2715.

The square-root Pinsker corollary gives about

0.2780,0.2780,

that is, a slightly weaker result.

Test risk does not enter the certificate. It is used only to check how conservative the certificate is in a synthetic world where a large independent test set can be generated.

Code solution · the same source file for RU/EN

PythonM12_generalization_experiments.pyDownload .py
from __future__ import annotations

from pathlib import Path
import json
import math

import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np
from scipy.special import expit, ndtr

ROOT = Path(__file__).resolve().parent
OUT = ROOT / "generated_experiment"
OUT.mkdir(exist_ok=True)
SEED = 202612


def binary_kl(q: float, p: float) -> float:
    """Bernoulli KL kl(q || p), in nats."""
    eps = 1e-15
    q = float(np.clip(q, eps, 1 - eps))
    p = float(np.clip(p, eps, 1 - eps))
    return q * math.log(q / p) + (1 - q) * math.log((1 - q) / (1 - p))


def kl_upper_inverse(q: float, c: float) -> float:
    """Largest p in [q,1] such that kl(q || p) <= c."""
    if c <= 0:
        return float(q)
    lo = float(q)
    hi = 1.0 - 1e-12
    if binary_kl(q, hi) <= c:
        return 1.0
    for _ in range(100):
        mid = 0.5 * (lo + hi)
        if binary_kl(q, mid) <= c:
            lo = mid
        else:
            hi = mid
    return lo


def softmax_rows(logits: np.ndarray) -> np.ndarray:
    shifted = logits - np.max(logits, axis=1, keepdims=True)
    weights = np.exp(shifted)
    return weights / np.sum(weights, axis=1, keepdims=True)


def experiment_adaptive_selection() -> dict:
    """Adaptive selection among equally good hypotheses.

    Each data point is a vector of M Bernoulli losses. All hypotheses have the
    same population risk p. The algorithm chooses a hypothesis using a Gibbs
    distribution over empirical losses. This makes the selection bias and the
    MI bound directly visible.
    """
    rng = np.random.default_rng(SEED)
    m = 32
    n = 80
    true_risk = 0.20
    trials = 120_000
    empirical = rng.binomial(n, true_risk, size=(trials, m)) / n
    temperatures = [0.0, 0.01, 0.02, 0.05, 0.10, 0.20, 0.50]
    rows: list[dict] = []

    # A deliberately mismatched fixed prior for the KL decomposition demo.
    skew_prior = np.full(m, 0.5 / (m - 1))
    skew_prior[0] = 0.5

    for tau in temperatures:
        if tau == 0.0:
            minima = np.min(empirical, axis=1, keepdims=True)
            ties = empirical == minima
            q_cond = ties / np.sum(ties, axis=1, keepdims=True)
        else:
            q_cond = softmax_rows(-empirical / tau)

        marginal = np.mean(q_cond, axis=0)
        eps = 1e-300
        h_marginal = -float(np.sum(marginal * np.log(np.clip(marginal, eps, None))))
        h_conditional = -float(
            np.mean(np.sum(q_cond * np.log(np.clip(q_cond, eps, None)), axis=1))
        )
        mutual_information = h_marginal - h_conditional
        selected_empirical = float(np.mean(np.sum(q_cond * empirical, axis=1)))
        expected_gap = true_risk - selected_empirical

        # A [0,1]-valued loss is 1/2-sub-Gaussian by Hoeffding's lemma,
        # hence sigma^2 = 1/4 and the Xu-Raginsky bound is sqrt(I/(2n)).
        mi_bound = math.sqrt(mutual_information / (2 * n))

        avg_kl_uniform = float(
            np.mean(np.sum(q_cond * (np.log(np.clip(q_cond, eps, None)) + math.log(m)), axis=1))
        )
        avg_kl_skew = float(
            np.mean(
                np.sum(
                    q_cond
                    * (
                        np.log(np.clip(q_cond, eps, None))
                        - np.log(skew_prior)[None, :]
                    ),
                    axis=1,
                )
            )
        )
        marginal_kl_skew = float(
            np.sum(marginal * (np.log(np.clip(marginal, eps, None)) - np.log(skew_prior)))
        )

        rows.append(
            {
                "temperature": tau,
                "mutual_information_nats": mutual_information,
                "expected_empirical_risk": selected_empirical,
                "population_risk": true_risk,
                "expected_generalization_gap": expected_gap,
                "mi_bound": mi_bound,
                "marginal_entropy_nats": h_marginal,
                "conditional_entropy_nats": h_conditional,
                "avg_kl_to_uniform_prior": avg_kl_uniform,
                "avg_kl_to_skew_prior": avg_kl_skew,
                "marginal_kl_to_skew_prior": marginal_kl_skew,
            }
        )

    fig, ax = plt.subplots(figsize=(9.6, 5.6))
    x = np.array([r["mutual_information_nats"] for r in rows])
    gap = np.array([r["expected_generalization_gap"] for r in rows])
    bound = np.array([r["mi_bound"] for r in rows])
    ax.plot(x, gap, marker="o", label="estimated expected gap")
    ax.plot(x, bound, marker="s", linestyle="--", label="MI upper bound")
    for r in rows:
        label = "argmin" if r["temperature"] == 0 else f"τ={r['temperature']:g}"
        ax.annotate(label, (r["mutual_information_nats"], r["expected_generalization_gap"]),
                    xytext=(4, 5), textcoords="offset points", fontsize=8)
    ax.set_xlabel("I(W; S), nats")
    ax.set_ylabel("expected generalization gap")
    ax.set_title("Adaptive selection: less information about the sample, less selection bias")
    ax.legend()
    ax.grid(alpha=0.25)
    fig.tight_layout()
    fig.savefig(OUT / "M12_experiment_adaptive_selection.png", dpi=180)
    plt.close(fig)

    # Decomposition for tau=0.05.
    chosen = next(r for r in rows if abs(r["temperature"] - 0.05) < 1e-12)
    terms = [
        chosen["mutual_information_nats"],
        chosen["marginal_kl_to_skew_prior"],
        chosen["avg_kl_to_skew_prior"],
    ]
    fig, ax = plt.subplots(figsize=(8.8, 5.2))
    ax.bar(["I(W;S)", "KL(P_W || P)", "E KL(Q_S || P)"], terms)
    ax.set_ylabel("nats")
    ax.set_title("Exact decomposition of average posterior-to-prior KL")
    ax.text(2, terms[2] + 0.02, "sum of the first two terms", ha="center", fontsize=9)
    ax.grid(axis="y", alpha=0.25)
    fig.tight_layout()
    fig.savefig(OUT / "M12_experiment_kl_decomposition.png", dpi=180)
    plt.close(fig)

    return {
        "M": m,
        "n": n,
        "true_risk": true_risk,
        "trials": trials,
        "rows": rows,
    }


def fit_logistic_regression(x: np.ndarray, y: np.ndarray) -> np.ndarray:
    """Simple deterministic full-batch logistic regression."""
    n, d = x.shape
    w = np.zeros(d)
    learning_rate = 0.10
    l2 = 1e-3
    for _ in range(1800):
        margins = y * (x @ w)
        grad = -(x.T @ (y * expit(-margins))) / n + l2 * w
        w -= learning_rate * grad
    return w


def gaussian_kl_isotropic(mean: np.ndarray, sigma_q: float, sigma_p: float) -> float:
    k = mean.size
    return 0.5 * float(
        np.sum((sigma_q**2 + mean**2) / sigma_p**2 - 1 + math.log(sigma_p**2 / sigma_q**2))
    )


def gibbs_linear_risk(x: np.ndarray, y: np.ndarray, mean: np.ndarray, sigma_q: float) -> float:
    """Exact Gibbs 0-1 risk for W~N(mean, sigma_q^2 I) and sign(W^T x)."""
    signed_mean = y * (x @ mean)
    std = sigma_q * np.linalg.norm(x, axis=1)
    z = -signed_mean / np.maximum(std, 1e-15)
    return float(np.mean(ndtr(z)))


def experiment_pac_bayes_classifier() -> dict:
    rng = np.random.default_rng(SEED + 1)
    n_train = 4000
    n_test = 80_000
    d = 5
    delta = 0.05
    sigma_prior = 1.0

    true_w = rng.normal(size=d)
    true_w /= np.linalg.norm(true_w)

    def sample_data(n: int) -> tuple[np.ndarray, np.ndarray]:
        x = rng.normal(size=(n, d))
        prob = expit(2.0 * (x @ true_w))
        y = np.where(rng.random(n) < prob, 1.0, -1.0)
        x_aug = np.column_stack([x, np.ones(n)])
        return x_aug, y

    x_train, y_train = sample_data(n_train)
    x_test, y_test = sample_data(n_test)
    mean = fit_logistic_regression(x_train, y_train)
    deterministic_train = float(np.mean(y_train * (x_train @ mean) <= 0))
    deterministic_test = float(np.mean(y_test * (x_test @ mean) <= 0))

    sigmas = [0.03, 0.05, 0.10, 0.20, 0.30, 0.50, 0.80, 1.00]
    rows: list[dict] = []
    confidence_term = math.log(2 * math.sqrt(n_train) / delta)

    for sigma_q in sigmas:
        empirical_gibbs = gibbs_linear_risk(x_train, y_train, mean, sigma_q)
        test_gibbs = gibbs_linear_risk(x_test, y_test, mean, sigma_q)
        kl = gaussian_kl_isotropic(mean, sigma_q, sigma_prior)
        complexity = (kl + confidence_term) / n_train
        kl_bound = kl_upper_inverse(empirical_gibbs, complexity)
        pinsker_bound = min(1.0, empirical_gibbs + math.sqrt(complexity / 2))
        rows.append(
            {
                "sigma_posterior": sigma_q,
                "empirical_gibbs_risk": empirical_gibbs,
                "test_gibbs_risk": test_gibbs,
                "kl_q_p_nats": kl,
                "pac_bayes_kl_bound": kl_bound,
                "pinsker_square_root_bound": pinsker_bound,
            }
        )

    best = min(rows, key=lambda r: r["pac_bayes_kl_bound"])

    fig, ax = plt.subplots(figsize=(9.6, 5.6))
    xs = np.array(sigmas)
    ax.plot(xs, [r["empirical_gibbs_risk"] for r in rows], marker="o", label="empirical Gibbs risk")
    ax.plot(xs, [r["test_gibbs_risk"] for r in rows], marker="o", label="test Gibbs risk")
    ax.plot(xs, [r["pac_bayes_kl_bound"] for r in rows], marker="s", label="PAC-Bayes-kl certificate")
    ax.plot(xs, [r["pinsker_square_root_bound"] for r in rows], linestyle="--", label="square-root corollary")
    ax.axhline(deterministic_test, linestyle=":", label="deterministic mean test error")
    ax.set_xscale("log")
    ax.set_xlabel("posterior standard deviation σ_Q")
    ax.set_ylabel("0-1 risk")
    ax.set_title("Stochastic linear classifier: empirical fit, KL complexity, and certificate")
    ax.legend()
    ax.grid(alpha=0.25)
    fig.tight_layout()
    fig.savefig(OUT / "M12_experiment_pac_bayes_classifier.png", dpi=180)
    plt.close(fig)

    return {
        "n_train": n_train,
        "n_test": n_test,
        "dimension_with_bias": d + 1,
        "delta": delta,
        "sigma_prior": sigma_prior,
        "mean_norm": float(np.linalg.norm(mean)),
        "deterministic_train_error": deterministic_train,
        "deterministic_test_error": deterministic_test,
        "rows": rows,
        "best_by_pac_bayes_kl": best,
    }


def main() -> None:
    results = {
        "adaptive_selection": experiment_adaptive_selection(),
        "pac_bayes_classifier": experiment_pac_bayes_classifier(),
    }
    (OUT / "M12_experiment_results.json").write_text(
        json.dumps(results, indent=2, ensure_ascii=False), encoding="utf-8"
    )

    best = results["pac_bayes_classifier"]["best_by_pac_bayes_kl"]
    print("Adaptive selection (argmin):")
    row0 = results["adaptive_selection"]["rows"][0]
    print(f"  I(W;S): {row0['mutual_information_nats']:.6f} nats")
    print(f"  expected gap: {row0['expected_generalization_gap']:.6f}")
    print(f"  MI bound: {row0['mi_bound']:.6f}")
    print("Best stochastic classifier certificate:")
    print(f"  sigma_Q: {best['sigma_posterior']:.3f}")
    print(f"  empirical Gibbs risk: {best['empirical_gibbs_risk']:.6f}")
    print(f"  test Gibbs risk: {best['test_gibbs_risk']:.6f}")
    print(f"  KL(Q||P): {best['kl_q_p_nats']:.6f} nats")
    print(f"  PAC-Bayes-kl bound: {best['pac_bayes_kl_bound']:.6f}")


if __name__ == "__main__":
    main()

Bonus. A valid prior learned from part of the data

Split the sample into S0S_0 and S1S_1.

  1. Build PS0P_{S_0} from S0S_0.

  2. Train QS0,S1Q_{S_0,S_1}.

  3. Conditional on S0S_0, state a PAC-Bayes bound on the independent subset S1S_1.

  4. Explain the trade-off between prior quality and certification-sample size.

Show answer and solution

Split the sample:

S=(S0,S1),S=(S_0,S_1),

where S0S_0 and S1S_1 are disjoint i.i.d. parts and therefore independent conditional on D\mathcal D.

From S0S_0 build the prior

PS0.P_{S_0}.

Now condition on a particular value of S0S_0. After that conditioning, PS0P_{S_0} is fixed and independent of the random certification sample S1S_1, so the standard PAC-Bayes theorem applies:

kl⁡(L^S1(Q)∥L(Q))≤KL(Q∥PS0)+ln⁡2∣S1∣δ∣S1∣.\operatorname{kl} \bigl( \widehat L_{S_1}(Q)\|L(Q) \bigr) \le \frac{ KL(Q\|P_{S_0}) + \ln\dfrac{2\sqrt{|S_1|}}{\delta} }{|S_1|}.

The posterior QQ may depend on both S0S_0 and S1S_1, because once the prior is fixed the bound holds simultaneously for all QQ.

The trade-off:

  • a larger S0S_0 allows a more informative prior and a smaller KL;
  • a smaller S1S_1 weakens the concentration term and shrinks the effective certification sample.