VKВлад КуликовОткрытые лекции
Теория информации для машинного обучения12 / 16

Модуль 12. Информационные границы обобщения: PAC-Bayes и взаимная информация

Сначала попробуйте решить упражнение. Ответы, подробные решения и проектные ориентиры раскрываются отдельно и сохраняют своё состояние при переключении RU/EN.

Скачать файлы курса (.zip) 33,9 КБ

Архив содержит девять Python-файлов решений, общих для RU/EN, с сохранением структуры каталогов.

Упражнение 1. Доказательство PAC-Bayes-kl

Восстановите доказательство §12.4.

  1. Начните с

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

    для фиксированного ww.

  2. Проинтегрируйте по PP и примените неравенство Маркова.

  3. Используйте замену меры

    EQF≤DKL(Q∥P)+ln⁡EPeF.\mathbb E_QF \le D_{\mathrm{KL}}(Q\|P) + \ln\mathbb E_Pe^F.
  4. Примените совместную выпуклость бинарной KL.

  5. Укажите точное место, где требуется независимость PP от SS.

Показать ответ и решение

Пусть

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

Для каждого фиксированного ww неравенство для экспоненциального момента Маурера даёт

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

Поскольку априорное распределение PP не зависит от SS, можно поменять порядок ожиданий:

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.

По неравенству Маркова с вероятностью не меньше 1−δ1-\delta:

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

Зафиксируем выборку, для которой это событие произошло. Для любого апостериорного распределения QQ неравенство замены меры даёт

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)}.

Следовательно,

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

Бинарная KL совместно выпукла. Поэтому

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}

Объединяя оценки и деля на nn, получаем

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}.

Где используется независимость априорного распределения

Критическое равенство:

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)}.

Если P=PSP=P_S выбирается по той же выборке, то внутри первого ожидания распределение WW меняется вместе с SS. Фиксированное неравенство для экспоненциального момента для заранее выбранной гипотезы больше нельзя применить без дополнительной платы за зависимость априорного распределения от данных.

Упражнение 2. Нулевая эмпирическая ошибка

Пусть

kl⁡(0∥L(Q))≤c.\operatorname{kl}(0\|L(Q))\le c.
  1. Покажите, что

    L(Q)≤1−e−c.L(Q)\le1-e^{-c}.
  2. Сравните результат с

    L(Q)≤c/2.L(Q)\le\sqrt{c/2}.
  3. Вычислите обе границы при c=0.01c=0.01.

  4. Объясните, почему точная инверсия особенно важна при почти нулевом обучающем риске.

Показать ответ и решение

При a=0a=0 бинарная KL равна

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

Поэтому из

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

следует

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

и наконец

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

При малом cc:

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

Pinsker даёт только

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

Например, при c=0.01c=0.01:

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

тогда как

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

Разница почти в семь раз. Поэтому для моделей с нулевой или почти нулевой обучающей ошибкой не стоит без необходимости заменять границу через бинарную KL квадратным следствием.

Упражнение 3. Гауссовское апостериорное распределение и L2L_2

Для

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

выведите DKL(Q∥P)D_{\mathrm{KL}}(Q\|P).

  1. Выделите член, пропорциональный ∥μ∥2\|\mu\|^2.

  2. Покажите роль дисперсионных членов.

  3. Объясните, почему это даёт связь с L2L_2-регуляризацией, но не полную эквивалентность обычному детерминированному затуханию весов.

Показать ответ и решение

Для

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

формула KL между гауссовскими распределениями даёт

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}

То есть

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) }.

Первый член действительно имеет форму L2L_2-штрафа. Но полная целевая функция PAC-Bayes содержит также:

  • дисперсионный член;
  • эмпирический Gibbs-риск, а не функция потерь сети со средними весами;
  • масштаб 1/(λn)1/(\lambda n);
  • доверительный член в самой границе;
  • требование корректного априорного распределения.

Поэтому обычное детерминированное затухание весов родственно гауссовскому PAC-Bayes-штрафу, но не тождественно всей процедуре.

Упражнение 4. Адаптивный выбор и MI

Есть MM гипотез с одинаковой истинной бернуллиевской функцией потерь pp. На выборке размера nn алгоритм выбирает гипотезу с минимальной эмпирической потерей.

  1. Почему ожидаемая эмпирическая потеря победителя не превосходит pp? Приведите пример равенства и достаточное условие строгого снижения.

  2. Если выбор детерминирован, почему

    I(W;S)=H(W)≤ln⁡M?I(W;S)=H(W)\le\ln M?
  3. Для потерь в [0,1][0,1] получите

    ∣Egen⁡∣≤ln⁡M2n.|\mathbb E\operatorname{gen}| \le \sqrt{\frac{\ln M}{2n}}.
  4. Что меняется при температурированном Gibbs-выборе?

Показать ответ и решение

У каждой гипотезы истинная ошибка pp, а эмпирическая ошибка случайна. Выбор минимума не увеличивает математическое ожидание оценки:

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.

Равенство возможно даже при 0<p<10<p<1. Пусть на каждом объекте потери всех гипотез совпадают, а между объектами они независимы и распределены как Bernoulli(p)(p). Тогда все L^j\widehat L_j равны, и ожидание их минимума равно pp. При фиксированном правиле разрешения ничьих, например выборе наименьшего индекса, WW постоянно и I(W;S)=0I(W;S)=0.

Достаточное условие строгого снижения — M>1M>1, n≥1n\ge1, 0<p<10<p<1 и независимость бернуллиевских потерь между кандидатами и объектами. Тогда событие «все потери первого кандидата равны 1, а второго — 0» имеет положительную вероятность. На нём min⁡jL^j<L^1\min_j\widehat L_j<\widehat L_1, а на остальных исходах минимум не больше L^1\widehat L_1. Поэтому его ожидание строго меньше pp.

