概述

概率电路的应用涵盖从传统概率建模到现代深度学习的多个领域。本章介绍概率电路在图生成知识图谱神经概率电路等方面的前沿应用,并分析其与主流深度生成模型的关系。1


图生成应用

图的概率表示

图数据结构可以用概率电路自然地表示:

  • 节点特征:作为电路的输入变量
  • 边结构:通过电路的乘积操作编码条件独立性
  • 图分布:整个电路表示图的概率分布

卷积概率电路

卷积概率电路(Convolutional Probabilistic Circuits, ConvPC)将卷积思想引入概率电路:

class ConvPC(nn.Module):
    def __init__(self, input_shape, num_filters):
        super().__init__()
        # 卷积核作为电路参数
        self.filters = nn.Parameter(torch.randn(num_filters, *kernel_size))
        # 求和节点
        self.sum_weights = nn.Parameter(torch.ones(num_filters))
    
    def forward(self, x):
        # 卷积操作
        conv_out = F.conv2d(x, self.filters, padding=1)
        
        # 概率求和
        B, C, H, W = conv_out.shape
        conv_flat = conv_out.view(B, C, -1)
        
        # 池化
        log_probs = torch.logsumexp(
            conv_flat + torch.log_softmax(self.sum_weights, dim=0).view(1, -1, 1),
            dim=1
        )
        return log_probs.view(B, H, W)

核心思想

  • 将局部区域的特征建模为条件分布
  • 通过求和节点混合不同滤波器
  • 保持概率电路的可追踪推断性质

图神经概率电路

图神经概率电路(Graph Neural Probabilistic Circuits)结合GNN与概率电路:

class GraphNeuralPC(nn.Module):
    def __init__(self, node_dim, edge_dim, num_messages):
        super().__init__()
        # 消息函数
        self.message_net = nn.Sequential(
            nn.Linear(2 * node_dim + edge_dim, node_dim),
            nn.ReLU(),
            nn.Linear(node_dim, node_dim)
        )
        
        # 概率电路的聚合
        self.aggregate_circuit = ProbabilisticCircuitAggregator(
            input_dim=node_dim,
            num_sums=num_messages
        )
    
    def forward(self, graph, node_features):
        # 消息传递
        messages = self.compute_messages(graph, node_features)
        
        # 概率电路聚合
        aggregated = self.aggregate_circuit(messages)
        
        return aggregated

应用场景

场景方法可追踪查询
分子生成ConvPC + 片段库有效性检查、属性预测
网络建模GraphPC + 时序扩展链接概率、影响力分析
图分类PC + 图核边缘概率、解释生成

知识图谱应用

知识图谱的概率表示

知识图谱 可以表示为概率电路:

  • 实体 :电路的叶子节点
  • 关系 :电路的操作类型
  • 三元组 :电路的求和/乘积结构

链接预测的概率电路方法

基于因式分解的方法

知识图谱的联合分布因式分解:

用概率电路实现:

class KGProbabilisticCircuit(nn.Module):
    def __init__(self, num_entities, num_relations, embedding_dim):
        super().__init__()
        # 实体嵌入
        self.entity_embeddings = nn.Embedding(num_entities, embedding_dim)
        
        # 关系嵌入
        self.relation_embeddings = nn.Embedding(num_relations, embedding_dim)
        
        # 电路结构
        self.head_circuit = nn.Sequential(
            nn.Linear(embedding_dim, 64),
            nn.ReLU(),
            nn.Linear(64, num_entities)
        )
        
        self.tail_circuit = nn.Sequential(
            nn.Linear(2 * embedding_dim, 64),
            nn.ReLU(),
            nn.Linear(64, num_entities)
        )
    
    def score_triplet(self, h, r, t):
        h_emb = self.entity_embeddings(h)
        r_emb = self.relation_embeddings(r)
        t_emb = self.entity_embeddings(t)
        
        # 计算三元组分数
        h_score = self.head_circuit(h_emb)
        ht_score = self.tail_circuit(torch.cat([h_emb, r_emb], dim=-1))
        
        # 概率归一化
        p_t = F.softmax(ht_score, dim=-1)
        
        return (p_t[:, t] * F.softmax(h_score, dim=-1)[:, t]).sum()

