1. 研究背景
1.1 因果发现的任务
因果发现旨在从观测数据中推断变量间的因果关系1:
# 从数据中发现因果结构
data = load_observational_data()
graph = causal_discovery(data) # 推断因果图1.2 现有方法的局限
| 方法 | 优势 | 局限 |
|---|---|---|
| PC算法 | 理论基础强 | 计算复杂度高 |
| NOTEARS | 可微分 | 需要领域知识 |
| DAG-GNN | 端到端 | 需要重训练 |
1.3 Arrow的愿景
构建一个零样本因果发现的基础模型,无需重训练即可应用于新数据集。
2. 技术框架
2.1 核心思想
Arrow基于以下洞察1:
- 因果结构的普遍性:高质量因果图共享通用模式
- 表示学习:学习跨领域的通用因果表示
- 适配器设计:少量参数即可适应新领域
2.2 架构设计
┌─────────────────────────────────────────────────────────────────────────┐
│ Arrow 架构 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ 预训练阶段: │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 多源因果数据集预训练 │ │
│ │ │ │
│ │ Dataset1: 生物数据 ──► 因果图 │ │
│ │ Dataset2: 经济数据 ──► 因果图 │ │
│ │ Dataset3: 医疗数据 ──► 因果图 │ │
│ │ │ │
│ │ ↓ 共享因果表示学习 │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ 推理阶段(零样本): │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 新数据集 → 因果发现 │ │
│ │ │ │
│ │ 新数据 ──► Arrow编码器 ──► 因果图 │ │
│ │ ↑ │ │
│ │ 无需参数更新! │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
3. 核心算法
3.1 因果图表示
class CausalGraphEncoder(nn.Module):
"""
因果图编码器
学习通用的因果结构表示
"""
def __init__(self, num_vars, hidden_dim):
super().__init__()
# 变量表示
self.var_embedding = nn.Embedding(num_vars, hidden_dim)
# 边表示(可学习的邻接矩阵)
self.adj_logits = nn.Parameter(torch.zeros(num_vars, num_vars))
# 因果强度编码
self.strength_encoder = nn.Sequential(
nn.Linear(hidden_dim * 2, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, 1)
)
def forward(self, var_indices):
"""
Args:
var_indices: 变量索引 [B, N]
Returns:
adj_matrix: 因果邻接矩阵 [B, N, N]
"""
# 变量嵌入
var_emb = self.var_embedding(var_indices) # [B, N, hidden]
# 计算边强度
adj_logits = self.adj_logits.unsqueeze(0) # [1, N, N]
# 注意力计算
src = var_emb.unsqueeze(2) # [B, N, 1, hidden]
dst = var_emb.unsqueeze(1) # [B, 1, N, hidden]
strength = self.strength_encoder(torch.cat([src, dst], dim=-1))
strength = strength.squeeze(-1) # [B, N, N]
# 融合
adj = torch.sigmoid(strength + adj_logits)
return adj3.2 零样本推理
class ArrowZeroShotCausalDiscovery:
"""
Arrow零样本因果发现
"""
def __init__(self, model, device='cuda'):
self.model = model
self.model.eval()
self.device = device
@torch.no_grad()
def discover(self, data, var_names=None):
"""
零样本因果发现
Args:
data: 观测数据 [N, D]
var_names: 变量名列表
Returns:
adj_matrix: 因果邻接矩阵
"""
# 标准化数据
data_norm = (data - data.mean(0)) / (data.std(0) + 1e-8)
# 构建变量索引
num_vars = data.shape[1]
var_indices = torch.arange(num_vars, device=self.device).unsqueeze(0)
# 编码
adj = self.model(var_indices) # [1, N, N]
adj = adj.squeeze(0).cpu().numpy()
# 移除自环
np.fill_diagonal(adj, 0)
# 阈值化
threshold = 0.3
adj_binary = (adj > threshold).astype(int)
return adj_binary, adj4. 理论分析
4.1 表示学习理论
假设(因果结构普遍性):高质量因果图在语义空间中形成低维流形。
定理(跨域泛化):设源域和目标域共享隐因果流形 ,则Arrow学到的表示 满足:
4.2 零样本保证
引理(分布无关性):Arrow的因果发现能力与具体数据集分布无关,仅依赖于因果结构的普遍模式。
5. 实验结果
5.1 标准基准
Sachs数据集:
| 方法 | SHD↓ | SID↓ | 运行时 |
|---|---|---|---|
| PC | 15 | 42 | 120s |
| GES | 12 | 38 | 45s |
| NOTEARS | 10 | 35 | 8s |
| Arrow | 8 | 28 | 0.5s |
5.2 零样本泛化
跨数据集评估:
| 源 → 目标 | 同分布 | Arrow零样本 | 微调后 |
|---|---|---|---|
| Bio → Econ | 0.85 | 0.72 | 0.83 |
| Med → Social | 0.88 | 0.68 | 0.81 |
| Tech → Finance | 0.82 | 0.65 | 0.78 |
5.3 计算效率
| 方法 | 时间 | 内存 |
|---|---|---|
| PC | O(n²) | 高 |
| GES | O(n³) | 中 |
| Arrow | O(1) | 低 |
6. 总结
6.1 主要贡献
- 零样本因果发现:无需重训练
- 跨域泛化:利用因果结构的普遍性
- 高效推理:预训练+推理模式
6.2 局限性
- 精度限制:复杂因果结构可能不准确
- 领域依赖:部分领域缺乏预训练数据
- 时序数据:主要针对表格数据