离线强化学习(Offline RL)系列3: (算法篇) Onestep 算法详解与实现

离线强化学习(Offline RL)系列3: (算法篇) Onestep 算法详解与实现_第1张图片

[更新记录]

论文信息: David Brandfonbrener, William F. Whitney, Rajesh Ranganath, Joan Bruna: “Offline RL Without Off-Policy Evaluation”, 2021; arXiv:2106.08909.

本论文由纽约大学(NYU)的David Brandfonbrener以第一作者提出,发表在NeurIPS 2021 顶会上【Accept (Spotlight)】,接收意见: While the method is very simple, the message is clear and the authors have done excellent job on concise and thorough writing and experimentation. As offline RL + D4RL benchmark are becoming mainstream, such work can likely guide the community to explore more impactful research *directions.

摘要:迭代方法(Iterative)相对较差主要是由于在执行off-policy评估时固有的高方差的结果,且因这些估计的重复优化策略而放大,本文提出的基于On-policy的Onestep方法通过一步约束/规则化的策略改进,解决了基于off-policy的multi-step/interative中遇到的iterative error exploitation等问题,在连续(continous)任务达到了SOTA的效果。

文章目录

  • 1. 问题 & Preliminaries
    • 1.1 Preliminaries
    • 1.2 迭代算法的问题
  • 2. 理论原理方法
    • 2.1 One-step和Multi-step区别
    • 2.2 原理 and 算法模板
      • 2.2.1 One-step
      • 2.2.2 Multi-step
      • 2.2.3 Iterative actor-critic
    • 2.3 策略优化操作符( Policy improvement Operators)
      • 2.3.1 Behavior clone
      • 2.3.2 Constraint policy updates
      • 2.3.3 Regularized policy update
      • 2.3.4 reverse KL
  • 3. 实验结果分析
    • 3.1 性能分析
    • 3.2 学习曲线分析
    • 3.3 Overestimate 分析
  • 4 非常重要的总结结论与讨论
    • 4.1 学习曲线和超参数灵敏性
    • 4.2 分布偏移(Distribution shift)
    • 4.3 迭代误差利用( Iterative error exploitation)
  • 5 什么时候用Multi-step
  • 6. OpenReview审稿意见
  • 7. 代码实现细节
  • 参考文献
  • OfflineRL推荐阅读

1. 问题 & Preliminaries

1.1 Preliminaries

经典的BCQ、CQL、BRAC、CRR、AWR等算法都依赖off-policy去评估学习Critic,通过对这些算法进行分析,发现效果不佳的原因大多是由于对 Q Q Q 函数的错误估计所导致,即使在论文 IQL中,也对OOD之外的state-action不例外,因此对基于Off-policy的迭代算法总结得出如下两个问题:

  • Distribution shift: 学习策略与行为策略之间
  • iterative error exploitation:策略优化引入了偏差,而动态规划则在整个状态空间中传播了这种偏差。 之前在BCQ中提出了外延误差。

目前经典的解决方法主要包括以下三种:

  • policy constraints/regularization: 其目标通过学习参数让行为策略和学习策略how close, 本质是iterative & offpolicy, 比如BCQ、CQL等
  • modifications of imitation learning:本质是iterative, 如ABM、CRR、BAIL等
  • Q regularization: 防止学习策略选择未知动作方法是加入某种形式的正规化,以鼓励学习策略呆在行为策略附近。比如BRAC、CQL、R_BVE等

1.2 迭代算法的问题

迭代会让误差不断累积放大,之前在Double Q learning中说明过这个问题,作者在这里重新分析了该过程

在论文Error Propagation for API中有明确的定义:
离线强化学习(Offline RL)系列3: (算法篇) Onestep 算法详解与实现_第2张图片

那么有没有办法避免这种问题呢?作者提出只要数据集足够大、行为策略有一个好的状态空间可以确保收敛就都可以的。

但这种很难满足,于是作者提出了Onestep RL方法 (其实Caglar Gulcehre等人之前就研究过Onestep算法在离散动作上的应用,只不过他们称为:行为值估计(Regularized Behavior Value Estimation,R_BVE)), 作者在此处提出的Onestep主要是去解决continous任务,这里面最大的不同在于:

  • 连续任务中存在actor-critic的方法,而在离散任务中,策略改进可以 Q Q Q 函数精确地计算出来。
  • Caglar Gulcehre等人将迭代(iterative)算法的性能不佳归因于“高估(overestimate)”,而作者重新定义和区分了distribution shift和迭代iterative误差利用的问题,这些问题结合起来会导致高估。

2. 理论原理方法

在sutton的圣经书中明确解释了1-step和n-step的含义,包含了n-step sarsa等算法的执行过程,在这里多了一个multi-step,这里首先阐述一下One-step、multi-step以及n-step之间的关系,

