采样方法

Build~120 minutesPython先修要求: Phase 1, Lessons 06-07 (Probability, Bayes' Theorem)
采样是 AI 探索可能性空间的方式。
学习目标
  • 仅使用均匀随机数从头实现逆 CDF、拒绝采样和重要性采样
  • 为语言模型 token 生成构建 temperature、top-k 和 top-p(nucleus)采样
  • 解释重参数化技巧,以及它为何能使 VAE 中的反向传播穿过采样操作
  • 运行 Metropolis-Hastings MCMC,从非归一化的目标分布中采样

问题

语言模型处理完你的 prompt 后,会输出一个包含 50,000 个 logit 的向量,词表中每个 token 对应一个。现在它必须从中选一个。怎么选?

如果它总是选择概率最高的 token,每次回复都会一模一样——确定、单调。如果它完全均匀随机地选,输出就是乱码。答案介于这两个极端之间,而这个「中间地带」由采样控制。

采样不只用于文本生成。强化学习通过采样轨迹来估计策略梯度;VAE 通过从学习到的分布中采样并反向传播穿过随机性来学习隐表示;扩散模型通过采样噪声并迭代去噪来生成图像;蒙特卡洛方法估计没有闭式解的积分;MCMC 算法探索无法枚举的高维后验分布。

每个生成式 AI 系统都是一个采样系统。采样策略决定了输出的质量、多样性和可控性。本节课从最底层的均匀随机数开始,逐步构建每一种主要的采样方法,最终覆盖驱动现代 LLM 和生成模型的技术。

概念

为什么采样很重要

采样在 AI 和机器学习中扮演着四种基本角色:

生成。 语言模型、扩散模型和 GAN 都通过采样产生输出。采样算法直接控制创造性、连贯性和多样性。temperature、top-k 和 nucleus 采样是工程师每天调节的旋钮。

训练。 随机梯度下降采样 mini-batch;dropout 采样要关闭的神经元;数据增强采样随机变换;重要性采样通过重新加权样本来降低强化学习(PPO、TRPO)中的梯度方差。

估计。 机器学习中的许多量没有闭式解:数据分布上的期望损失、基于能量模型的配分函数、贝叶斯推断中的证据。蒙特卡洛估计通过对样本取平均来近似所有这些量。

探索。 MCMC 算法探索贝叶斯推断中的后验分布;进化策略采样参数扰动;Thompson 采样在 bandit 中平衡探索与利用。

核心挑战在于:你只能直接从简单分布(均匀、正态)中采样。对于其他所有分布,都需要一种方法把简单样本转换为目标分布的样本。

均匀随机采样

每种采样方法都从这里开始。均匀随机数生成器在 [0, 1) 上产生数值,等长子区间具有相等概率。

U ~ Uniform(0, 1)

P(a <= U <= b) = b - a    for 0 <= a <= b <= 1

Properties:
  E[U] = 0.5
  Var(U) = 1/12

要从 n 个离散项中均匀采样,生成 U 并返回 \lfloor n U \rfloor。要从连续区间 [a, b] 中采样,计算 a + (b - a) U。

关键洞察:单个均匀随机数恰好包含产生任意分布一个样本所需的全部随机性。难点在于找到正确的变换。

逆 CDF 方法(逆变换采样)

累积分布函数(CDF)将数值映射为概率:

F(x) = P(X <= x)

Properties:
  F is non-decreasing
  F(-inf) = 0
  F(+inf) = 1
  F maps the real line to [0, 1]

逆 CDF 把概率映射回数值。如果 U \sim \text{Uniform}(0, 1),那么 X = F^{-1}(U) 服从目标分布。

Algorithm:
  1. Generate u ~ Uniform(0, 1)
  2. Return F_inverse(u)

Why it works:
  P(X <= x) = P(F_inverse(U) <= x) = P(U <= F(x)) = F(x)

指数分布示例:

PDF: f(x) = lambda * exp(-lambda * x),   x >= 0
CDF: F(x) = 1 - exp(-lambda * x)

Solve F(x) = u for x:
  u = 1 - exp(-lambda * x)
  exp(-lambda * x) = 1 - u
  x = -ln(1 - u) / lambda

Since (1 - U) and U have the same distribution:
  x = -ln(u) / lambda

当你能写出闭式 F^{-1} 时,这种方法完美无缺。对于正态分布,没有闭式逆 CDF,因此需要使用其他方法(Box-Muller 或数值近似)。

离散版本: 对于离散分布,将 CDF 构建为累积和,生成 U,找到累积和首次超过 U 的索引。这就是第 06 课中 sample_categorical 的工作原理。

拒绝采样

当你无法求逆 CDF,但可以计算目标 PDF(允许差一个常数因子)时,拒绝采样就能工作。

Target distribution: p(x)  (can evaluate, possibly unnormalized)
Proposal distribution: q(x)  (can sample from)
Bound: M such that p(x) <= M * q(x) for all x

Algorithm:
  1. Sample x ~ q(x)
  2. Sample u ~ Uniform(0, 1)
  3. If u < p(x) / (M * q(x)), accept x
  4. Otherwise, reject and go to step 1

Acceptance rate = 1/M

边界 M 越紧,接受率越高。在低维(1-3 维)中拒绝采样效果很好。在高维中,接受率指数级下降,因为提议分布的大部分体积都会被拒绝。这就是拒绝采样的维度灾难。

示例:从截断正态分布中采样。 在截断区间上使用均匀提议分布。包络 M 取该区间内正态 PDF 的最大值。

示例:从半圆中采样。 在包围矩形内均匀提议,接受落在半圆内的点。这就是蒙特卡洛计算 \pi 的方式:接受率等于面积比 \pi/4。

重要性采样

有时你不需要目标分布 p(x) 的样本,而是要估计 p(x) 下的期望,而你拥有的样本来自另一个分布 q(x)。

Goal: estimate E_p[f(x)] = integral of f(x) * p(x) dx

Rewrite:
  E_p[f(x)] = integral of f(x) * (p(x)/q(x)) * q(x) dx
            = E_q[f(x) * w(x)]

where w(x) = p(x) / q(x)  are the importance weights.

Estimator:
  E_p[f(x)] ~ (1/N) * sum(f(x_i) * w(x_i))    where x_i ~ q(x)

这在强化学习中至关重要。在 PPO(Proximal Policy Optimization)中,你在旧策略 \pi_{\text{old}} 下收集轨迹,但希望优化新策略 \pi_{\text{new}}。重要性权重为 \pi_{\text{new}}(a \mid s) / \pi_{\text{old}}(a \mid s)。PPO 会裁剪这些权重,防止新策略偏离旧策略过远。

重要性采样估计量的方差取决于 q 与 p 的相似程度。如果 q 与 p 差异很大,少数样本会获得巨大权重并主导估计。自归一化重要性采样通过除以权重之和来缓解这个问题:

\mathbb{E}_p[f(x)] \approx \frac{\sum_i w_i \, f(x_i)}{\sum_i w_i}

蒙特卡洛估计

蒙特卡洛估计通过随机样本的平均来近似积分。大数定律保证其收敛。

Goal: estimate I = integral of g(x) dx over domain D

Method:
  1. Sample x_1, ..., x_N uniformly from D
  2. I ~ (Volume of D / N) * sum(g(x_i))

Error: O(1 / sqrt(N))   regardless of dimension

误差率与维度无关。这就是为什么蒙特卡洛方法在高维中占据主导,而基于网格的积分则不可行。

估计 pi:

Sample (x, y) uniformly from [-1, 1] x [-1, 1]
Count how many fall inside the unit circle: x^2 + y^2 <= 1
pi ~ 4 * (count inside) / (total count)

估计期望:

E[f(X)] ~ (1/N) * sum(f(x_i))    where x_i ~ p(x)

The sample mean converges to the true expectation.
Variance of the estimator = Var(f(X)) / N

马尔可夫链蒙特卡洛(MCMC):Metropolis-Hastings 算法

MCMC 构建一个马尔可夫链,使其平稳分布就是目标分布 p(x)。经过足够多的步数后,链上的样本就近似来自 p(x) 的样本。

Target: p(x)  (known up to a normalizing constant)
Proposal: q(x'|x)  (how to propose the next state given the current state)

Metropolis-Hastings algorithm:
  1. Start at some x_0
  2. For t = 1, 2, ..., T:
     a. Propose x' ~ q(x'|x_t)
     b. Compute acceptance ratio:
        alpha = [p(x') * q(x_t|x')] / [p(x_t) * q(x'|x_t)]
     c. Accept with probability min(1, alpha):
        - If u < alpha (u ~ Uniform(0,1)): x_{t+1} = x'
        - Otherwise: x_{t+1} = x_t
  3. Discard first B samples (burn-in)
  4. Return remaining samples

对于对称提议分布 (q(x' \mid x) = q(x \mid x')),比率简化为 p(x')/p(x)。这就是原始的 Metropolis 算法。

为什么它有效。 接受规则保证了细致平衡:处于 x 并移动到 x' 的概率,等于处于 x' 并移动到 x 的概率。细致平衡意味着 p(x) 是链的平稳分布。

实际考虑:

  • Burn-in:在链达到平衡前丢弃早期样本
  • Thinning:每隔 k 个样本保留一个,以降低自相关
  • 提议尺度:太小则链移动缓慢(接受率高但探索慢);太大则大部分提议被拒绝(接受率低,原地踏步)
  • 高维中高斯提议的最优接受率约为 0.234

Gibbs 采样

Gibbs 采样是 MCMC 在多变量分布上的特例。它不是一次性在所有维度上提议移动,而是每次只从一个变量的条件分布中更新该变量。

Target: p(x_1, x_2, ..., x_d)

Algorithm:
  For each iteration t:
    Sample x_1^{t+1} ~ p(x_1 | x_2^t, x_3^t, ..., x_d^t)
    Sample x_2^{t+1} ~ p(x_2 | x_1^{t+1}, x_3^t, ..., x_d^t)
    ...
    Sample x_d^{t+1} ~ p(x_d | x_1^{t+1}, x_2^{t+1}, ..., x_{d-1}^{t+1})

Gibbs 采样要求你能从每个条件分布 p(x_i \mid x_{-i}) 中采样。这对许多模型都很直接:

  • 贝叶斯网络:条件分布由图结构决定
  • 高斯混合:条件分布是高斯分布
  • 伊辛模型:每个自旋的条件只依赖于其邻居

接受率始终为 1(每个提议都被接受),因为从精确的条件分布中采样自动满足细致平衡。

局限。 当变量高度相关时,Gibbs 采样混合得很慢,因为每次只更新一个变量无法在对角线上大幅移动。

温度采样(用于 LLM)

语言模型为词表中的每个 token 输出 logit z_1, \ldots, z_V。softmax 将其转换为概率。temperature 在 softmax 之前重新缩放 logit:

p_i = exp(z_i / T) / sum(exp(z_j / T))

T = 1.0: standard softmax (original distribution)
T -> 0:  argmax (deterministic, always picks highest logit)
T -> inf: uniform (all tokens equally likely)
T < 1.0: sharpens the distribution (more confident, less diverse)
T > 1.0: flattens the distribution (less confident, more diverse)

为什么它有效。 用 T < 1 去除 logit 会放大 logit 之间的差距。若 z_1 = 2、z_2 = 1,用 T = 0.5 除后得到 z_1/T = 4、z_2/T = 2,差距变大。softmax 后,最高 logit 的 token 获得更大的概率份额。

实践中:

  • T = 0.0:贪心解码,最适合事实性问答
  • T = 0.3\text{-}0.7:略带创造性,适合代码生成
  • T = 0.7\text{-}1.0:平衡,适合一般对话
  • T = 1.0\text{-}1.5:创意写作、头脑风暴
  • T > 1.5:越来越随机,很少有用

温度不改变哪些 token 是可能的。它改变的是分配给每个 token 的概率质量。

Top-k 采样

Top-k 采样将候选集限制为概率最高的 k 个 token,然后重新归一化并从该受限集合中采样。

Algorithm:
  1. Compute softmax probabilities for all V tokens
  2. Sort tokens by probability (descending)
  3. Keep only the top k tokens
  4. Renormalize: p_i' = p_i / sum(p_j for j in top-k)
  5. Sample from the renormalized distribution

k = 1:  greedy decoding
k = V:  no filtering (standard sampling)
k = 40: typical setting, removes long tail of unlikely tokens

Top-k 防止模型选择概率分布长尾中极不可能的 token(错字、无意义内容)。问题是 k 是固定的,与上下文无关。当模型很自信(某个 token 概率为 95%)时,k = 40 仍允许 39 个替代项;当模型不确定(概率分散在 1000 个 token 上)时,k = 40 会切断合理的选项。

Top-p(核)采样

Top-p 采样动态调整候选集大小。它保留最小的 token 集合,使其累积概率超过 p。

Algorithm:
  1. Compute softmax probabilities for all V tokens
  2. Sort tokens by probability (descending)
  3. Find smallest k such that sum of top-k probabilities >= p
  4. Keep only those k tokens
  5. Renormalize and sample

p = 0.9:  keeps tokens covering 90% of probability mass
p = 1.0:  no filtering
p = 0.1:  very restrictive, nearly greedy

当模型自信时,核采样只保留少量 token(可能 2-3 个);当模型不确定时,它保留很多(可能 200 个)。这种自适应行为就是核采样通常比 top-k 产生更好文本的原因。

常见组合:

  • Temperature 0.7 + top-p 0.9:通用好设置
  • Temperature 0.0(贪心):确定性任务的最佳选择
  • Temperature 1.0 + top-k 50:Fan 等人(2018)原始论文设置

Top-k 和 top-p 可以组合使用。先应用 top-k,再对剩余集合应用 top-p。

重参数化技巧(用于 VAE)

变分自编码器(VAE)通过将输入编码为隐空间分布、从该分布采样、再解码样本来学习。问题是你无法反向传播穿过采样操作。

Standard sampling (not differentiable):
  z ~ N(mu, sigma^2)

  The randomness blocks gradient flow.
  d/d_mu [sample from N(mu, sigma^2)] = ???

重参数化技巧将随机性与参数分离:

Reparameterized sampling:
  epsilon ~ N(0, 1)          (fixed random noise, no parameters)
  z = mu + sigma * epsilon   (deterministic function of parameters)

  Now z is a deterministic, differentiable function of mu and sigma.
  d(z)/d(mu) = 1
  d(z)/d(sigma) = epsilon

  Gradients flow through mu and sigma.

这是因为 \mathcal{N}(\mu, \sigma^2) 与 \mu + \sigma \cdot \mathcal{N}(0, 1) 同分布。关键洞察:把随机性转移到一个无参数的源(\epsilon),然后把样本表示为参数的可微变换。

在 VAE 训练循环中:

  1. 编码器为每个输入输出 \mu 和 \log(\sigma^2)
  2. 采样 \epsilon \sim \mathcal{N}(0, 1)
  3. 计算 z = \mu + \sigma \epsilon
  4. 解码 z 以重建输入
  5. 反向传播穿过第 4、3、2、1 步(因为第 3 步可微)

没有重参数化技巧,VAE 就无法用标准反向传播训练。这一单独洞察使 VAE 变得实用。

Gumbel-Softmax(可微分分类采样)

重参数化技巧适用于连续分布(高斯分布)。对于离散分类分布,需要另一种方法。Gumbel-Softmax 提供了分类采样的可微近似。

Gumbel-Max 技巧(不可微):

To sample from a categorical distribution with log-probabilities log(p_1), ..., log(p_k):
  1. Sample g_i ~ Gumbel(0, 1) for each category
     (g = -log(-log(u)), where u ~ Uniform(0, 1))
  2. Return argmax(log(p_i) + g_i)

This produces exact categorical samples.

Gumbel-Softmax(可微近似):

Replace the hard argmax with a soft softmax:
  y_i = exp((log(p_i) + g_i) / tau) / sum(exp((log(p_j) + g_j) / tau))

tau (temperature) controls the approximation:
  tau -> 0:  approaches a one-hot vector (hard categorical)
  tau -> inf: approaches uniform (1/k, 1/k, ..., 1/k)
  tau = 1.0: soft approximation

Gumbel-Softmax 产生离散样本的连续松弛。输出是概率向量(软 one-hot)而非硬 one-hot。梯度流经 softmax。训练的前向传播中,可以使用 straight-through 估计器:前向传播用硬 argmax,反向传播用软 Gumbel-Softmax 梯度。

应用:

  • VAE 中的离散隐变量
  • 神经网络架构搜索(选择离散操作)
  • 硬注意力机制
  • 离散动作强化学习

分层采样

标准蒙特卡洛采样可能偶然在样本空间中留下空隙。分层采样通过将空间划分为若干层并从每层采样来强制均匀覆盖。

Standard Monte Carlo:
  Sample N points uniformly from [0, 1]
  Some regions may have clusters, others gaps

Stratified sampling:
  Divide [0, 1] into N equal strata: [0, 1/N), [1/N, 2/N), ..., [(N-1)/N, 1)
  Sample one point uniformly within each stratum
  x_i = (i + u_i) / N   where u_i ~ Uniform(0, 1),  i = 0, ..., N-1

分层采样的方差总是小于或等于标准蒙特卡洛:

Var(stratified) <= Var(standard Monte Carlo)

The improvement is largest when f(x) varies smoothly.
For piecewise-constant functions, stratified sampling is exact.

应用:

  • 数值积分(拟蒙特卡洛)
  • 训练数据划分(确保每折类别平衡)
  • 与分层结合的重要性采样
  • NeRF(Neural Radiance Fields)沿相机光线使用分层采样

与扩散模型的联系

扩散模型通过采样过程生成图像。前向过程在 T 步内逐渐向图像添加高斯噪声,直到变成纯噪声。反向过程学习去噪,逐步恢复原始图像。

Forward process (known):
  x_t = sqrt(alpha_t) * x_{t-1} + sqrt(1 - alpha_t) * epsilon
  where epsilon ~ N(0, I)

  After T steps: x_T ~ N(0, I)  (pure noise)

Reverse process (learned):
  x_{t-1} = (1/sqrt(alpha_t)) * (x_t - (1 - alpha_t)/sqrt(1 - alpha_bar_t) * epsilon_theta(x_t, t)) + sigma_t * z
  where z ~ N(0, I)

  Each denoising step is a sampling step.

与本节课方法之间的联系:

  • 每个去噪步骤都使用重参数化技巧(采样噪声,应用确定性变换)
  • 噪声调度 \lbrace \alpha_t \rbrace 控制一种形式的温度退火
  • 训练使用蒙特卡洛估计来近似 ELBO(evidence lower bound)
  • 扩散模型中的 ancestral 采样是一个马尔可夫链(每步只依赖当前状态)

整个图像生成过程就是迭代采样:从噪声开始,每一步都采样一个以学习到的去噪模型为条件的、噪声略小的版本。

monte-carlo-pi静态版本未包含此交互图

构建它

第 1 步:均匀采样与逆 CDF 采样

pythonimport math
import random

def sample_uniform(a, b):
    return a + (b - a) * random.random()

def sample_exponential_inverse_cdf(lam):
    u = random.random()
    return -math.log(u) / lam

生成 10,000 个指数样本,并验证均值是否为 1/\lambda。

第 2 步:拒绝采样

pythondef rejection_sample(target_pdf, proposal_sample, proposal_pdf, M):
    while True:
        x = proposal_sample()
        u = random.random()
        if u < target_pdf(x) / (M * proposal_pdf(x)):
            return x

使用拒绝采样从截断正态分布中抽取样本。通过直方图验证样本形状。

第 3 步:重要性采样

pythondef importance_sampling_estimate(f, target_pdf, proposal_pdf, proposal_sample, n):
    total = 0
    for _ in range(n):
        x = proposal_sample()
        w = target_pdf(x) / proposal_pdf(x)
        total += f(x) * w
    return total / n

使用均匀提议估计正态分布下 \mathbb{E}[X^2]。与已知答案(\mu^2 + \sigma^2)比较。

第 4 步:蒙特卡洛估计 pi

pythondef monte_carlo_pi(n):
    inside = 0
    for _ in range(n):
        x = random.uniform(-1, 1)
        y = random.uniform(-1, 1)
        if x*x + y*y <= 1:
            inside += 1
    return 4 * inside / n

第 5 步:Metropolis-Hastings MCMC

pythondef metropolis_hastings(target_log_pdf, proposal_sample, proposal_log_pdf, x0, n_samples, burn_in):
    samples = []
    x = x0
    for i in range(n_samples + burn_in):
        x_new = proposal_sample(x)
        log_alpha = (target_log_pdf(x_new) + proposal_log_pdf(x, x_new)
                     - target_log_pdf(x) - proposal_log_pdf(x_new, x))
        if math.log(random.random()) < log_alpha:
            x = x_new
        if i >= burn_in:
            samples.append(x)
    return samples

从双峰分布(两个高斯混合)中采样。可视化链的轨迹。

第 6 步:Gibbs 采样

pythondef gibbs_sampling_2d(conditional_x_given_y, conditional_y_given_x, x0, y0, n_samples, burn_in):
    x, y = x0, y0
    samples = []
    for i in range(n_samples + burn_in):
        x = conditional_x_given_y(y)
        y = conditional_y_given_x(x)
        if i >= burn_in:
            samples.append((x, y))
    return samples

第 7 步:温度采样

pythondef softmax(logits):
    max_l = max(logits)
    exps = [math.exp(z - max_l) for z in logits]
    total = sum(exps)
    return [e / total for e in exps]

def temperature_sample(logits, temperature):
    scaled = [z / temperature for z in logits]
    probs = softmax(scaled)
    return sample_from_probs(probs)

展示温度如何改变一组 token logit 的输出分布。

第 8 步:Top-k 与 top-p 采样

pythondef top_k_sample(logits, k):
    indexed = sorted(enumerate(logits), key=lambda x: -x[1])
    top = indexed[:k]
    top_logits = [l for _, l in top]
    probs = softmax(top_logits)
    idx = sample_from_probs(probs)
    return top[idx][0]

def top_p_sample(logits, p):
    probs = softmax(logits)
    indexed = sorted(enumerate(probs), key=lambda x: -x[1])
    cumsum = 0
    selected = []
    for token_idx, prob in indexed:
        cumsum += prob
        selected.append((token_idx, prob))
        if cumsum >= p:
            break
    sel_probs = [pr for _, pr in selected]
    total = sum(sel_probs)
    sel_probs = [pr / total for pr in sel_probs]
    idx = sample_from_probs(sel_probs)
    return selected[idx][0]

第 9 步:重参数化技巧

pythondef reparam_sample(mu, sigma):
    epsilon = random.gauss(0, 1)
    return mu + sigma * epsilon

def reparam_gradient(mu, sigma, epsilon):
    dz_dmu = 1.0
    dz_dsigma = epsilon
    return dz_dmu, dz_dsigma

演示梯度可以流经重参数化样本,但不能流经直接采样。

第 10 步:Gumbel-Softmax

pythondef gumbel_sample():
    u = random.random()
    return -math.log(-math.log(u))

def gumbel_softmax(logits, temperature):
    gumbels = [math.log(p) + gumbel_sample() for p in logits]
    return softmax([g / temperature for g in gumbels])

展示降低温度如何让输出趋近 one-hot 向量。

完整实现及所有可视化见 code/sampling.py。

使用它

使用 NumPy 和 SciPy 的生产级版本:

pythonimport numpy as np

rng = np.random.default_rng(42)

exponential_samples = rng.exponential(scale=2.0, size=10000)
print(f"Exponential mean: {exponential_samples.mean():.4f} (expected 2.0)")

from scipy import stats
normal = stats.norm(loc=0, scale=1)
print(f"CDF at 1.96: {normal.cdf(1.96):.4f}")
print(f"Inverse CDF at 0.975: {normal.ppf(0.975):.4f}")

logits = np.array([2.0, 1.0, 0.5, 0.1, -1.0])
temperature = 0.7
scaled = logits / temperature
probs = np.exp(scaled - scaled.max()) / np.exp(scaled - scaled.max()).sum()
token = rng.choice(len(logits), p=probs)
print(f"Sampled token index: {token}")

对于大规模 MCMC,使用专门库:

  • PyMC:完整的贝叶斯建模,使用 NUTS(自适应 HMC)
  • emcee:集成 MCMC 采样器
  • NumPyro/JAX:GPU 加速 MCMC

你已经从头构建了这些方法。现在你知道这些库调用背后的原理了。

练习

  1. 为柯西分布实现逆 CDF 采样。其 CDF 为 F(x) = 0.5 + \arctan(x)/\pi。生成 10,000 个样本并绘制直方图与真实 PDF 对比。注意重尾(远离中心的极端值)。
  1. 使用拒绝采样,用 Uniform(0, 1) 提议分布生成 Beta(2, 5) 分布的样本。将接受样本与真实 Beta PDF 绘图对比。理论接受率是多少?
  1. 用蒙特卡洛估计 \sin(x) 从 0 到 \pi 的积分,分别使用 1,000、10,000 和 100,000 个样本。比较每个规模下的误差。验证误差按 O(1/\sqrt{N}) 缩放。
  1. 实现 Metropolis-Hastings 算法,从二维分布 p(x, y) 正比于 \exp(-(x^2 y^2 + x^2 + y^2 - 8x - 8y) / 2) 中采样。绘制样本和链轨迹。尝试不同的提议标准差。
  1. 构建完整文本生成 demo:给定包含 10 个词的词表和对应 logit,使用 (a) 贪心、(b) temperature=0.7、(c) top-k=3、(d) top-p=0.9 生成 20 个 token 的序列。比较 5 次运行中输出的多样性。

提示

练习 1。 解 u = F(x) 得到 x = \tan(\pi(u - 0.5))。检查样本中位数接近 0,且约 6% 的样本满足 \lvert x \rvert > 10,即 1 - (2/\pi)\arctan(10)。

练习 2。 Beta(2, 5) 密度为 30x(1-x)^4。在众数 x = 1/5 处找到最大值并作为 rejection_sample 中的 M。理论接受率为 1/M,因此可与你实际接受的比例比较。

练习 3。 精确值为 2。对每个 n 调用 monte_carlo_integral(math.sin, 0, math.pi, n),并用多个种子重复运行。当 n 增大 10 倍时,平均误差应下降约 \sqrt{10} \approx 3.2。

练习 4。 写出目标的对数,即 -(x^2 y^2 + x^2 + y^2 - 8x - 8y)/2,并传给 metropolis_hastings_2d。记录每种提议标准差下的接受率:过小的值几乎接受每一步但移动缓慢,过大的值几乎拒绝每一步。

练习 5。 贪心解码每步取最大 logit 的索引。其他三种方法分别使用 temperature_sample、top_k_sample 和 top_p_sample。贪心在 5 次运行中必须给出相同序列,因此统计每种方法产生不同序列的数量来衡量多样性。

关键术语

术语人们常说实际含义
Sampling"抽取随机值"按照概率分布生成数值。所有生成式 AI 背后的机制
Uniform distribution"全都一样可能"[a, b] 内每个值的概率密度均为 1/(b-a)。所有采样方法的起点
Inverse CDF"概率变换"F^{-1}(U) 将均匀样本转换为任意已知 CDF 分布的样本。精确且高效
Rejection sampling"提议并接受/拒绝"从简单提议分布生成,按目标/提议比例的概率接受。精确但浪费样本
Importance sampling"重新加权样本"用来自 q(x) 的样本,通过权重 p(x)/q(x) 估计 p(x) 下的期望。强化学习中 PPO 的核心
Monte Carlo"随机样本取平均"将积分近似为样本平均。误差 O(1/\sqrt{N}),与维度无关
MCMC"会收敛的随机游走"构造平稳分布为目标的马尔可夫链。Metropolis-Hastings 是基础算法
Metropolis-Hastings"大概率上山,偶尔下山"提议移动,按密度比决定是否接受。细致平衡保证收敛到目标分布
Gibbs sampling"一次更新一个变量"固定其他变量,从每个变量的条件分布中更新。接受率 100%
Temperature"置信度旋钮"在 softmax 前将 logit 除以 T。T<1 锐化(更自信),T>1 拉平(更多样)
Top-k sampling"保留最好的 k 个"只保留概率最高的 k 个 token,重新归一化后采样。候选集大小固定
Nucleus sampling (top-p)"保留可能的那些"保留累积概率超过 p 的最小 token 集合。候选集大小自适应
Reparameterization trick"把随机性移到外面"写成 z = \mu + \sigma \epsilon,其中 \epsilon \sim \mathcal{N}(0,1)。让采样可微。VAE 训练的关键
Gumbel-Softmax"软分类采样"用 Gumbel 噪声 + 带温度的 softmax 对分类采样做可微近似
Stratified sampling"强制覆盖"将样本空间分层,每层都采样。方差总是低于朴素蒙特卡洛
Burn-in"预热期"链达到平稳分布前丢弃的初始 MCMC 样本
Detailed balance"可逆性条件"p(x) T(x \to y) = p(y) T(y \to x)。p 是马尔可夫链平稳分布的充分条件
Diffusion sampling"迭代去噪"从噪声出发,应用学习到的去噪步骤生成数据。每步都是条件采样操作

延伸阅读

“Stay hungry, stay foolish.”

— Steve Jobs

esc
↑↓切换↵打开esc关闭