第六章 函數逼近-強化學習理論學習與代碼實現(強化學習導論第二版)

在這裏插入圖片描述
獲取更多資訊,趕快關注上面的公衆號吧!

【強化學習系列】

第六章 函數逼近

在前面的章節中我們介紹的都是表格型強化學習,但是當問題的狀態空間很大,表格型強化學習需要爲每一個狀態存儲其每一個可選動作的估計值,勢必需要很大的內存佔用,例如西洋雙陸棋的狀態空間爲102010^{20},計算機圍棋的狀態空間爲1017010^{170},甚至像直升機控制這樣的問題其狀態空間爲無限大。那麼該如何才能將之前講的無模型預測和控制擴展到這種情況呢?這就是本部分要講的函數近似或逼近

6.1 學習目標

  • 理解相較於查表法函數逼近的動機;
  • 理解如何將函數逼近集成到現有的算法中;
  • 代碼實現線性函數逼近的Q學習。

6.2 值函數近似

之前的內容是通過查表法來表達值函數,一種方式就是記錄每個狀態的值V(s),另一種就是狀態-動作值函數Q(s,a),但是面對大規模MDPs時,可能會有太多的狀態或動作而無法內存存儲,哪怕能存儲,對於這麼大的一張表格進行學習,速度也是很慢的。因此一種簡單的方式就是建立參數近似函數來逼近真正的價值。
v^(s,w)vπ(s)\hat{v}(s, \mathbf{w}) \approx v_{\pi}(s)
 or q^(s,a,w)qπ(s,a)\text { or } \hat{q}(s, a, \mathbf{w}) \approx q_{\pi}(s, a)
其中w\mathbf{w}表示權重,或者說是逼近器的參數,通過對特徵基進行加權求和。
通過這樣的方式,只要給定狀態或狀態-動作對,就能給出相應的近似值,一方面減少了內存佔用,更重要的是可以預測未知狀態下的價值,從而大大增強泛化性。而w\mathbf{w}可以藉助MC或TD學習進行更新。

值函數近似就像是一個黑盒子,只要給定輸入就能得到輸出,根據輸入和輸出的不同,可以分爲三種類型,如圖1所示。

  1. 輸入狀態,輸出值函數;
  2. 輸入狀態和動作,輸出狀態-動作值函數;
  3. 輸入狀態,輸出每個動作的狀態-動作值函數。
圖1 值函數近似的不同類型

應該選擇什麼樣的函數逼近器呢?目前有很多方式可以實現,如下所示,但一般考慮選擇可微分的函數逼近器,例如下面的線性特徵組合和神經網絡。除此之外,還需要一種適用於非平穩、非獨立同分布數據的訓練方法。

  1. 線性特徵組合
  2. 神經網絡
  3. 決策樹
  4. 最近鄰域
  5. 傅里葉/小波基
  6. ……

6.2 增量式方法

6.2.1 梯度下降

梯度下降

J(w)J(\mathbf{w})爲參數向量w\mathbf{w}的可微函數,J(w)J(\mathbf{w})的梯度定義爲對J(w)J(\mathbf{w})w\mathbf{w}的各個維度上分別進行偏微分,即
wJ(w)=(J(w)w1J(w)wn)\nabla_{\mathbf{w}} J(\mathbf{w})=\left(\begin{array}{c} \frac{\partial J(\mathbf{w})}{\partial \mathbf{w}_{1}} \\ \vdots \\ \frac{\partial J(\mathbf{w})}{\partial \mathbf{w}_{n}} \end{array}\right)
爲了找到J(w)J(\mathbf{w})的局部最小值,只需要沿着負梯度方向更新w\mathbf{w}即可:
Δw=12αwJ(w)\Delta \mathbf{w}=-\frac{1}{2} \alpha \nabla_{\mathbf{w}} J(\mathbf{w})
其中α\alpha爲步長參數。

隨機梯度下降的值函數近似