2.1 One-step和Multi-step区别

离线强化学习(Offline RL)系列3: (算法篇) Onestep 算法详解与实现_第3张图片

从图中我们可以明显看到,onestep在safe policy范围内一次就可以,而multi-step则通过不断地iterative直到最优,这里补充一张R-BVE论文中关于该概念的阐述(更加清晰),后文将从代码角度分析。接着我们看作者提出的template。

2.2 原理 and 算法模板

在这里,作者给结合2.1 中第二幅图得出了一个通用的算法模板(algorithmic template),如下所示:
离线强化学习(Offline RL)系列3: (算法篇) Onestep 算法详解与实现_第4张图片
这里有几个关键变量: K K K E \mathcal{E} E 以及 I \mathcal{I} I

2.2.1 One-step

如果 K = 1 K=1 K=1 ,我们就认为是Onestep 操作, 同时通过最大似然法(maximum
likelihood)来学习 β ^ \hat{\beta} β^ ,并训练策略去估计 Q β Q^{\beta} Qβ (备注:作者解释这个时候可以用任意策略去更新 π 1 \pi_{1} π1 ,且不涉及任何off-policy操作)
离线强化学习(Offline RL)系列3: (算法篇) Onestep 算法详解与实现_第5张图片

2.2.2 Multi-step

如果 K > 1 K>1 K>1 , 我们成称之为 Multi-step 操作, 由于 β \beta β 是从数据 D N D_{N} DN 中收集,所以evaluation operator必须去评估off-policy, 且当 K > 2 K>2 K>2 时,评估策略 π k ≠ β \pi_{k} \neq \beta πk=β ,每次在估计和改进步骤中去训练直至收敛性。

2.2.3 Iterative actor-critic

Actor-critic 方法看起来有点像Multi-step算法,但不会在每次迭代时训练收敛,而是使用更大的 K K K 。这里每次迭代都包含一个更新 Q Q Q 估计的梯度step和一个改进 Q Q Q 估计值的梯度步骤策略。 由于所有evaluation和improvement operator都是基于梯度的,因此该算法可以采用与multi-step算法相同的评估和改进operator。

2.3 策略优化操作符( Policy improvement Operators)

2.3.1 Behavior clone

π ← β ^ \pi \gets \hat{\beta} πβ^

2.3.2 Constraint policy updates

经典的BCQ、BEAR等算法将学习策略限制在一个支撑集范围内,本文直接将BCQ进行了简化,即"Easy-BCQ"(删掉了其中的扰动网络perturbation network), 在这里作者 从 β \beta β 中采样了 M M M 和tuple 并重新定义了新策略 π ^ k M \hat{\pi}_{k}^{M} π^kM , 然后从 Q ^ β \hat{Q}^{\beta} Q^β 中执行
π ^ k M ( a ∣ s ) = 1 [ a = arg ⁡ max ⁡ a j { Q ^ π k − 1 ( s , a j ) : a j ∼ π k − 1 ( ⋅ ∣ s ) , 1 ≤ j ≤ M } ] \hat{\pi}_{k}^{M}(a \mid s)=\mathbb{1}\left[a=\arg \max _{a_{j}}\left\{\widehat{Q}^{\pi_{k-1}}\left(s, a_{j}\right): a_{j} \sim \pi_{k-1}(\cdot \mid s), 1 \leq j \leq M\right\}\right] π^kM(as)=1[a=argajmax{Q πk1(s,aj):ajπk1(s),1jM}]

2.3.3 Regularized policy update

另外作者也提到了regulization方法,同时提了一个reverse KL(没去仔细研究)。
π ^ k α = arg ⁡ max ⁡ π ∑ i E a ∼ π ∣ s [ Q ^ π k − 1 ( s i , a ) ] − α D ( β ^ ( ⋅ ∣ s i ) , π ( ⋅ ∣ s i ) ) \hat{\pi}_{k}^{\alpha}=\arg \max _{\pi} \sum_{i} \underset{a \sim \pi \mid s}{\mathbb{E}}\left[\widehat{Q}^{\pi_{k-1}}\left(s_{i}, a\right)\right]-\alpha D\left(\hat{\beta}\left(\cdot \mid s_{i}\right), \pi\left(\cdot \mid s_{i}\right)\right) π^kα=argπmaxiaπsE[Q πk1(si,a)]αD(β^(si),π(si))
离线强化学习(Offline RL)系列3: (算法篇) Onestep 算法详解与实现_第6张图片

2.3.4 reverse KL

