持久图与强化学习:拓扑结构演化中的策略学习实践

发布时间:2026/8/28 13:37:43
持久图与强化学习:拓扑结构演化中的策略学习实践 持久图Persistence Diagram和强化学习Reinforcement Learning放在一起最容易被误解成两套工具硬凑。实际上这类工作解决的是一个非常具体的问题当系统需要从初始拓扑状态演化到目标拓扑状态或者生成一段带拓扑约束的轨迹时持久图空间承担着状态描述强化学习负责在这个非欧空间里学习随机动力学。简单说不是用 RL 去替代拓扑数据分析而是用 RL 去学习“拓扑结构如何随时间变化”的策略。这个方向适合三类人看一是已经在用持久图做特征提取但不知道下一步怎么生成或控制拓扑演化的研究者二是熟悉强化学习想找一个有挑战的非欧状态空间应用的工程师三是做图形生成、材料结构演化、异常轨迹检测的从业者想评估拓扑约束能不能提升自己的流程。最值得关注的点不是模型多复杂而是怎么把持久图这种“点集”结构塞进 RL 的状态、动作和奖励里并且不要在一开始就被 Wasserstein 距离的代价算到崩溃。下面按实际落地顺序拆开讲。1. 先想清楚这个方向到底解决什么问题1.1 持久图不是普通向量不能直接套生成模型持久图是持续同调Persistent Homology的输出它把数据在不同尺度下的拓扑特征表示成平面上的点集。每个点有两个坐标出生尺度Birth和死亡尺度Death。点的横纵距离越远通常意味着这个拓扑特征越显著。这个表示有两个麻烦图的语义在点的集合上而不在某个固定维度的向量上。点的数量是动态的同一个数据集的两次采样持久图可能分别有 30 个点和 45 个点。如果你直接拉平成一个固定维度的向量比如把 (birth, death) 点排序后补零那么这个向量会在很多维度上没有稳定语义神经网络很难学到良好规律。更麻烦的是Wasserstein 距离和 Bottleneck 距离都不是简单的逐点欧氏距离。你让点集整体移动一格和移动其中一个点对拓扑语义的影响完全不同。所以在这个方向里持久图空间既是状态空间也是度量最棘手的地方。传统生成模型假设数据位于欧氏空间的低维流形上这篇文章要讨论的方法则更接近“在点集度量空间里做控制”的思路。1.2 随机动力学要做什么拓扑特征的演化轨迹如果目标只是计算一个数据集的持久图那根本不需要强化学习。真正有价值的问题是从一个初始点云开始希望它经过若干步变换后拓扑特征变成目标持久图的样子。给定一段时序数据希望预测下一时刻的新生拓扑结构。在材料结构演化中希望生成一条从“无环”到“有环”的合理轨迹。这类问题都要求模型在持久图空间里输出一个“下一步动作”。但因为动作施加在原始数据或者持久图点上结果会受噪声、采样密度、距离度量影响所以确定性策略往往不稳。随机动力学在这里的意思是策略输出的是动作分布每次采样得到的轨迹会略有不同训练过程中通过强化学习来调整这个动作分布使轨迹满足拓扑约束。1.3 为什么选择强化学习而不是监督学习最直接的对比思路是如果已经有一批“初始持久图-目标持久图”样本是不是训练一个监督网络直接回归目标就行理论上可以但实际很难。持久图点集数量不固定目标匹配关系不唯一。给定一个初始持久图可能有多个等价的目标匹配方式监督学习会强迫模型在多个合理答案之间取平均结果往往得到模糊甚至错误的中间态。另外很多情况下我们并没有完整的高质量轨迹标注只有最终目标或奖励函数比如“最终持久图与目标差距不能太大”“中间过程的拓扑特征不能消失”。强化学习的优势就是不需要为每一步提供标签只需要一个能计算奖励的环境。策略自己探索如何从初始状态一步步到达目标区域。这正好匹配持久图空间里“目标明确但路径不唯一”的特点。2. 把问题拆成状态、动作、奖励和策略2.1 状态设计持久图怎么编码进神经网络状态是整个流程的起点。你要让策略网络知道“当前拓扑长什么样”。一般有两种做法。第一种是直接对持久图点集编码。先对每个点做归一化把坐标系压到一个固定范围然后用 DeepSet 结构编码点集。DeepSet 的好处是对点的排列不敏感适合处理数量可变的点集。核心公式类似state_embedding pooling(MLP(point_i))其中 pooling 可以是 mean、max 或注意力加权。注意mean pooling 会把大量噪声点也平均进去如果噪声点很多拓扑特征会被稀释。我建议一开始用 max pooling或者先做显著性过滤只保留 life time 足够长的点。第二种是把持久图转成持久影像Persistence Image或持久曲面然后再用卷积网络。这样做的好处是方便复用现成视觉网络坏处是引入了额外分辨率参数。如果分辨率设置不好会丢失小特征的差异也会增大计算量。我个人的经验是对强化学习来说DeepSet 编码通常更稳。因为状态变化需要连续可导而持久图点的数量本身稳定时可导但如果你的环境里点集数量经常剧烈变化就需要加一个固定数量的 padding 掩码并保证网络对 padding 不敏感。2.2 动作设计每一步移动持久图点还是移动原始数据这是很多实现卡住的地方。动作空间到底作用在持久图上还是作用在生成持久图的原始数据上两种思路各有侧重。直接作用于持久图点动作给每个点一个二维位移比如移动(delta_birth, delta_death)。这种设计简单、训练快但生成的持久图可能不满足实际数据的可实现性。也就是说可能存在一个持久图但没有任何真实点云或函数能够精确映射到它。作用于原始数据或描述参数如果原始数据是点云动作可以是每个点的坐标位移如果原始数据是函数采样动作可以是函数值的变化。这样每一步生成的持久图都是合法的但计算持久图本身有额外开销而且梯度不能直接穿透持续同调计算只能用无梯度强化学习优化。我建议先从小规模、动作空间简单的情况入手。比如固定原始数据点数让动作直接控制点云位移然后每步用 ripser 重新计算持久图作为观测。这样动作空间物理意义明确奖励也容易算。如果算力有限可以先在持久图点集上做实验验证策略是不是能学会拓扑特征移动再决定要不要接入原始数据生成。2.3 奖励设计距离度量、拓扑约束和正则项一起加奖励设计是这个方向最敏感的部分。首先要有一个基础距离项衡量当前持久图和目标持久图之间的差距。常用的是 2-Wasserstein 距离因为它在点匹配上有较好性质也比 Bottleneck 距离对位置变化更敏感。但只给 Wasserstein 距离会遇到一个典型问题策略很容易找到一个中间持久图把所有点都移动到极远或极近的位置让距离变小但拓扑结构已经退化。所以奖励里要加约束reward - distance(current, target) - alpha * topology_loss - beta * action_regularizationtopology_loss 可以包括点的数量是否合理显著特征的持久比例是否保持是否存在大量短寿命噪声点。action_regularization 则限制每一步动作的幅度避免策略用极大位移来刷奖励。注意奖励 scale 很关键。我一般会把 Wasserstein 距离除一个典型尺度使单步奖励大致在[-0.1, 0]范围内。如果奖励绝对值太大策略会非常激进如果太小探索效率又低。2.4 策略模型从持久图到动作分布的条件概率策略网络把状态编码映射到动作分布。使用随机策略时一般假设动作服从高斯分布网络输出均值和方差。对持久图点集动作来说既要能输出连续位移也要让不同点之间的动作不冲突所以可以直接让每个点共享一个 MLP再对点数维度做循环或并行计算。代码结构大致如下class StochasticPolicy(nn.Module): def __init__(self): super().__init__() self.encoder DeepSetEncoder() self.mean_head nn.Linear(64, 2) self.log_std nn.Parameter(torch.tensor(-1.0)) def forward(self, diagrams): # diagrams: [batch, num_points, 2] embedding self.encoder(diagrams) mean self.mean_head(embedding) std torch.exp(self.log_std) return mean, std这里 log_std 一开始不要设成特别小否则策略过早趋向于确定性探索不足。后面训练稳定了再让熵系数自动下降。3. 环境、依赖与最小数据准备3.1 常见库与运行环境实现这个方向不需要太重的基础设施。我个人常用的组合是模块用途推荐库持续同调计算从点云/图/函数算出持久图GUDHI、ripser持久图距离计算Wasserstein / Bottleneckpersim、gudhi.wasserstein强化学习框架策略优化和训练循环Stable-Baselines3、自定义 PyTorch数据生成点云、随机图、带噪函数numpy、scipy如果只用小规模验证CPU 就够。比如几十个点的点云计算一次 Rips 持久图很快。但是如果你想在 RL rollout 里每步都重新算持久图而且点云规模达到几百个点建议先用 GPU 跑神经网络但持续同调计算本身仍以 CPU 为主。依赖版本不要盲目追新。比如 GUDHI 的 Python 接口在不同版本之间 API 有过调整尤其是plot_persistence_diagram和wasserstein_distance。落地前先确认依赖能否在你当前环境正常安装。3.2 用二维点云构造第一组测试数据第一次实验不要直接上高维点云也不要用特别复杂的图数据。我建议用二维点云作为出发点。具体步骤如下随机生成一个点云比如两个圆环叠加每个圆环 40 个点。给点坐标加一点高斯噪声制造 H1 维的环特征。用 ripser 计算持久图。只保留 life time 大于阈值的点作为显著拓扑特征。目标状态可以这样构造把其中一个圆环的半径扩大或者把两个环相对移动一段距离。这样就有一个“目标持久图”可供训练。这里有一个很关键的细节初始点云和目标点云的点数必须一致。如果动作直接作用在点云坐标上点数不一致会引入多余的匹配复杂度。真实场景里可以允许点数变化但最小验证阶段固定住点数能减少很多调试困难。3.3 持久图的批量计算和缓存强化学习训练会产生大量 rollout 数据。如果每一步都重新算持久图开销会迅速变大。有一个比较实用的做法是在环境步进时只对变化的那部分点云重新计算持久图或者先离线生成一批原始数据变化轨迹把每一步的持久图都预计算好训练时直接读取。在实验中我倾向于先做离线缓存。虽然这样会减少 RL 探索的自由度但用来验证策略网络和奖励设计是否合理足够了。等确认核心模块没问题再改成在线计算。4. 一个最小可跑的 RL 训练流程4.1 先做单步决策不要直接做多步很多人一上来就训练一个完整的多步 MDP结果训练半天发现奖励不稳定根本分不清是状态编码问题还是动作空间问题。更稳妥的路径是训练一个单步策略给定一个初始持久图输出一次动作然后计算奖励。验证单步动作能否降低 Wasserstein 距离。确认单步可行后再扩展到多步轨迹。单步任务可以看成一个上下文 bandit训练起来更快也更容易定位问题。如果单步都学不到有效动作多步一定更差。4.2 一个参考训练配置下面是我在类似问题中会用到的初始参数具体数值要按你的环境调整参数初始值说明点云点数40 到 60越小训练越快每个 episode 步数10 到 20先短后长学习率3e-4默认即可批量大小256小规模可以先 128动作标准差初值0.5 到 1.0不能太小奖励系数 alpha1.0 到 5.0拓扑约束权重奖励系数 beta0.01 到 0.1动作惩罚权重环境并行数4 到 8看 CPU 核心数不要一上来就把 episode 步数设成 100。拓扑结构在初始几步可能改变最大。步数越多credit assignment 越难策略越容易陷入局部最优。4.3 第一个正确信号奖励曲线下降但不过度震荡判断模型是否开始学不应该只看最终目标距离。我一般会看三个信号单步动作后当前持久图与目标持久图的 Wasserstein 距离是否稳定下降每个 episode 结束后显著特征点数是否保持在合理范围内动作幅度是否会因为奖励过大而出现“一步到位再震荡”的现象。如果奖励曲线下降但持久图点集体积迅速收缩说明策略找到 了某种“奖励黑客”方式。比如把所有点都移动到出生坐标和死亡坐标相近的位置虽然距离可能下降但拓扑特征已经消失。这时候需要提高拓扑约束权重的优先级而不是继续调学习率。4.4 可视化和定量验证可视化是这个方向最重要的验证工具。持久图本身是二维点图很好画。每个 episode 结束后把当前持久图用红色点画出来目标持久图用蓝色点画出来再叠加一条点对点的匹配线。如果匹配线基本是横向或纵向的说明策略在做合理的移动如果匹配线乱成一团多半是距离度量或者状态编码有问题。除了持久图还可以把原始点云的变化过程保存成 gif 或者多帧图片。这一步能看到更直观的拓扑演化。不要只看 lossloss 下降了不代表拓扑轨迹合理。# 伪代码训练主循环 for iteration in range(max_iterations): obs env.reset() actions, log_probs policy.sample(obs) next_obs, rewards env.step(actions) # 按 RL 算法更新策略 update(policy, obs, actions, rewards, log_probs)这个伪代码只用来表达流程实际落地要按 PPO 或 SAC 的实现来写。5. 参数边界、评测指标和常见失败模式5.1 哪些参数最影响稳定性在这个方向里参数对结果的影响是按优先级排序的。我体验下来从高到低依次是持久图距离的计算方式用 2-Wasserstein 还是 Bottleneck会对梯度信号非常敏感。Wasserstein 更平滑适合 RL。奖励 scale如果距离数值太大策略会对微小变化不敏感如果太小很容易被动作惩罚淹没。动作空间范围动作范围限制在多少直接决定策略能不能一次性跨过拓扑分岔点。状态编码器的 pooling 方式mean 和 max 差异明显尤其在噪声点较多时。拓扑阈值保留哪些点、过滤哪些点会影响整个状态空间的语义稳定性。我发现很多人会花大量时间调学习率和网络层数但忽略了奖励 scale。实际上在持久图空间里Wasserstein 距离可能从几十到几百不等如果不先做归一化后面所有超参数都会被带偏。5.2 评测指标不能只看平均距离建议记录以下几类指标指标看什么平均 Wasserstein 距离离目标有多近显著特征点数量拓扑结构是否退化动作位移均值策略是否激进成功 episode 比例是否在限制步数内达到目标轨迹多样性多次采样是否产生相似轨迹如果轨迹多样性很低即使平均距离下降也说明随机动力学退化成近确定性策略了这在需要生成多条候选轨迹的场景里不是好事。5.3 常见失败模式模式一奖励训练上去了但拓扑特征丢失。原因通常是拓扑约束权重不够。持久图点可以通过不断合并到对角线附近来减少与目标匹配的代价因为对角线附近的点通常会被距离匹配忽略。要避免这个可以在奖励里显式惩罚靠近对角线的点或者直接过滤掉 life time 过短的点。模式二训练时 Wasserstein 距离计算太慢rollout 效率极低。如果每个 step 都调用完整的最优匹配算法在点集数量大时计算量会爆炸。先用小点集或者离线缓存持久图都是有效的缓解办法。不要一开始就追求大规模真实数据。模式三策略输出的动作导致持久图点数量突变。当动作作用于原始点云时点云点之间的碰撞、重叠可能导致某些环结构消失。这不一定是 bug但会让训练不稳定。建议 on-policy 算法里限制动作最大范数让每一步变化尽量小。模式四无论如何训练距离曲线都在固定值附近震荡。这种情况先看输入点云是否已经退化成没有显著拓扑特征的形态。如果初始状态本身和目标差距过大策略可能无法一次性学到有效动作。解决办法是调整初始状态与目标状态的差距让轨迹可以由小步完成。6. 从单智能体到多智能体和贝叶斯动作解码的延伸6.1 批量生成与序列控制当单条轨迹跑稳后很容易想到批量生成。比如需要生成 100 条从初始拓扑到目标拓扑的轨迹。这时除了 RL 策略还需要考虑输出命名、采样种子、失败重试和轨迹长度控制。不要直接并行上千个 episode。持久图距离计算和原始数据持久度计算都是 CPU 密集任务并行数量过高会导致调度器大量切换。先用 4 到 8 个进程观察 CPU 占用和每个 episode 的平均耗时再逐步增加。批量任务中失败重试尤其重要。一条轨迹可能因为显式步数耗尽而失败不应该直接丢弃而应该记录失败原因并对初始状态做随机扰动后重试。这种重试策略比单纯增加 episode 步数更有效。6.2 多智能体场景中的拓扑特征调度这个方向也可以和多智能体强化学习结合。比如多个智能体共同改变一个点云的不同区域每个智能体只负责局部拓扑特征。此时持久图不再是全局单点集而需要按区域划分成多个子图。全局奖励可以是整体 Wasserstein 距离局部奖励可以是各自区域的持久图变化。这种设计类似于分层控制上层决定哪个拓扑特征先改变下层决定具体怎么移动点。多智能体环境里最需要注意的是动作冲突。如果一个智能体在生成环结构另一个智能体在破坏同一条边全局奖励会剧烈波动。可以先固定其他智能体只训练其中一个逐个验证。6.3 Bayesian action decoder 能带来什么最近看到的 bayesian action decoder for deep multi-agent reinforcement learning 这个方向和持久图上的随机动力学放在一起是有价值的它强调动作解码时的不确定性估计而不是只输出一个点估计动作。对持久图点集来说不确定性非常重要因为拓扑特征本身存在歧义同一个持久图可以有多种合理演化方式。如果采用类似贝叶斯动作解码的思路策略网络不再只输出高斯均值而是输出一个动作分布的后验估计。这样在生成多条候选轨迹时可以自然得到轨迹的置信区间。应用到持久图空间时你可以回答“在保留环特征的前提下哪些演化路径更可能成功”。这对材料制备、分子构象生成等需要可控随机性的场景很实用。当然原始材料里没有给出具体的贝叶斯解码器实现细节落地时还是要先确认你的 RL 框架是否支持自定义动作分布以及推断时是否需要对隐变量做重参数化采样。这类改动会让训练变慢但换来的是生成轨迹的可解释多样性。7. 我调试时优先看的几个位置如果哪天你的持久图 RL 训练完全失控或者结果总是不稳定我会按下面的顺序排查。第一先确认输入持久图是否干净。很多问题不是策略不行而是持久图里有大量短寿命噪声点。可以先做一次显著性过滤把 life time 小于阈值的点移除再看状态编码是否更稳定。第二把奖励里的各个分项单独打印出来。不要只打印总奖励。看 Wasserstein 项、拓扑约束项、动作正则项分别是什么量级。如果某项比其他项大 100 倍策略基本只会优化那一项。第三检查动作是否真的在改变状态。在 episode 中单独记录初始持久图、中间持久图和最终持久图。如果中间输出和初始几乎一样说明动作没有被环境正确应用或者动作太接近 0。第四检查距离计算的输入输出方向是否一致。Wasserstein 距离虽然是对称的但持久图点集的匹配函数在实现里可能因为转置、排序等原因产生不稳定。先用两个人工构造的持久图验证距离是否符合直觉。第五把训练步数降低到一个非常小的规模比如 1000 步。如果这么小的步数里都没有任何下降趋势说明问题大概率在奖励设计或状态编码而不是训练不稳定。我最常踩的坑是策略发现把点云所有点聚集在一起会让持久图点数量减少从而缩短距离计算匹配时间并且在某些距离度量下看起来“更接近目标”。这种 reward hacking 很难通过调学习率解决。正确做法是给每个持久图点数量一个稳定惩罚并且强制保留至少一定数量的显著特征。这个方向最终能不能落地不取决于你是不是能把 PPO 跑通而取决于你有没有把持久图的“点集语义”和 RL 的状态、动作、奖励对应清楚。先在小规模点云上验证整条链路再慢慢扩展到更复杂的数据类型每一步都用可视化和指标双重核对会比直接追求复杂算法稳定得多。