一個好的逼近器就是要儘量減少近似值和真實值之間的誤差,因此函數逼近的目標就是找到一個參數向量w\mathbf{w},使得近似值v^(s,w)\hat{v}(s, \mathbf{w})vπ(s)v_{\pi}(s)之間的均方誤差最小:
J(w)=Eπ[(vπ(S)v^(S,w))2]J(\mathbf{w})=\mathbb{E}_{\pi}\left[\left(v_{\pi}(S)-\hat{v}(S, \mathbf{w})\right)^{2}\right]
通過使用梯度下降,可以按照如下進行參數更新:
Δw=12αwJ(w)=αEπ[(vπ(S)v^(S,w))wv^(S,w)]\begin{aligned} \Delta \mathbf{w} &=-\frac{1}{2} \alpha \nabla_{\mathbf{w}} J(\mathbf{w}) \\ &=\alpha \mathbb{E}_{\pi}\left[\left(v_{\pi}(S)-\hat{v}(S, \mathbf{w})\right) \nabla_{\mathbf{w}} \hat{v}(S, \mathbf{w})\right] \end{aligned}
而在實際更新時並不是使用全梯度下降,而是隨機採樣一個狀態,去評判該狀態下的真實價值與近似值之間的誤差:
Δw=α(vπ(S)v^(S,w))wv^(S,w)\Delta \mathbf{w}=\alpha\left(v_{\pi}(S)-\hat{v}(S, \mathbf{w})\right) \nabla_{\mathbf{w}} \hat{v}(S, \mathbf{w})

6.2.2 線性函數逼近

特徵向量

可以使用一組特徵向量來表達狀態,特徵向量中每個元素都是狀態的一個具體表現:
x(S)=(x1(S)xn(S))\mathbf{x}(S)=\left(\begin{array}{c} \mathbf{x}_{1}(S) \\ \vdots \\ \mathbf{x}_{n}(S) \end{array}\right)
例如:

  • 機器人與地標的距離
  • 股票市場的走勢
  • 象棋中車和卒的局面

線性值函數近似

使用特徵向量的最簡單的方法就是對這些特徵進行線性組合來表達近似值函數:
v^(S,w)=x(S)w=j=1nxj(S)wj\hat{v}(S, \mathbf{w})=\mathbf{x}(S)^{\top} \mathbf{w}=\sum_{j=1}^{n} \mathbf{x}_{j}(S) \mathbf{w}_{j}
同樣目標函數是真實值與近似值之間的均方誤差:
J(w)=Eπ[(vπ(S)x(S)w)2]J(\mathbf{w})=\mathbb{E}_{\pi}\left[\left(v_{\pi}(S)-\mathbf{x}(S)^{\top} \mathbf{w}\right)^{2}\right]
同樣採用隨機梯度下降,可以得到如下很簡單的參數更新規則:
wv^(S,w)=x(S)Δw=α(vπ(S)v^(S,w))x(S)\begin{aligned} \nabla_{\mathbf{w}} \hat{v}(S, \mathbf{w}) &=\mathbf{x}(S) \\ \Delta \mathbf{w} &=\alpha\left(v_{\pi}(S)-\hat{v}(S, \mathbf{w})\right) \mathbf{x}(S) \end{aligned}
因此,在線性值函數近似情況下,更新規則可以概括爲:
Update == step-size ×\times prediction error ×\times feature value

查表特徵

查表實際上是線性值函數近似的一種特殊情況,查表特徵可以表示爲:
xtable(S)=(1(S=s1)1(S=sn))\mathbf{x}^{\text {table}}(S)=\left(\begin{array}{c} \mathbf{1}\left(S=s_{1}\right) \\ \vdots \\ \mathbf{1}\left(S=s_{n}\right) \end{array}\right)
對於狀態1,如果處在狀態1,則對應位置的值爲1否則爲0,其他狀態以此類推(類似於獨熱編碼)。
只要給定參數向量w\mathbf{w},就可以通過查表特徵與權重的點積計算近似值函數。
v^(S,w)=(1(S=s1)1(S=sn))(w1wn)\hat{v}(S, \mathbf{w})=\left(\begin{array}{c} \mathbf{1}\left(S=s_{1}\right) \\ \vdots \\ \mathbf{1}\left(S=s_{n}\right) \end{array}\right) \cdot\left(\begin{array}{c} \mathbf{w}_{1} \\ \vdots \\ \mathbf{w}_{n} \end{array}\right)

6.2.3 增量預測算法

增量預測算法

