Q学习与DQN

欸呦图丢了

Q学习

一种与模型无关的、基于值的强化学习算法,直接迭代优化\(Q_{\bm\theta}\)直至收敛。其中\(\bm\theta\)\(Q\)的参数。

MDP

  • \(\mathcal S\):状态集,\(\bm s=\mathbb R^n\)
  • \(\mathcal A\):动作集,\(\bm a=\mathbb R^d\)
  • \(T\):可供模型决策的最长时间或者最大步数,\(t\)就是时间;设置一个仿真器并提供\(m\)个初始状态执行随机动作并模拟\(T\)步,可以得到\(m\)串马尔可夫链;
  • \(P\)\(^t\bm w\sim\mathcal N(0,\Sigma_{\bm w})\)是高斯噪声;$$^tP_{\bm s,\bm a}(\bm s^\prime)=1\ ,\ P_{\bm s,\bm a}(\bm s^\prime)\geq0\ ,\ \bm s^\prime\sim P_{\bm s,\bm a}$$ $${^{t+1}\bm s}={^t\bm A}{^{t}\bm s}+{^t\bm B}{^{t}\bm a}+{^t\bm w},\ {^t\bm A}=\mathbb R^{n\times n},\ {^t\bm B}=\mathbb R^{n\times d}$$
  • \(R\)\(R=\mathbb R^{d\times n}\)

\(\bm s\)状态下的奖励最大(最优)的动作为:

\[\bm a^*=\pi^*(\bm s)=\arg\max_\bm a\sum_{s^\prime\in \mathcal S}P_{\bm s,\bm a}(s^\prime)V(s^\prime)=\arg\max_\bm a\mathbb E_{s^\prime\sim P_{\bm s,\bm a}}\big[V^*(s^\prime)\big] \]

其中,价值函数\(V\)为:

\[V(\bm s)=R(\bm s)+\Gamma \sum_{\bm s^\prime\in \mathcal S}P_{\bm s\to \bm s^\prime}V(\bm s^\prime) \]

DQN采用深度学习来代替MDP中的无穷递归求\(V(\bm s)\)

Q函数\(Q(\bm s,\bm a)\)是指在一个给定状态\(\bm s\)下采取某一个动作\(\bm a\)之后,后续的各个状态所能得到的回报的期望值。和监督学习不同,Q学习的训练数据也需要标注,但这个标注是一个比现在能够计算的动作\(\bm a\)更好的\(\bm a^\prime\),迭代直到\(\bm a^\prime\to \bm a^*\)。而且这些标注并不能从数据中直接得到,是从环境得到\(\bm s^\prime\)然后MDP计算出价值间接得到的。

在线Q迭代

训模型时产生动作\(\bm a\)的策略被叫行为策略,而跑模型时的策略被叫目标策略。当行为策略和目标策略是同一个策略时该算法就是一种在线策略方法,也就是边跑边训,参数\(\bm \theta\)跑着跑着就优化了。如果是先训后跑,那就是离线策略方法。“在线Q迭代”这个名字具有一些迷惑性,因为它是离线策略方法。

function(\(\mathcal S\), \(\mathcal A\), epochs, environment){
    var \(\bm\theta\) = init();
    for(var i in range(0, epochs)){
        var {\(\bm{s}_i\),\(\bm{a}_i\),\(r_i\),\(\bm{s}_i^\prime\)} = environment(\(\bm{s}_i\),\(\bm{a}_i\));
        var \(y\) = \(\displaystyle r+\gamma\max_{\bm{a}_{i}^\prime\in \mathcal A_{i}^\prime}Q_{\bm\theta}(\bm{s}_{i}^\prime,\bm{a}_{i}^\prime)\);
        \(\displaystyle\bm\theta=\bm\theta-lr\text{Loss}(Q_{\bm\theta}(\bm{s},\bm{a}), y)\frac{\mathrm{d}Q_{\bm\theta}(\bm{s},\bm{a})}{\mathrm{d}\bm\theta}\);
    }
    return \(\bm\theta\);
}

显然,未必有\(\bm{a}_i^\prime=\bm{a}_{i+1}\)

拟合Q迭代

也是离线策略方法。