π ^ k τ = arg ⁡ max ⁡ π ∑ i exp ⁡ ( τ ( Q ^ π k − 1 ( s i , a i ) − V ^ ( s i ) ) ) log ⁡ π ( a i ∣ s i ) \hat{\pi}_{k}^{\tau}=\arg \max _{\pi} \sum_{i} \exp \left(\tau\left(\widehat{Q}^{\pi_{k-1}}\left(s_{i}, a_{i}\right)-\widehat{V}\left(s_{i}\right)\right)\right) \log \pi\left(a_{i} \mid s_{i}\right) π^kτ=argπmaxiexp(τ(Q πk1(si,ai)V (si)))logπ(aisi)

个人理解总结一下:其实Onestep就是policy的evaluation和improvement分开了,没有通过iterative的方式去更新,而是直接通过on-policy的方式去evaluation了
离线强化学习(Offline RL)系列3: (算法篇) Onestep 算法详解与实现_第7张图片

以上是作者关于方法的而一些定义,下满让我们看一下实验效果。

3. 实验结果分析

3.1 性能分析

这里作者对比了onestep和iterative的结果,表1中清晰表明,除了在random数据集上,onestep效果相比其他算法差之外(作者后面有分析原因),其他效果均不错。
离线强化学习(Offline RL)系列3: (算法篇) Onestep 算法详解与实现_第8张图片
当然作者在这里也分析了onestep、multi-step以及iterative之间的区别
离线强化学习(Offline RL)系列3: (算法篇) Onestep 算法详解与实现_第9张图片

3.2 学习曲线分析

作者在这里解释了说onestep算法相比其他的更加稳定,方差更小,没有大起大落。
离线强化学习(Offline RL)系列3: (算法篇) Onestep 算法详解与实现_第10张图片

3.3 Overestimate 分析

离线强化学习(Offline RL)系列3: (算法篇) Onestep 算法详解与实现_第11张图片
离线强化学习(Offline RL)系列3: (算法篇) Onestep 算法详解与实现_第12张图片

4 非常重要的总结结论与讨论

这一部分也是作者在此论文中的一份非常大的亮点.

4.1 学习曲线和超参数灵敏性

从图中很明显看到,迭代算法开始效果还然后崩溃。正则化可以帮助防止这种崩溃,因为对行为策略的足够强的正则化确保了评估几乎是在策略上的。
离线强化学习(Offline RL)系列3: (算法篇) Onestep 算法详解与实现_第13张图片
离线强化学习(Offline RL)系列3: (算法篇) Onestep 算法详解与实现_第14张图片

4.2 分布偏移(Distribution shift)

离线强化学习(Offline RL)系列3: (算法篇) Onestep 算法详解与实现_第15张图片
这个是个老问题了,不在赘述。

4.3 迭代误差利用( Iterative error exploitation)

在原始离散动作上的onestep方法 R-BVE中,作者明确的给出了由于OOD之外的原因导致 Q Q Q 函数过高的原因,图中的解释非常的清晰。
离线强化学习(Offline RL)系列3: (算法篇) Onestep 算法详解与实现_第16张图片