前面講的兩種方法(梯度下降和線性逼近)其實有一個前提,就是真實價值函數是已知的,這樣就變成了監督學習,但是很遺憾的是,真實值函數往往不能提前已知,並且強化學習中也只能給出獎勵值,最基本的方法就是利用之前的蒙特卡洛方法和時序差分方法來設立真實值函數的目標。

  • 對於MC,目標就是回報值GtG_{t},則對應更新爲:
    Δw=α(Gtv^(St,w))wv^(St,w)\Delta \mathbf{w}=\alpha\left(G_{t}-\hat{v}\left(S_{t}, \mathbf{w}\right)\right) \nabla_{\mathbf{w}} \hat{v}\left(S_{t}, \mathbf{w}\right)
  • 對於TD(0),目標爲TD目標Rt+1+γv^(St+1,w)R_{t+1}+\gamma \hat{v}\left(S_{t+1}, \mathbf{w}\right)
    Δw=α(Rt+1+γv^(St+1,w)v^(St,w))wv^(St,w)\Delta \mathbf{w}=\alpha\left(R_{t+1}+\gamma \hat{v}\left(S_{t+1}, \mathbf{w}\right)-\hat{v}\left(S_{t}, \mathbf{w}\right)\right) \nabla_{\mathbf{w}} \hat{v}\left(S_{t}, \mathbf{w}\right)
  • 對於TD(λ\lambda),目標爲λ\lambda回報GtλG_{t}^{\lambda}
    Δw=α(Gtλv^(St,w))wv^(St,w)\Delta \mathbf{w}=\alpha\left(G_{t}^{\lambda}-\hat{v}\left(S_{t}, \mathbf{w}\right)\right) \nabla_{\mathbf{w}} \hat{v}\left(S_{t}, \mathbf{w}\right)

基於值函數近似的蒙特卡洛

其實上面講的設定目標的過程和監督學習很相近,當使用蒙特卡洛方法時,主要使用的是returnGtG_{t},這個過程就是完善建立訓練數據,但這個過程是逐漸累積完成的,首先看到了狀態S1S_{1},在該狀態下有一個軌跡,然後得到一個回報G1G_{1},接下來狀態S2S_{2}得到回報G2G_{2},以此類推直到結束狀態。
S1,G1,S2,G2,,ST,GT\left\langle S_{1}, G_{1}\right\rangle,\left\langle S_{2}, G_{2}\right\rangle, \ldots,\left\langle S_{T}, G_{T}\right\rangle
現在需要做的基本上和監督學習一下,把上述過程生成的數據看成真實數據,只需要調整值函數近似模型去不斷逼近這些數值即可。
例如使用線性蒙特卡洛策略評估的更新方式如下:
Δw=α(Gtv^(St,w))wv^(St,w)=α(Gtv^(St,w))x(St)\begin{aligned} \Delta \mathbf{w} &=\alpha\left(G_{t}-\hat{v}\left(S_{t}, \mathbf{w}\right)\right) \nabla_{\mathbf{w}} \hat{v}\left(S_{t}, \mathbf{w}\right) \\ &=\alpha\left(G_{t}-\hat{v}\left(S_{t}, \mathbf{w}\right)\right) \mathbf{x}\left(S_{t}\right) \end{aligned}
在蒙特卡洛中GtG_{t}無偏的,通過隨機梯度下降,蒙特卡洛評估總能收斂到最優,但是學習過程會比較漫長。

基於值函數近似的TD學習

TD學習同樣採用了相同的思想,只不過現在的TD目標Rt+1+γv^(St+1,w)R_{t+1}+\gamma \hat{v}\left(S_{t+1}, \mathbf{w}\right)有偏的,但仍然可以將監督學習應用以下訓練數據:
S1,R2+γv^(S2,w),S2,R3+γv^(S3,w),,ST1,RT\left\langle S_{1}, R_{2}+\gamma \hat{v}\left(S_{2}, \mathbf{w}\right)\right\rangle,\left\langle S_{2}, R_{3}+\gamma \hat{v}\left(S_{3}, \mathbf{w}\right)\right\rangle, \ldots,\left\langle S_{T-1}, R_{T}\right\rangle
例如對於線性TD(0),更新如下:
Δw=α(R+γv^(S,w)v^(S,w))wv^(S,w)=αδx(S)\begin{aligned} \Delta \mathbf{w} &=\alpha\left(R+\gamma \hat{v}\left(S^{\prime}, \mathbf{w}\right)-\hat{v}(S, \mathbf{w})\right) \nabla_{\mathbf{w}} \hat{v}(S, \mathbf{w}) \\ &=\alpha \delta \mathbf{x}(S) \end{aligned}
線性TD(0)能收斂或接近全局最優。

基於值函數近似的TD(λ\lambda)