function(x, epochs, batchSize){
    var \(\bm\theta\) = init();
    for(var t in range(0, epochs)){
        var batch = Random.select(x, batchSize); /* 抽取一定数量的状态、动作、奖励 */
        for(var i in range(0, batchSize)){
            var {\(\bm{s}\),\(\bm{a}\),\(r\),\(\bm{s}^\prime\)} = batch[i];
            var \(y\) = \(\displaystyle r+\gamma\max_{\bm{a}^\prime\in \mathcal A^\prime}Q_{\bm\theta}(\bm{s}^\prime,\bm{a}^\prime)\);
            \(\displaystyle\bm\theta=\arg\min_{\bm\theta}\text{Loss}(Q_{\bm\theta}(\bm{s},\bm{a}),y)\);
        }
    }
    return \(\bm\theta\);
}

DQN

DQN通过经验回放目标网络两个关键技术结合Q学习和深度学习来解决不稳定性问题。

  • 经验回放
    获取随机的样本集,以此满足深度学习训练数据需要,连续采样得到的样本集各个样本都是高度相关的。夸张一点,就像是在一批次中所有样本都差不多。
  • 目标网络
    用模型\(Q\)计算\(\hat{\bm{y}}\)并用目标网络\(\hat{Q}\)来计算\(\bm y\),然后每隔一定步数就用\(Q\)的参数\(\bm\theta\)更新一次\(\hat{Q}\),这样\(\bm{y}\)不会受到最新参数的影响,收敛变慢了但是换来了稳定性。

function(props){
    var {epochs, \(T\), batchSize, C, environment, \(\epsilon\)} = props;
    var \(\bm\theta\) = init();
    for(var epoch in range(0, epochs){
        for(var \(t\) in range(0, \(T\)){
            /* 选取动作,其中函数\(\phi\)用来将状态处理成模型入参并可能做一些额外转换以及其它数据操作,例如加入前几帧状态等 */
            var \(\bm{a}_t\);
            if(Random.rand() > \(\epsilon\)){
                /* 等模型训练完之后,👇这一行就是最常执行的操作 */
                \(\bm{a}_t\) = \(\arg\max_\bm{a}Q_{\bm\theta}(\phi(\bm{s}_t),\bm{a})\);
            }else{
                \(\bm{a}_t\) = Random.rand(Action.shape);
            }
            var {\(\bm{s}_{t+1}\), \(r_t\)} = environment(\(\bm{s}_t\),\(\bm{a}_t\)); /* \(r_t\)是当前状态的奖励,一般不包含未来的 */
            Cache.insert({\(\bm \phi\) = \(\phi(\bm{s}_{t})\), \(\bm a\) = \(\bm{a}_t\), \(r\) = \(r_t\), \({\bm\phi}^\prime\) = \(\phi(\bm{s}_{t+1})\)}); /* 积累经验 */
            /* 从经验回放取出一定量的数据参与拟合,当然,经验数量不够也不能凭空生出来 */
            for (var {\(\bm{\phi}\), \(r\), \(\bm a\), \({\bm\phi}^\prime\)} in Cache.selectRandom(batchSize){
                var \(\bm y\) = \(r_i+\gamma\max_\bm{a^\prime} Q_{\hat{\bm\theta}}({\bm\phi}^\prime,{\bm{a}}^\prime)\);
                \(\bm\theta\) -= \(\nabla_{\bm\theta}\text{Loss}(Q_{\bm\theta}(\bm\phi,\bm{a}),\bm{y})\);
            }
            if(t % C == 0){
                /* 每隔一定步数就用\(Q\)的参数\(\bm\theta\)更新一次\(\hat{Q}=Q_{\hat{\bm\theta}}\);可以采用“软更新” */
                \(\hat{\bm\theta}\) = update(\(\hat{\bm\theta}\), \(\bm\theta\));
            }
        }
    }
    /* 其实返回\(\bm\theta\)\(\hat{\bm\theta}\)差不多,因为此时模型已经收敛,两组参数差异微小 */
    return \(\hat{\bm\theta}\);
}

实际上神经网络的输出维数表示操作种类数时,每一个输出层节点的输出表示当前状态下执行这个输出层节点所对应动作的价值,而神经网络的输入中可以不直接包含动作。即当模型参数收敛到极小值时\(Q_{\bm\theta}(\bm s)=\begin{bmatrix}V_{\bm{s},\bm{a}_0}\ V_{\bm{s},\bm{a}_1}\ \cdots \ V_{\bm{s},\bm{a}_d} \end{bmatrix}^\text{T}\)\(\bm a^*=\arg\max_{\bm a}V_{\bm a}\)

转载声明

posted on 2022-03-24 20:27  星云*  阅读(312)  评论(0编辑  收藏  举报