可追踪的多跳推理

概率电路支持精确的多跳推理

这与传统的链式规则不同,不需要多次近似或采样。

应用实例:查询嵌入

询问(Query Embedding)的概率电路

将逻辑询问映射到概率电路:

询问: ∃x : Person(x) ∧ WorksAt(x, Google) ∧ LivesIn(x, NYC)

电路结构:
    [Sum] (存在量词)
      |
   [Prod] (合取)
   /    \    \
[Person] [WorksAt] [LivesIn]

答案检索

给定询问,检索答案:

def query_answering(circuit, query, entities):
    # 编码询问
    query_encoding = circuit.encode_query(query)
    
    # 计算每个实体的概率
    scores = []
    for entity in entities:
        score = circuit.evaluate(query_encoding, entity)
        scores.append(score)
    
    # 返回概率最高的答案
    answer_probs = torch.softmax(torch.tensor(scores), dim=0)
    return answer_probs

神经概率电路

从变分推断到概率电路

神经概率电路(Neural Probabilistic Circuits, NPC)结合了变分推断的灵活性和概率电路的可追踪性。

核心思想

class NeuralProbabilisticCircuit(nn.Module):
    """
    神经概率电路:可微分的概率电路
    """
    def __init__(self, latent_dim, num_components):
        super().__init__()
        # 神经网络的编码器
        self.encoder = nn.Sequential(
            nn.Linear(input_dim, 128),
            nn.ReLU(),
            nn.Linear(128, latent_dim)
        )
        
        # 概率电路参数生成器
        self.circuit_generator = nn.ModuleDict({
            'weights': nn.Linear(latent_dim, num_components),
            'means': nn.Linear(latent_dim, latent_dim * num_components),
            'scales': nn.Linear(latent_dim, latent_dim * num_components)
        })
        
        # 固定结构的概率电路
        self.circuit = TractableProbabilisticCircuit(
            latent_dim=latent_dim,
            num_components=num_components
        )
    
    def forward(self, x):
        # 1. 编码
        z = self.encoder(x)
        
        # 2. 生成电路参数
        weights = F.softmax(self.circuit_generator['weights'](z), dim=-1)
        means = self.circuit_generator['means'](z).view(-1, num_components, latent_dim)
        scales = F.softplus(self.circuit_generator['scales'](z)).view(-1, num_components, latent_dim)
        
        # 3. 在概率电路上评估
        log_prob = self.circuit.evaluate(x, weights, means, scales)
        
        return log_prob

自编码概率电路

自编码概率电路(Autoencoding Probabilistic Circuits, APC)实现端到端的概率建模:

class AutoencodingPC(nn.Module):
    def __init__(self, input_dim, latent_dim, num_components):
        super().__init__()
        
        # 编码器:输入 → 潜在变量分布参数
        self.encoder = nn.Sequential(
            nn.Linear(input_dim, 256),
            nn.ReLU(),
            nn.Linear(256, latent_dim),
            nn.ReLU(),
            nn.Linear(latent_dim, 2 * num_components)  # 均值 + 对数方差
        )
        
        # 概率电路解码器
        self.decoder = TractableDecoder(
            latent_dim=latent_dim,
            output_dim=input_dim,
            num_components=num_components
        )
    
    def forward(self, x):
        # 编码
        z_params = self.encoder(x)
        z_mean, z_logvar = z_params.chunk(2, dim=-1)
        
        # 重参化采样
        z = z_mean + torch.randn_like(z_mean) * torch.exp(0.5 * z_logvar)
        
        # 解码(概率电路)
        log_prob = self.decoder(z)
        
        return log_prob, z_mean, z_logvar
    
    def loss(self, x):
        log_prob, z_mean, z_logvar = self.forward(x)
        
        # 重建损失
        recon_loss = -log_prob.mean()
        
        # KL散度
        kl_loss = -0.5 * (1 + z_logvar - z_mean ** 2 - z_logvar.exp()).mean()
        
        return recon_loss + 0.1 * kl_loss