GtλG_{t}^{\lambda}也是真實值函數的有偏估計,可以將監督學習應用到以下訓練數據:
S1,G1λ,S2,G2λ,,ST1,GT1λ\left\langle S_{1}, G_{1}^{\lambda}\right\rangle,\left\langle S_{2}, G_{2}^{\lambda}\right\rangle, \ldots,\left\langle S_{T-1}, G_{T-1}^{\lambda}\right\rangle
例如對於前向視角線性TD(λ\lambda),更新如下:
Δw=α(Gtλv^(St,w))wv^(St,w)=α(Gtλv^(St,w))x(St)\begin{aligned} \Delta \mathbf{w} &=\alpha\left(G_{t}^{\lambda}-\hat{v}\left(S_{t}, \mathbf{w}\right)\right) \nabla_{\mathbf{w}} \hat{v}\left(S_{t}, \mathbf{w}\right) \\ &=\alpha\left(G_{t}^{\lambda}-\hat{v}\left(S_{t}, \mathbf{w}\right)\right) \mathbf{x}\left(S_{t}\right) \end{aligned}
對於後向視角線性TD(λ\lambda),更新如下:
δt=Rt+1+γv^(St+1,w)v^(St,w)Et=γλEt1+x(St)Δw=αδtEt\begin{aligned} \delta_{t} &=R_{t+1}+\gamma \hat{v}\left(S_{t+1}, \mathbf{w}\right)-\hat{v}\left(S_{t}, \mathbf{w}\right) \\ E_{t} &=\gamma \lambda E_{t-1}+\mathbf{x}\left(S_{t}\right) \\ \Delta \mathbf{w} &=\alpha \delta_{t} E_{t} \end{aligned}
但是對於前向和後向線性TD(λ\lambda)是等效的。

6.2.4 增量控制算法

基於值函數近似的控制

控制部分採用廣義迭代策略的概念,先進行策略評估,這裏運用的是近似策略評估q^(,,w)qπ\hat{q}(\cdot, \cdot, \mathbf{w}) \approx q_{\pi},然後進行ϵ\epsilon-greedy策略改進。

動作值函數近似

這裏同樣使用參數向量w\mathbf{w}來近似表達動作值函數:
q^(S,A,w)qπ(S,A)\hat{q}(S, A, \mathbf{w}) \approx q_{\pi}(S, A)
目標函數就是最小化近似動作值函數q^(S,A,w)\hat{q}(S, A, \mathbf{w})與真實動作值函數qπ(S,A)q_{\pi}(S, A)之間的均方誤差:
J(w)=Eπ[(qπ(S,A)q^(S,A,w))2]J(\mathbf{w})=\mathbb{E}_{\pi}\left[\left(q_{\pi}(S, A)-\hat{q}(S, A, \mathbf{w})\right)^{2}\right]
使用隨機梯度下降進行參數更新,找到局部最優:
12wJ(w)=(qπ(S,A)q^(S,A,w))wq^(S,A,w)Δw=α(qπ(S,A)q^(S,A,w))wq^(S,A,w)\begin{aligned} -\frac{1}{2} \nabla_{\mathbf{w}} J(\mathbf{w}) &=\left(q_{\pi}(S, A)-\hat{q}(S, A, \mathbf{w})\right) \nabla_{\mathbf{w}} \hat{q}(S, A, \mathbf{w}) \\ \Delta \mathbf{w} &=\alpha\left(q_{\pi}(S, A)-\hat{q}(S, A, \mathbf{w})\right) \nabla_{\mathbf{w}} \hat{q}(S, A, \mathbf{w}) \end{aligned}

線性動作值函數近似

使用特徵向量表達狀態和動作:
x(S,A)=(x1(S,A)xn(S,A))\mathbf{x}(S, A)=\left(\begin{array}{c} \mathbf{x}_{1}(S, A) \\ \vdots \\ \mathbf{x}_{n}(S, A) \end{array}\right)
通過特徵的加權線性組合可以表達動作值函數:
q^(S,A,w)=x(S,A)w=j=1nxj(S,A)wj\hat{q}(S, A, \mathbf{w})=\mathbf{x}(S, A)^{\top} \mathbf{w}=\sum_{j=1}^{n} \mathbf{x}_{j}(S, A) \mathbf{w}_{j}
隨機梯度下降更新如下:
wq^(S,A,w)=x(S,A)Δw=α(qπ(S,A)q^(S,A,w))x(S,A)\begin{aligned} \nabla_{\mathbf{w}} \hat{q}(S, A, \mathbf{w}) &=\mathbf{x}(S, A) \\ \Delta \mathbf{w} &=\alpha\left(q_{\pi}(S, A)-\hat{q}(S, A, \mathbf{w})\right) \mathbf{x}(S, A) \end{aligned}

