✨ 复制成功!

以文会友,打造好学人设!

📋 已复制到剪贴板:

《PyTorch入门精华》


1 前言
    1.1  PyTorch安装

    1.2  显卡驱动的困惑

    1.3  CUDA安装注意事项

    1.4  cuDNN的介绍

    1.5  Pytorch Lightning介绍

    1.6  PyTorch学习之道

    1.7  PyTorch快速入门

    1.8  PyTorch调参之道

    1.9  PyTorch调参套件

    1.10  手动创建虚拟环境

2 深度学习之数学基础
    2.1  希腊字母解读

    2.2  梯度的物理意义

    2.3  图解梯度下降法

    2.4  图解梯度上升法

    2.5  自然梯度

    2.6  泰勒公式的介绍

    2.7  信息与信息熵

    2.8  重要性采样

    2.10  欧几里得范数

    2.11  特征值和特征向量

    2.12  似然函数的理解

    2.13  矩阵秩的深刻理解

3 PyTorch入门疑难点
4 PyTorch全局设置
    4.1  全局设置当前设备

    4.2  全局设置浮点精度

5 PyTorch GPU分布式训练
    5.1  PyTorch GPU基础操作

    5.2  DataParallel用法详解

    5.3  GPU分布式训练模型

    5.4  CUDA_VISIBLE_DEVICES

    5.5  device详细说明

    5.6  to(device)和.cuda()

    5.7  CUDA设备索引

    5.8  GPU设备索引

6 向量的基础与核心
    6.1  Tensor的组成与存储

    6.2  Tensor的grad属性

    6.4  Tensor的叠加

    6.5  禁用梯度计算

    6.6  向量的保存和加载

    6.7  参数向量

    6.8  叶子节点

    6.9  detach原理

    6.10  requires_grad属性

    6.11  Tensor与Numpy互换

    6.12  张量cat操作

    6.13  零维张量

    6.15  squeeze/unsqu...函数

    6.16  argmax和max的区别

    6.17  torch.as_tensor的应用

7 神经网络基础
    7.2  PyTorch计算图

    7.3  查看网络权重参数

    7.4  保存模型

    7.5  Adam相关面试题

    7.6  Train模式和Eval模式

    7.7  线性网络

    7.8  双线性网络

    7.9  惰性线性层

    7.10  PyTorch中的自动微分

    7.12  Dropout机制

    7.13  半精度训练

    7.14  Xavier初始化

    7.15  注意力机制

    7.16  Dataset数据处理

    7.17  StepLR学习率调度器

    7.18  词嵌入的理解

    7.19  TensorDataset的使用

    7.20  模型的保存与加载

    7.21  ModuleList和Sequential

    7.22  Batch Normalization介绍

8 计算机视觉基础知识
    8.1  通道的深刻理解

    8.2  1x1卷积的作用

    8.3  特征提取和可视化

    8.4  反卷积的推导

    8.5  理解卷积

    8.7  空洞卷积

    8.8  池化层的作用

    8.9  感受野与特征图

    8.10  NMS算法

    8.11  特征图尺寸计算

9 循环神经网络基础
    9.2  RNN的介绍

10 注意力机制
    10.1  位置编码的作用

    10.2  位置编码的种类

    10.4  Embedding本质理解

    10.6  Transformer VS CNN/RNN

    10.7  ELMo介绍

11 PyTorch归一化
    11.2  层归一化技术详解

12 激活函数相关内容
    12.1  激活函数简介

    12.2  万能逼近定理

    12.3  指数函数的学习

    12.4  Sigmoid函数的介绍

    12.5  Tanh函数的介绍

    12.6  Softmax函数的实现

    12.7  ReLU函数的介绍

    12.8  Leaky Relu函数的介绍

    12.9  ReLu与非线性的理解

    12.10  Parametric ReLU函数

    12.11  ELU函数介绍

    12.12  神经元死亡的问题

13 思考题的答案
    13.1  思考题的答案解密

重要性采样

创建时间:2025-02-15 更新时间:2025-02-23 阅读次数:1659 次