Если выбор W=A(S)W=A(S) детерминирован, то

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

Следовательно,

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

Поскольку WW принимает не более MM значений,

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

Для функции потерь в [0,1][0,1] в MI-границе можно взять σ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} }.

Температурированный Gibbs-выбор задаёт распределение

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

При τ→0\tau\to0 он приближается к argmin, а при τ→∞\tau\to\infty — к почти равномерному выбору. Рост температуры увеличивает

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

уменьшая

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

Цена — менее агрессивное использование эмпирической подгонки.

Упражнение 5. Точное разложение средней KL

Докажите

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).

Затем ответьте.

  1. Какое PP минимизирует левую часть в среднем?

  2. Почему его называют оракульным априорным распределением?

  3. При каких знаниях оно теоретически было бы допустимым в стандартной теореме?

  4. Почему на практике его нельзя оценить по той же выборке без поправки?

Показать ответ и решение

Пусть

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

а PWP_W — маргинал WW. Тогда

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}

Поскольку второй член неотрицателен, минимум по PP достигается при

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

Тогда

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

Это распределение называют оракульным априорным, потому что для его построения обычно нужно знать распределение результата алгоритма по всем возможным выборкам из неизвестного распределения данных D\mathcal D.

Здесь важно не смешать недоступность и валидность. Если D\mathcal D и условный закон алгоритма PW∣SP_{W\mid S} известны, то маргинал

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

определён до наблюдения конкретной сертифицирующей выборки. В таком идеализированном случае PWP_W является фиксированным и теоретически допустимым априорным распределением стандартной PAC-Bayes-теоремы.

На практике D\mathcal D неизвестно, поэтому возникает соблазн оценить PWP_W по текущей выборке и затем подставить эту оценку в сертификат. Это уже другой объект: априорное распределение зависит от сертифицирующих данных. Для него нужен отдельный аргумент — например, разделение выборки, иерархическая конструкция, поправка через дифференциальную приватность или специальная граница для зависящего от данных априорного распределения.

Упражнение 6. Python: смещение выбора и PAC-Bayes-сертификат

Запустите

text
M12_generalization_experiments.py

Скрипт выполняет два эксперимента.

  1. Адаптивный выбор из 32 одинаково хороших гипотез:

    • сравните смещение выбора и MI-границу;
    • проследите влияние температуры;
    • проверьте точное разложение средней KL.
  2. Стохастический линейный классификатор:

    • сравните эмпирический Gibbs-риск, диагностический тестовый риск и PAC-Bayes-kl-сертификат;
    • найдите дисперсию QQ, минимизирующую сертификат;
    • сравните точную инверсию бинарной KL с квадратным следствием.

Объясните, почему тестовый риск не входит в сертификат.

Показать ответ и решение

Скрипт воспроизводит два эксперимента.

Часть 1. Адаптивный выбор

Для argmin:

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

а MI-граница равна примерно

0.1422.0.1422.

При температуре τ=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-граница≈0.0460.\text{MI-граница} \approx0.0460.

При τ=0.5\tau=0.5 MI и разрыв становятся почти нулевыми, потому что алгоритм почти перестаёт выбирать победителя по данным.

Для τ=0.05\tau=0.05 скрипт также проверяет

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

с численной ошибкой порядка шума Монте-Карло.

Часть 2. Стохастический линейный классификатор

Лучший среди проверенных стандартных отклонений апостериорного распределения:

σQ=0.1.\sigma_Q=0.1.

Для него:

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 ната,D_{\mathrm{KL}}(Q\|P) \approx12.6653\text{ ната}, PAC-Bayes-kl-сертификат≈0.2715.\text{PAC-Bayes-kl-сертификат} \approx0.2715.

Квадратное Pinsker-следствие даёт около

0.2780,0.2780,

то есть немного более слабый результат.

Тестовый риск не входит в сертификат. Он используется только для проверки того, насколько сертификат консервативен в синтетическом мире, где мы можем сгенерировать большую независимую тестовую выборку.

Программная часть решения · один исходный файл для RU/EN

PythonM12_generalization_experiments.pyСкачать .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()

Бонус. Корректное априорное распределение по части данных

Разделите выборку на S0S_0 и S1S_1.

  1. Постройте PS0P_{S_0} по S0S_0.

  2. Обучите QS0,S1Q_{S_0,S_1}.

  3. Условившись на S0S_0, сформулируйте PAC-Bayes-границу на независимой части S1S_1.

  4. Объясните компромисс между качеством априорного распределения и размером сертифицирующей выборки.

Показать ответ и решение

Разобьём выборку:

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

причём S0S_0 и S1S_1 независимы условно на D\mathcal D как непересекающиеся i.i.d. части.

По S0S_0 строим априорное распределение

PS0.P_{S_0}.

Теперь условимся на конкретном значении S0S_0. После такого условливания PS0P_{S_0} фиксирован и не зависит от случайной сертифицирующей выборки S1S_1. Поэтому стандартная PAC-Bayes-теорема применима:

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|}.

Апостериорное распределение QQ может зависеть от обеих частей S0,S1S_0,S_1, потому что после фиксации априорного распределения граница одновременно верна для всех QQ.

Компромисс:

  • больше S0S_0 позволяет построить более информативное априорное распределение и уменьшить KL;
  • меньшее S1S_1 ухудшает концентрационный член и сокращает эффективный размер сертифицирующей выборки.