增量控制算法

  • 對於MC,目標是GtG_{t},更新如下:
    Δw=α(Gtq^(St,At,w))wq^(St,At,w)\Delta \mathbf{w}=\alpha\left(G_{t}-\hat{q}\left(S_{t}, A_{t}, \mathbf{w}\right)\right) \nabla_{\mathbf{w}} \hat{q}\left(S_{t}, A_{t}, \mathbf{w}\right)
  • 對於TD(0),目標是TD目標Rt+1+γQ(St+1,At+1)R_{t+1}+\gamma Q\left(S_{t+1}, A_{t+1}\right),更新如下:
    Δw=α(Rt+1+γq^(St+1,At+1,w)q^(St,At,w))wq^(St,At,w)\Delta \mathbf{w}=\alpha\left(R_{t+1}+\gamma \hat{q}\left(S_{t+1}, A_{t+1}, \mathbf{w}\right)-\hat{q}\left(S_{t}, A_{t}, \mathbf{w}\right)\right) \nabla_{\mathbf{w}} \hat{q}\left(S_{t}, A_{t}, \mathbf{w}\right)
  • 對於前向TD(λ)T D(\lambda),目標爲動作值λ\lambda-回報,更新如下:
    Δw=α(qtλq^(St,At,w))wq^(St,At,w)\Delta \mathbf{w}=\alpha\left(q_{t}^{\lambda}-\hat{q}\left(S_{t}, A_{t}, \mathbf{w}\right)\right) \nabla_{\mathbf{w}} \hat{q}\left(S_{t}, A_{t}, \mathbf{w}\right)
  • 對於後向TD(λ)T D(\lambda),等效的更新如下:
    δt=Rt+1+γq^(St+1,At+1,w)q^(St,At,w)Et=γλEt1+wq^(St,At,w)Δw=αδtEt\begin{aligned} \delta_{t} &=R_{t+1}+\gamma \hat{q}\left(S_{t+1}, A_{t+1}, \mathbf{w}\right)-\hat{q}\left(S_{t}, A_{t}, \mathbf{w}\right) \\ E_{t} &=\gamma \lambda E_{t-1}+\nabla_{\mathbf{w}} \hat{q}\left(S_{t}, A_{t}, \mathbf{w}\right) \\ \Delta \mathbf{w} &=\alpha \delta_{t} E_{t} \end{aligned}

6.3 代碼實現

代碼實現部分我們選用Mountain Car作爲環境,環境使用位置和速度表達狀態,動作有3個:向左,不動和向右。下面給出了線性逼近的Q學習算法代碼。

import gym
import itertools
import matplotlib
import numpy as np
import sys
import sklearn.pipeline
import sklearn.preprocessing

if "../" not in sys.path:
  sys.path.append("../")

from Lib import plotting
from sklearn.linear_model import SGDRegressor
from sklearn.kernel_approximation import RBFSampler

matplotlib.style.use('ggplot')

env = gym.envs.make("MountainCar-v0")

# 特徵預處理:歸一化爲均值爲0,方差爲1
# 從觀察空間中採樣部分樣本
observation_examples = np.array([env.observation_space.sample() for x in range(10000)])
scaler = sklearn.preprocessing.StandardScaler()
scaler.fit(observation_examples)

# 用於將狀態轉換成特徵表達
# 使用不同方差的RBF核來覆蓋空間的不同部分
featurizer = sklearn.pipeline.FeatureUnion([
        ("rbf1", RBFSampler(gamma=5.0, n_components=100)),
        ("rbf2", RBFSampler(gamma=2.0, n_components=100)),
        ("rbf3", RBFSampler(gamma=1.0, n_components=100)),
        ("rbf4", RBFSampler(gamma=0.5, n_components=100))
        ])
featurizer.fit(scaler.transform(observation_examples))


class Estimator():
    """
    值函數逼近器.
    """

    def __init__(self):
        # 爲環境的動作空間中的每個動作創建一個單獨的模型。或者,我們可以以某種方式將動作編碼到特性中,但是這樣更容易編碼。
        self.models = []
        for _ in range(env.action_space.n):
            model = SGDRegressor(learning_rate="constant")
            # 需要調用一次partial_fit來初始化模型
            # 或者在預測時獲取NotFittedError
            model.partial_fit([self.featurize_state(env.reset())], [0])
            self.models.append(model)

    def featurize_state(self, state):
        """
        返回狀態的特徵化表達.
        """
        scaled = scaler.transform([state])
        featurized = featurizer.transform(scaled)
        return featurized[0]

    def predict(self, s, a=None):
        """
        進行值函數預測.

        參數:
            s: 需要預測的狀態
            a: (可選) 需要預測的動作

        返回值:
            如果給定了動作a,則返回一個數值作爲預測結果
            如果沒有給定a,則返回一個向量來預測環境中的所有動作,其中pred[i]爲對動作i的預測

        """
        features = self.featurize_state(s)
        if not a:
            return np.array([m.predict([features])[0] for m in self.models])
        else:
            return self.models[a].predict([features])[0]

    def update(self, s, a, y):
        """
        給定狀態和動作,更新逼近器參數以靠近目標y
        """
        features = self.featurize_state(s)
        self.models[a].partial_fit([features], [y])