Intuition about the problem
KaTeX parse error: Undefined control sequence: \substack at position 51: …amma \underset{\̲s̲u̲b̲s̲t̲a̲c̲k̲{s^{\prime}|| s…

Q ^ π ( s , a ) = Q π ( s , a ) + Q ~ β π ( s , a ) , Q ~ β π ( s , a ) : = E π ∣ s 0 , a 0 = s , a [ ∑ t = 0 ∞ γ t ε β ( s t , a t ) ] \widehat{Q}^{\pi}(s, a)=Q^{\pi}(s, a)+\widetilde{Q}_{\beta}^{\pi}(s, a), \quad \widetilde{Q}_{\beta}^{\pi}(s, a):=\underset{\pi \mid s_{0}, a_{0}=s, a}{\mathbb{E}}\left[\sum_{t=0}^{\infty} \gamma^{t} \varepsilon_{\beta}\left(s_{t}, a_{t}\right)\right] Q π(s,a)=Qπ(s,a)+Q βπ(s,a),Q βπ(s,a):=πs0,a0=s,aE[t=0γtεβ(st,at)]

作者同时给出了例子说明:
离线强化学习(Offline RL)系列3: (算法篇) Onestep 算法详解与实现_第17张图片


5 什么时候用Multi-step

之前讨论过 multi-step 和 iterative 的算法存在估计误差传播的问题。虽然 multi-step 算法比 one-step 算法会更广泛地传播这种噪声,但它们在传播噪声的同时也传播了有用的信号。所以,当数据集中有足够的覆盖范围来降低噪声的大小时,随着噪声减小,那么信号的传播相对来说就会增强,这可以帮助迭代算法的训练。

6. OpenReview审稿意见

本篇论文每一位审稿人都给出了相当高的分数,且最终录取为spotlight: 【Access】Offline RL Without Off-Policy Evaluation
离线强化学习(Offline RL)系列3: (算法篇) Onestep 算法详解与实现_第18张图片

7. 代码实现细节

作者提供了基于pytorch的源代码

离线强化学习(Offline RL)系列3: (算法篇) Onestep 算法详解与实现_第19张图片

离线强化学习(Offline RL)系列3: (算法篇) Onestep 算法详解与实现_第20张图片
上图中的红色圈是本文非常重要的核心内容。

# train
    if cfg.pi.name == 'pi_easy_bcq':
        pi.update_beta(beta)
        pi.update_q(q)

    # train beta
    if cfg.train_beta:
        for step in range(int(cfg.beta_steps)):
            beta.train_step(replay, None, None, None)

            if step % int(cfg.log_freq) == 0:
                logger.update('beta/step', step)
                beta.eval(env, cfg.eval_episodes)
                logger.write_sub_meter('beta')
            if step % int(cfg.beta_save_freq) == 0:
                beta.save(cfg.beta.model_save_path + '_' + str(step) + '.pt')

    # train baseline
    if cfg.train_baseline:
        for step in range(int(cfg.baseline_steps)):
            baseline.train_step(replay)

            if step % int(cfg.log_freq) == 0:
                logger.update('baseline/step', step)
                baseline.eval(env, beta, cfg.eval_episodes)
                logger.write_sub_meter('baseline')
            if step % int(cfg.beta_save_freq) == 0:
                beta.save(cfg.beta.model_save_path + '_' + str(step) + '.pt')

    # load beta as init pi
    pi.load_from_pilearner(beta)

    # iterate between eval and improvement
    for out_step in range(int(cfg.steps)):        
        # train Q
        if cfg.train_q:
            for in_step in range(int(cfg.q_steps)): 
                q.train_step(replay, pi, beta)
                
                step = out_step * int(cfg.q_steps) + in_step 
                if step % int(cfg.log_freq) == 0:
                    logger.update('q/step', step)
                    q.eval(env, pi, cfg.eval_episodes)
                    logger.write_sub_meter('q')
                
                if step % int(cfg.q_save_freq) == 0:
                    q.save(cfg.q.model_save_path + '_' + str(step) + '.pt')

        # train pi
        if cfg.train_pi and cfg.pi.name != 'pi_easy_bcq':
            for in_step in range(int(cfg.pi_steps)):
                pi.train_step(replay, q, baseline, beta)

                step = out_step * int(cfg.pi_steps) + in_step
                if step % int(cfg.log_freq) == 0:
                    logger.update('pi/step', step)
                    pi.eval(env, cfg.eval_episodes)
                    logger.write_sub_meter('pi')
                if step % int(cfg.pi_save_freq) == 0:
                    pi.save(cfg.pi.model_save_path + '_' + str(step) + '.pt')
        elif cfg.pi.name == 'pi_easy_bcq':
            step = out_step + 1
            pi.update_q(q)
            if step % int(cfg.log_freq) == 0:
                logger.update('pi/step', step)
                pi.eval(env, cfg.eval_episodes)
                logger.write_sub_meter('pi')
    
    if cfg.train_q:
        q.save(cfg.q.model_save_path + '.pt')
    if cfg.train_pi:
        pi.save(cfg.pi.model_save_path + '.pt')

参考文献

[1]. David Brandfonbrener, William F. Whitney, Rajesh Ranganath, Joan Bruna: “Offline RL Without Off-Policy Evaluation”, 2021; arXiv:2106.08909.
[2]. Caglar Gulcehre, Sergio Gómez Colmenarejo, Ziyu Wang, Jakub Sygnowski, Thomas Paine, Konrad Zolna, Yutian Chen, Matthew Hoffman, Razvan Pascanu, Nando de Freitas: “Regularized Behavior Value Estimation”, 2021; arXiv:2103.09575.


OfflineRL推荐阅读

离线强化学习(Offline RL)系列3: (算法篇) IQL(Implicit Q-learning)算法详解与实现
离线强化学习(Offline RL)系列3: (算法篇) CQL 算法详解与实现
离线强化学习(Offline RL)系列3: (算法篇) TD3+BC 算法详解与实现(经验篇)
离线强化学习(Offline RL)系列3: (算法篇) REM(Random Ensemble Mixture)算法详解与实现
离线强化学习(Offline RL)系列3: (算法篇)策略约束 - BRAC算法原理详解与实现(经验篇)
离线强化学习(Offline RL)系列3: (算法篇)策略约束 - BEAR算法原理详解与实现
离线强化学习(Offline RL)系列3: (算法篇)策略约束 - BCQ算法详解与实现
离线强化学习(Offline RL)系列2: (环境篇)D4RL数据集简介、安装及错误解决
离线强化学习(Offline RL)系列1:离线强化学习原理入门

你可能感兴趣的:(离线强化学习系列博客,离线强化学习,Offline,RL,Onestep,Multi-step,n-step)