Skip to content

伴随灵敏度分析

伴随灵敏度分析(Adjoint Sensitivity Analysis),也称为反向灵敏度分析(Reverse Sensitivity Analysis),是一种高效计算标量目标函数关于大量参数梯度的方法。

理论基础

考虑一个离散动力学系统: $ x_{k+1} = f(x_k, u_k, \theta), \quad k=0, \dots, N-1 $ 以及一个定义在轨迹上的目标函数: $ J = \sum_{k=0}^{N-1} L_k(x_k, u_k) + \Phi(x_N) $ 其中 x 是状态,u 是控制,θ 是参数。

为了计算梯度 dJdθ,伴随方法引入了一组拉格朗日乘子(伴随状态)λk。伴随方程通常由终态向初态反向递归求解: $ \lambda_k = \frac{\partial L_k}{\partial x_k} + \left(\frac{\partial f}{\partial x_k}\right)^T \lambda_{k+1} $ 一旦求得伴随状态,参数梯度可以通过下式一次性计算得出,而无需对每个参数分别进行扰动: $ \frac{dJ}{d\theta} = \sum_{k=0}^{N-1} \left( \frac{\partial L_k}{\partial \theta} + \lambda_{k+1}^T \frac{\partial f}{\partial \theta} \right) $

Rible.jl 实现

Rible.jl 实现了基于 Zhong06 变分积分子(Variational Integrator)的离散伴随方法。这种方法直接在离散层面上构建伴随方程,保证了梯度的精确性和数值稳定性,特别适合处理包含接触和碰撞的非光滑系统。

核心组件

  • Adjoint_Zhong06_Constant_Mass_Cache: 存储伴随求解所需的中间变量。

  • generate_cache: 初始化伴随求解器缓存。

  • solve!: 执行反向伴随求解。

使用示例

julia
using Rible

# 1. 定义问题 (prob) 和前向仿真结果 (sim)
# 假设 prob 是 DynamicsProblem,sim 是 Simulator

# 2. 配置伴随求解器
adjoint_solver = Rible.AdjointDynamicsSensitivitySolver(
    Rible.DynamicsSolver(Rible.Zhong06()),
    objective_function # 用户定义的目标函数
)

# 3. 生成缓存
# 注意:伴随求解通常需要前向仿真的完整轨迹
adjoint_cache = Rible.generate_cache(
    prob, 
    adjoint_solver, 
    Val(true); 
    dt = 1e-3, 
    totalstep = 1000
)

# 4. 求解伴随状态
# 这将反向遍历时间步,计算伴随变量
Rible.solve!(
    sim, 
    forward_cache, 
    adjoint_cache; 
    dt = 1e-3
)

# 5. 获取梯度
# 梯度信息存储在 adjoint_cache 中
# 例如,获取关于初始状态的梯度
grad_x0 = adjoint_cache.solver_cache.adjoint_cache.∂J∂x₀ᵀ

注意事项

  • 内存消耗:伴随方法需要存储整个前向仿真过程的状态轨迹,对于长时间仿真,内存消耗可能较大。

  • 接触处理:Rible.jl 的伴随求解器能够处理接触约束,但需要确保前向仿真中正确记录了接触事件。

  • 常质量假设:目前的实现主要针对常质量矩阵系统进行了优化。