def make_epsilon_greedy_policy(estimator, epsilon, nA):
    """
    根據給定的Q函數逼近器和epsilon,創建epsilon貪婪策略.

    參數:
        逼近器: 返回給定狀態下的q值
        epsilon: 隨機選擇動作的概率between 0 and 1
        nA: 環境中動作數量

    返回值:
        返回一個函數,以觀察爲參數,以長度爲nA的numpy數組的形式返回每個動作的概率

    """

    def policy_fn(observation):
        A = np.ones(nA, dtype=float) * epsilon / nA
        q_values = estimator.predict(observation)
        best_action = np.argmax(q_values)
        A[best_action] += (1.0 - epsilon)
        return A

    return policy_fn


def q_learning(env, estimator, num_episodes, discount_factor=1.0, epsilon=0.1, epsilon_decay=1.0):
    """
    使用函數逼近進行離策略TD控制的Q學習.
    遵循epsilon貪婪策略以尋找最優貪婪策略.

    參數:
        env: OpenAI環境.
        estimator: 動作值函數逼近器
        num_episodes: 迭代次數.
        discount_factor: Gamma折扣因子.
        epsilon: 隨機選擇動作的概率betwen 0 and 1.
        epsilon_decay: 每個片段中,epsilon都以該因子進行衰減

    返回值:
        一個片段狀態對象,包括兩個numpy數組,用於分別存放片段長度和片段獎勵.
    """

    # 進行必要的統計
    stats = plotting.EpisodeStats(
        episode_lengths=np.zeros(num_episodes),
        episode_rewards=np.zeros(num_episodes))

    for i_episode in range(num_episodes):

        # 正在遵循的策略
        policy = make_epsilon_greedy_policy(
            estimator, epsilon * epsilon_decay ** i_episode, env.action_space.n)


        last_reward = stats.episode_rewards[i_episode - 1]
        sys.stdout.flush()

        # 重置環境
        state = env.reset()
        # 只針對SARSA有用
        next_action = None

        # 環境中迭代執行每一步
        for t in itertools.count():

            # 選擇動作
            # 如果使用的時SARSA,next_action在前一步已經確定了
            if next_action is None:
                action_probs = policy(state)
                action = np.random.choice(np.arange(len(action_probs)), p=action_probs)
            else:
                action = next_action

            # 單步執行
            next_state, reward, done, _ = env.step(action)

            # 更細統計
            stats.episode_rewards[i_episode] += reward
            stats.episode_lengths[i_episode] = t

            # TD更新
            q_values_next = estimator.predict(next_state)

            # 學習Q-Learning的TD目標
            td_target = reward + discount_factor * np.max(q_values_next)

            # 使用下面的代碼進行SARSA在策略控制
            # next_action_probs = policy(next_state)
            # next_action = np.random.choice(np.arange(len(next_action_probs)), p=next_action_probs)
            # td_target = reward + discount_factor * q_values_next[next_action]

            # 使用目標更新函數逼近器
            estimator.update(state, action, td_target)

            print("\rStep {} @ Episode {}/{} ({})".format(t, i_episode + 1, num_episodes, last_reward), end="")

            if done:
                break

            state = next_state

    return stats

estimator = Estimator()
# 注意: 對於Mountain Car遊戲,不必保證epsilon>0.0
# 因爲對所有狀態的初始估計太過樂觀,從而導致對所有狀態進行探索.
stats = q_learning(env, estimator, 100, epsilon=0.0)

plotting.plot_cost_to_go_mountain_car(env, estimator)
plotting.plot_episode_stats(stats, smoothing_window=25)

最終學習到的位置和速度與值函數的關係如下。

整體上隨着迭代次數的增多,小車爬上山坡需要的部屬逐漸下降,如下所示。

隨着迭代次數的增加,片段獎勵呈現上升趨勢,如下所示。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章