导读

重要性采样(Importance Sampling)是一种用于估计期望值的统计方法,特别适用于从难以直接采样的分布中获取样本的情况。其核心思想是通过一个易于采样的提议分布(proposal distribution)来近似目标分布(target distribution),从而计算期望值

重要性采样的本质是计算期望值,在《概率论》这门学科中,计算期望值是最核心的基础操作,重要性采样从另外一个角度告诉人们如何计算期望值的方式,它通过从一个易于采样的分布中抽取样本,并对这些样本进行加权,来估计目标分布的期望值。

1、基本概念

  • 目标分布:我们想要从中采样的分布 $p(x)$,通常是难以直接采样的。

  • 提议分布:一个易于采样的分布$q(x)$,用于近似目标分布。

  • 重要性权重:用于调整从提议分布中采样的样本,使其能够反映目标分布的特性。权重定义为$w(x_i) = \frac{p(x_i)}{q(x_i)}$。

2、期望值估计

假设我们想要估计函数 $f(x)$ 在目标分布 $p(x)$ 下的期望值:

$$\mathbb{E}_{p(x)}[f(x)] = \int f(x) p(x) \, dx$$

通过重要性采样,可以将其转化为在提议分布$q(x)$下的期望值:

$$\mathbb{E}_{p(x)}[f(x)] = \int f(x) \frac{p(x)}{q(x)} q(x) \,dx$$

$$= \mathbb{E}_{q(x)}[f(x) \frac{p(x)}{q(x)}]$$

因此,我们可以从 $q(x)$ 中采样,并计算加权平均: $$\hat{\mu} = \frac{1}{N} \sum_{i=1}^N f(x_i) w(x_i)$$

其中,$w(x_i) = \frac{p(x_i)}{q(x_i)}$

3、重要性采样的优缺点分析

优点:

能够处理难以直接采样的目标分布。

通过选择合适的提议分布,可以提高估计的效率和准确性。

缺点:

如果提议分布 $q(x)$ 与目标分布$p(x)$ 差异较大,可能导致权重分布不均,估计方差增大。

需要计算重要性权重,可能增加计算复杂度。

4、重要性采样的应用场景

重要性采样广泛应用于蒙特卡洛方法、贝叶斯推断、强化学习等领域,尤其是在高维空间或复杂分布中。

5、疑问

既然目标分布难以采样,怎么在计算权重的时候又出现了目标分布呢?

这是一个非常好的问题!重要性采样中的核心矛盾在于:目标分布 $p(x)$ 难以直接采样,但我们仍然需要知道它的形式(或至少知道它的未归一化形式)来计算权重。

6、通俗易懂的例子

重要性采样是一种通过改变采样分布来提高估计效率的方法。以下是一个通俗易懂的例子(估计一个稀有事件的概率):

假设你有一个不均匀的骰子,掷出6的概率非常低(比如0.1%),你想估计这个概率。如果直接用蒙特卡洛方法,可能需要掷很多次骰子才能观察到几次6,效率很低。

在此情况下,可以应用重要性采样,总共分为下面三个过程:

  • 1、改变采样分布:你可以设计一个“偏向”骰子,使得掷出6的概率更高(比如10%)。这样,你更容易观察到6。

  • 2、加权调整:每次掷出6时,记录结果并乘以一个权重,这个权重是原始分布与改变后分布的概率比。例如,如果原始概率是0.1%,改变后是10%,那么权重就是0.1% / 10% = 0.01。

  • 3、计算估计值:通过多次掷骰,记录加权结果并取平均,得到更准确的估计。

总之,重要性采样通过增加稀有事件的采样频率,并用权重调整结果,从而在较少样本下获得更精确的估计。这个方法在金融风险评估、物理模拟等领域有广泛应用。

重要性采样的代码实现

下面是使用 PyTorch 实现重要性采样的代码。我们将使用 PyTorch 的张量操作和随机数生成功能来实现上述逻辑。

import torch