与变分自编码器的比较

特性VAE神经概率电路
推断方式变分近似精确推断
ELBO优化需要下界直接优化
潜在变量连续连续/离散
推断查询仅后验多项式时间任意查询
表达能力受近似限制受电路结构限制

与深度生成模型的比较

生成模型谱系

概率电路位于精确推断的端点,与其他生成模型形成对比:

精确推断 ←————————————————————————————→ 近似推断
   ↓                                              ↓
概率电路                                      VAE, Diffusion, GAN
   ↓                                              ↓
可追踪推断                                   可扩展但近似

各模型的优势与局限

概率电路

优势

  • 精确的边缘概率和条件概率
  • 多种查询的追踪计算
  • 可解释的推断过程

局限

  • 结构学习困难
  • 对高维复杂数据表达能力有限
  • 计算复杂度与电路规模相关

扩散模型

优势

  • 强大的生成质量
  • 稳定的训练目标
  • 规模化能力强

局限

  • 推断成本高
  • 无法直接计算概率
  • 查询灵活性差

VAE

优势

  • 训练稳定
  • 潜在空间可用
  • 规模化能力中上

局限

  • ELBO与真实似然有差距
  • 后验坍塌问题
  • 推断近似

混合方法

PC + Diffusion

在扩散模型中使用概率电路:

class PCGuidedDiffusion(nn.Module):
    def __init__(self, diffusion_model, pc_circuit):
        super().__init__()
        self.diffusion = diffusion_model
        self.circuit = pc_circuit
        
        # PC指导强度
        self.guidance_scale = 1.0
    
    def sample(self, condition, num_steps=100):
        # PC先验
        log_prob_fn = lambda x: self.circuit.log_prob(x)
        
        # 扩散采样 + PC引导
        samples = self.diffusion.sample(
            condition,
            guide_fn=log_prob_fn,
            guidance_scale=self.guidance_scale,
            num_steps=num_steps
        )
        
        return samples

高效潜在变量模型

概率电路可以实现高效但可追踪的潜在变量模型。

连续潜在变量

概率积分电路(PIC)

将连续积分转化为离散求和:

class ProbabilisticIntegralCircuit(nn.Module):
    def __init__(self, num_quadrature_points):
        super().__init__()
        # 数值积分节点和权重
        self.quadrature_nodes = nn.Parameter(torch.randn(num_quadrature_points, latent_dim))
        self.quadrature_weights = nn.Parameter(torch.ones(num_quadrature_points))
        
        # 归一化权重
        self.quadrature_weights.data = F.softmax(self.quadrature_weights.data, dim=0)
    
    def forward(self, x):
        # 计算积分近似
        log_likelihoods = []
        for i in range(self.num_quadrature_points):
            z_i = self.quadrature_nodes[i]
            p_z = self.quadrature_weights[i]
            p_x_given_z = self.likelihood_net(x, z_i)
            log_likelihoods.append(p_x_given_z + torch.log(p_z))
        
        # 求和(积分近似)
        return torch.logsumexp(torch.stack(log_likelihoods, dim=0), dim=0)

离散潜在变量

离散潜在变量是概率电路的传统优势:

class DiscreteLatentPC(nn.Module):
    def __init__(self, num_latent_states):
        super().__init__()
        # 离散潜在变量的先验
        self.prior_weights = nn.Parameter(torch.ones(num_latent_states))
        
        # 每个潜在状态的似然网络
        self.likelihood_nets = nn.ModuleList([
            nn.Sequential(
                nn.Linear(latent_dim, 128),
                nn.ReLU(),
                nn.Linear(128, output_dim)
            )
            for _ in range(num_latent_states)
        ])
    
    def forward(self, x):
        # 精确的边缘化:求和掉离散潜在变量
        log_probs = []
        for i, net in enumerate(self.likelihood_nets):
            z_i = self.discrete_to_continuous(i)  # 潜在状态i的表示
            p_x_z = net(torch.cat([x, z_i], dim=-1))
            p_z = F.softmax(self.prior_weights, dim=0)[i]
            log_probs.append(p_x_z + torch.log(p_z))
        
        # 精确边缘化
        return torch.logsumexp(torch.stack(log_probs, dim=0), dim=0)