# 目标分布 p(x) = exp(-x^2 / 2) / sqrt(2 * pi)
def target_distribution(x):
    return torch.exp(-x**2 / 2) / torch.sqrt(2 * torch.tensor(torch.pi))

# 提议分布 q(x) = 1 / (1 + x^2) / pi
def proposal_distribution(x):
    return 1 / (1 + x**2) / torch.tensor(torch.pi)

# 从提议分布中采样(柯西分布)
def sample_from_proposal(n_samples):
    return torch.tan(torch.tensor(torch.pi) * (torch.rand(n_samples) - 0.5))

# 重要性采样
def importance_sampling(n_samples):
    samples = sample_from_proposal(n_samples)
    weights = target_distribution(samples) / proposal_distribution(samples)
    return samples, weights

# 估计期望值
def estimate_expectation(n_samples):
    samples, weights = importance_sampling(n_samples)
    expectation = torch.mean(samples * weights)
    return expectation

# 参数设置
n_samples = 10000

# 估计期望值
estimated_expectation = estimate_expectation(n_samples)
print(f"Estimated Expectation: {estimated_expectation.item()}")

代码解释

目标分布:

target_distribution(x) 是标准正态分布的概率密度函数。

使用 PyTorch 的 torch.exp 和 torch.sqrt 实现。

提议分布:

proposal_distribution(x) 是柯西分布的概率密度函数。

柯西分布的公式为 $q(x)= \frac{ π(1+x^2)}{1}$

从提议分布中采样:

柯西分布可以通过均匀分布生成:$x = \tan(\pi (u - 0.5))$,其中$u \sim \text{Uniform}(0,1)$。

使用 torch.rand 生成均匀分布,并通过变换得到柯西分布的样本。

重要性采样:

计算每个样本的权重:$w(x_i) = \frac{p(x_i)}{q(x_i)}$

使用 PyTorch 的张量操作计算权重。

估计期望值:

使用加权样本计算期望值:$\mathbb{E}[x] \sim \tfrac{1}{N} \sum_{i=1}^N x_i w(x_i)$

使用 torch.mean 计算加权平均值。

运行结果

运行代码后,你会得到一个估计的期望值。由于目标分布是标准正态分布,期望值应该接近 0。例如:

Estimated Expectation: 0.0123

重要性采样,如果目标分布一点都不知道,那该怎么办呢?

如果目标分布完全未知,重要性采样的直接应用会变得困难,因为我们需要知道目标分布的概率密度函数(PDF)来计算权重。然而,即使目标分布未知,仍然有一些方法可以尝试解决这个问题。以下是几种可能的解决方案:

1. 使用近似目标分布

如果目标分布未知,但我们可以从目标分布中采样(例如通过实验或模拟),则可以通过以下步骤近似目标分布:

步骤 1:从目标分布中收集一些样本。

步骤 2:使用这些样本来拟合一个近似的概率分布(例如高斯混合模型、核密度估计等)。

步骤 3:将拟合的分布作为目标分布的近似,然后进行重要性采样。

代码示例:使用核密度估计(KDE)近似目标分布

import torch
from sklearn.neighbors import KernelDensity

# 假设我们有一些从目标分布中采样的数据
target_samples = torch.randn(1000)  # 例如,目标分布是标准正态分布

# 使用核密度估计(KDE)拟合目标分布
kde = KernelDensity(kernel="gaussian", bandwidth=0.5).fit(target_samples.reshape(-1, 1))

# 定义近似的目标分布
def approximate_target_distribution(x):
    log_prob = kde.score_samples(x.reshape(-1, 1))
    return torch.tensor(np.exp(log_prob))

# 提议分布(例如柯西分布)
def proposal_distribution(x):
    return 1 / (1 + x**2) / torch.tensor(torch.pi)

# 从提议分布中采样
def sample_from_proposal(n_samples):
    return torch.tan(torch.tensor(torch.pi) * (torch.rand(n_samples) - 0.5))

# 重要性采样
def importance_sampling(n_samples):
    samples = sample_from_proposal(n_samples)
    weights = approximate_target_distribution(samples) / proposal_distribution(samples)
    return samples, weights

# 估计期望值
def estimate_expectation(n_samples):
    samples, weights = importance_sampling(n_samples)
    expectation = torch.mean(samples * weights)
    return expectation

# 参数设置
n_samples = 10000

# 估计期望值
estimated_expectation = estimate_expectation(n_samples)
print(f"Estimated Expectation: {estimated_expectation.item()}")

2. 使用无模型方法(Model-Free Methods)

如果目标分布完全未知且无法采样,但仍然可以评估某个函数在目标分布下的期望值(例如通过实验或模拟),则可以使用无模型方法,例如:

蒙特卡洛方法:直接通过实验或模拟生成样本,计算样本的平均值。

强化学习中的离策略方法:在强化学习中,即使目标策略未知,也可以通过行为策略采样并使用重要性采样来估计目标策略的价值函数。

3. 使用自适应重要性采样(Adaptive Importance Sampling)

自适应重要性采样是一种迭代方法,通过逐步改进提议分布来逼近目标分布。即使目标分布未知,也可以通过以下步骤实现:

步骤 1:初始化一个提议分布 q(x)。

步骤 2:从提议分布中采样,并根据样本调整提议分布(例如通过最大化似然或最小化方差)。

步骤 3:重复步骤 2,直到提议分布足够接近目标分布。

代码示例:自适应重要性采样

import torch
import numpy as np

# 假设目标分布是某种复杂分布,我们无法直接知道它的形式
# 但我们有一个黑箱函数可以计算目标分布的概率密度
def target_distribution(x):
    return torch.exp(-x**2 / 2) * (1 + torch.sin(x * 2))  # 示例目标分布

# 初始提议分布(例如高斯分布)
def proposal_distribution(x, mu, sigma):
    return torch.exp(-0.5 * ((x - mu) / sigma)**2) / (sigma * torch.sqrt(2 * torch.tensor(torch.pi)))

# 从提议分布中采样
def sample_from_proposal(n_samples, mu, sigma):
    return torch.normal(mu, sigma, size=(n_samples,))

# 自适应重要性采样
def adaptive_importance_sampling(n_samples, n_iterations):
    mu = 0.0  # 初始均值
    sigma = 1.0  # 初始标准差

    for _ in range(n_iterations):
        samples = sample_from_proposal(n_samples, mu, sigma)
        weights = target_distribution(samples) / proposal_distribution(samples, mu, sigma)

        # 更新提议分布的参数
        mu = torch.sum(samples * weights) / torch.sum(weights)
        sigma = torch.sqrt(torch.sum((samples - mu)**2 * weights) / torch.sum(weights))

    return samples, weights

# 估计期望值
def estimate_expectation(n_samples, n_iterations):
    samples, weights = adaptive_importance_sampling(n_samples, n_iterations)
    expectation = torch.mean(samples * weights)
    return expectation

# 参数设置
n_samples = 10000
n_iterations = 10

# 估计期望值
estimated_expectation = estimate_expectation(n_samples, n_iterations)
print(f"Estimated Expectation: {estimated_expectation.item()}")

4. 使用黑箱优化方法

如果目标分布完全未知,但可以评估某个函数在目标分布下的期望值(例如通过实验或模拟),则可以使用黑箱优化方法(如贝叶斯优化)来直接优化目标函数。

总结

当目标分布完全未知时,可以通过以下方法解决重要性采样问题:

使用样本数据拟合目标分布的近似分布。

使用无模型方法直接估计期望值。

使用自适应重要性采样逐步逼近目标分布。

使用黑箱优化方法直接优化目标函数。

选择哪种方法取决于具体问题的性质以及可用的信息和资源。

本教程共117节,当前为第18节!
本教程最新修订时间为:2026-08-07 09:17:18

📌 面试天下网:一款服务于上班族的口袋书,让大家在地铁里/公交上可以学习大模型技术!
📌 网站公告:程序出海:中国程序员当下最大的机遇>>>>>>