与标准化流的关系

标准化流(Normalizing Flow)可以通过概率电路实现:

class FlowCircuit(nn.Module):
    def __init__(self, base_circuit, flow_layers):
        super().__init__()
        self.base_circuit = base_circuit  # 基础分布
        self.flow_layers = flow_layers     # 可逆变换层
    
    def log_prob(self, x):
        # 前向变换 + 雅可比行列式
        z, log_det = self.flow_layers(x)
        
        # 基础分布概率
        log_prob_base = self.base_circuit.log_prob(z)
        
        # 变换后的概率
        return log_prob_base + log_det
    
    def sample(self, num_samples):
        # 从基础分布采样
        z = self.base_circuit.sample(num_samples)
        
        # 逆变换
        x = self.flow_layers.inverse(z)
        
        return x

科学计算应用

分子性质预测

概率电路可以精确计算分子性质的不确定性:

class MolecularPropertyPC(nn.Module):
    def __init__(self, atom_types, bond_types):
        super().__init__()
        # 分子图编码
        self.graph_encoder = MolecularGraphEncoder(atom_types, bond_types)
        
        # 概率电路:建模性质分布
        self.property_circuit = TractablePropertyPredictor(
            input_dim=graph_dim,
            num_components=16
        )
    
    def forward(self, mol_graph):
        # 编码分子
        h = self.graph_encoder(mol_graph)
        
        # 预测 + 不确定性量化
        log_prob = self.property_circuit(h)
        
        return log_prob
    
    def predict_with_uncertainty(self, mol_graph):
        # 返回预测均值和方差
        probs = torch.softmax(self.property_circuit.get_components(), dim=-1)
        means = self.property_circuit.get_means()
        
        pred_mean = (probs * means).sum(dim=-1)
        pred_var = (probs * (means - pred_mean.unsqueeze(-1))**2).sum(dim=-1)
        
        return pred_mean, pred_var

时间序列建模

class TimeSeriesPC(nn.Module):
    def __init__(self, time_steps, num_states):
        super().__init__()
        # 时序编码器
        self.temporal_encoder = nn.LSTM(
            input_size=feature_dim,
            hidden_size=hidden_dim,
            num_layers=2
        )
        
        # 概率电路:建模状态转换
        self.transition_circuit = TractableTransitionModel(
            hidden_dim=hidden_dim,
            num_states=num_states
        )
    
    def forward(self, x):
        # 时序编码
        h, _ = self.temporal_encoder(x)
        
        # 概率电路:计算转移概率
        log_prob = self.transition_circuit(h)
        
        return log_prob

实践建议

何时选择概率电路

适合场景

  • 需要精确概率而非近似
  • 需要多种可追踪查询(边缘、条件、MAP)
  • 数据结构适合电路表示(如树形、网格)
  • 需要可解释的推断过程

不适合场景

  • 超高维数据(>1000维)
  • 极复杂依赖关系
  • 只需单次生成任务
  • 部署资源极其有限

实现库推荐

特点适用场景
SPFlow全面、易用入门和原型
cirkit高效、研究级复杂电路、定制
EiNetGPU加速大规模数据
PyroPyTorch集成与深度学习结合

总结

概率电路的应用正在从传统概率建模向现代深度学习扩展:

应用领域核心价值关键技术
图生成精确可追踪ConvPC、GraphPC
知识图谱多跳精确推理查询嵌入、链接预测
神经概率电路可微分+可追踪NPC、APC
科学计算不确定性量化分子建模、时间序列

概率电路代表了精确概率推断深度学习融合的重要方向,在需要严格概率保证的应用场景中具有独特价值。


参考

Footnotes

  1. Neural Probabilistic Circuits: Towards Efficient and Tractable Deep Probabilistic Models (NeurIPS 2024)