05.md 21.2 KB
Newer Older
W
wizardforcel 已提交
1 2
# 时间差异学习

W
wizardforcel 已提交
3
在上一章第四章,“使用蒙特卡洛方法的游戏”中,我们了解了有趣的蒙特卡洛方法,该方法用于解决**马尔可夫决策过程****MDP**),而不像动态规划那样预先未知环境的模型动态。 我们研究了蒙特卡洛预测方法,该方法用于预测值函数,而控制方法用于进一步优化值函数。 但是蒙特卡洛方法存在一些陷阱。 它仅适用于情景任务。 如果剧集很长,那么我们必须等待很长时间才能计算值函数。 因此,我们将使用另一种有趣的算法,称为**时差****TD**)学习,这是一种无模型的学习算法:不需要事先知道模型动态,它也可以用于非临时性任务。
W
wizardforcel 已提交
4 5 6 7 8

在本章中,您将学习:

*   TD 学习
*   Q 学习
W
wizardforcel 已提交
9 10
*   SARSA
*   使用 Q 学习和 SARSA 调度出租车
W
wizardforcel 已提交
11 12 13 14
*   Q 学习和 SARSA 之间的区别

# TD 学习

W
wizardforcel 已提交
15
TD 学习算法由 Sutton 于 1988 年提出。该算法兼顾了蒙特卡洛方法和**动态规划****DP**)的优点。 像蒙特卡洛方法一样,它不需要模型动态,而像 DP 一样,它不需要等到剧集结束就可以估计值函数。 取而代之的是,它基于先前学习的估计值来估计当前估计值,这也称为自举。 如果您在蒙特卡洛方法中看到没有引导程序,那么我们仅在剧集结束时进行估计,但在 TD 方法中我们可以进行引导。
W
wizardforcel 已提交
16 17 18 19 20 21 22

# TD 预测

就像我们在蒙特卡洛预测中所做的一样,在 TD 预测中,我们尝试预测状态值。 在蒙特卡洛预测中,我们仅通过取均值收益来估计值函数。 但是在 TD 学习中,我们通过当前状态更新先前状态的值。 我们应该怎么做? TD 学习使用一种称为 TD 更新规则的东西来更新状态值,如下所示:

![](img/00111.jpeg)

W
wizardforcel 已提交
23 24 25
```
先前状态的值 = 先前状态的值 + 学习率(奖励 + 折扣因子(当前状态的值)- 先前状态的值)
```
W
wizardforcel 已提交
26 27 28

这个方程实际上是什么意思?

W
wizardforcel 已提交
29
如果您直观地想到此方程,则实际上是实际奖励(`r + γV(s')`)和预期奖励(`V(s)`)之间的差乘以学习率`α`。 学习率代表什么? 学习率(也称为步长)对于收敛很有用。
W
wizardforcel 已提交
30

W
wizardforcel 已提交
31
你注意到了吗? 由于我们将实际值和预测值之差作为`r + γV(s') - V(s)`,因此实际上是一个误差。 我们可以称其为 TD 误差。 在多次迭代中,我们将尝试最小化此误差。
W
wizardforcel 已提交
32

W
wizardforcel 已提交
33
让我们通过前面几章中的冰湖示例来了解 TD 预测。 接下来显示的是冰冻的湖泊环境。 首先,对于所有状态,我们将值函数初始化为`0`,就像在`V(S)`中将其初始化为`0`一样,如以下状态值图所示 :
W
wizardforcel 已提交
34 35 36

![](img/00115.jpeg)

W
wizardforcel 已提交
37
假设我们处于`s = (1, 1)`的初始状态,我们将采取正确的操作并移至下一个状态`s' = (1, 2)`,并获得 -0.3 的奖励(`r`)。 我们如何使用此信息来更新状态的值?
W
wizardforcel 已提交
38 39 40 41 42

回忆一下 TD 更新公式:

![](img/00116.jpeg)

W
wizardforcel 已提交
43
让我们将学习率(`α`)视为`0.1`,将折扣率(`γ`)视为 0.5; 我们知道状态`(1, 1)`的值(如`V(S)`中的值)为 0,而下一个状态`(1, 2)`的值与`V(S)`一样,也是`0`。 我们获得的奖励(`r`)为 -0.3。 我们将其替换为 TD 规则,如下所示:
W
wizardforcel 已提交
44

W
wizardforcel 已提交
45 46 47 48
```
V(s) = 0 + 0.1 * (-0.3 + 0.5 (0) - 0)
V(s) = -0.03
```
W
wizardforcel 已提交
49

W
wizardforcel 已提交
50
因此,我们在值表中将状态`(1, 1)`的值更新为`-0.03`,如下图所示:
W
wizardforcel 已提交
51 52 53

![](img/00118.jpeg)

W
wizardforcel 已提交
54
现在我们以`(1, 2)`的状态处于`s`的状态,我们将采取正确的操作并移至下一个状态`s' = (1, 3)`并获得奖励`r = -0.3`。 我们现在如何更新状态`(1, 2)`的值?
W
wizardforcel 已提交
55 56 57

像我们之前所做的那样,我们将 TD 更新方程中的值替换为:

W
wizardforcel 已提交
58 59 60 61
```
V(s) = 0 + 0.1 * (-0.3 + 0.5(0) - 0)
V(s) = -0.03
```
W
wizardforcel 已提交
62

W
wizardforcel 已提交
63
因此,我们将状态`(1, 2)`的值设置为`-0.03`,并在值表中对其进行更新,如下所示:
W
wizardforcel 已提交
64 65 66

![](img/00119.jpeg)

W
wizardforcel 已提交
67
现在我们处于`s = (1, 3)`状态; 假设我们要采取行动了。 我们再次回到该状态`s' = (1, 2)`,我们将获得奖励`r = -0.3`。 此处,状态`(1, 3)`的值为`0`,下一个状态`(1, 2)`的值为值表中的`-0.03`
W
wizardforcel 已提交
68

W
wizardforcel 已提交
69
现在我们可以更新状态`(1, 3)`的值,如下所示:
W
wizardforcel 已提交
70

W
wizardforcel 已提交
71 72
```
V(s) = 0 + 0.1 * (-0.3 + 0.5 * (-0.03) - 0))
W
wizardforcel 已提交
73

W
wizardforcel 已提交
74
V(s) = 0.1 * -0.315
W
wizardforcel 已提交
75

W
wizardforcel 已提交
76 77
V(s) = -0.0315
```
W
wizardforcel 已提交
78

W
wizardforcel 已提交
79
因此,我们在值表中将状态`(1, 3)`的值更新为`-0.0315`,如下所示:
W
wizardforcel 已提交
80 81 82 83 84

![](img/00120.jpeg)

以类似的方式,我们使用 TD 更新规则更新所有状态的值。 TD 预测算法涉及的步骤如下:

W
wizardforcel 已提交
85
1.  首先,我们将`V(S)`初始化为`0`或一些任意值
W
wizardforcel 已提交
86
2.  然后我们开始该剧集,并在剧集中的每个步骤中,在状态`S`中执行动作`A`,并获得奖励`R`,然后移至下一个状态`s'`
W
wizardforcel 已提交
87
3.  现在,我们使用 TD 更新规则更新先前状态的值
W
wizardforcel 已提交
88
4.  重复步骤`3``4`,直到达到最终状态
W
wizardforcel 已提交
89 90 91

# TD 控制

W
wizardforcel 已提交
92
在 TD 预测中,我们估计了值函数。 在 TD 控制中,我们优化了值函数。 对于 TD 控制,我们使用两种控制算法:
W
wizardforcel 已提交
93

W
wizardforcel 已提交
94
*   **无策略学习算法**:Q 学习
W
wizardforcel 已提交
95 96 97 98
*   **策略学习算法**:SARSA

# Q 学习

W
wizardforcel 已提交
99
现在,我们将研究称为 Q 学习的非常流行的非策略性 TD 控制算法。 Q 学习是一种非常简单且广泛使用的 TD 算法。 在控制算法中,我们不在乎状态值。 在这里,在 Q 学习中,我们关心的是状态-动作值对-在状态`S`下执行动作`A`的效果。
W
wizardforcel 已提交
100

W
wizardforcel 已提交
101
我们将根据以下公式更新`Q`值:
W
wizardforcel 已提交
102 103 104 105 106

![](img/00121.jpeg)

前面的公式与 TD 预测更新规则相似,只是有一点点差异。 我们将逐步详细介绍这一点。 Q 学习涉及的步骤如下:

W
wizardforcel 已提交
107
1.  首先,我们将`Q`函数初始化为一些任意值
W
wizardforcel 已提交
108
2.  我们使用`ε`贪婪策略(`ε > 0`)从某个状态采取了一项行动,并将其移至新的状态
W
wizardforcel 已提交
109
3.  我们通过遵循更新规则来更新先前状态的`Q`值:
W
wizardforcel 已提交
110 111 112

![](img/00123.jpeg)

W
wizardforcel 已提交
113
4.  重复步骤`2``3`,直到达到最终状态
W
wizardforcel 已提交
114 115 116

现在,我们将使用不同的步骤来理解算法。

W
wizardforcel 已提交
117
考虑相同的冻湖示例。 假设我们处于状态`(3, 2)`,并且有两个动作(左和右)。 现在让我们参考该图,并将其与`ε`贪婪策略进行比较:
W
wizardforcel 已提交
118 119 120

![](img/00124.jpeg)

W
wizardforcel 已提交
121
在“Q 学习”中,我们使用`ε`贪婪策略选择一个动作。 我们要么探索概率为ε的新动作,要么选择概率为`1ε`的最佳动作。 假设我们选择一个概率`ε`,并探索一个新的动作**向下**,然后选择该动作:
W
wizardforcel 已提交
122 123 124

![](img/00125.jpeg)

W
wizardforcel 已提交
125
现在,我们已经对状态`(3, 2)`执行了向下操作,并使用`ε`贪婪策略达到了新状态`(4, 2)`,我们如何使用我们的更新规则来更新先前状态`(3, 2)`的值? 这很简单。 查看`Q`表,如下所示:
W
wizardforcel 已提交
126 127 128

![](img/00126.jpeg)

W
wizardforcel 已提交
129
让我们将`alpha`视为`0.1`,并将折扣因子视为`1`
W
wizardforcel 已提交
130 131 132

![](img/00127.jpeg)

W
wizardforcel 已提交
133 134 135
```
Q( (3,2) down) = Q( (3,2), down ) + 0.1 ( 0.3 + 1 max [Q( (4,2) action) ]- Q( (3,2), down)
```
W
wizardforcel 已提交
136

W
wizardforcel 已提交
137
我们可以说具有向下作用的状态`(3, 2)`的值,例如`Q((3, 2), down)`的值为`Q`表中的`0.8`
W
wizardforcel 已提交
138

W
wizardforcel 已提交
139
状态`(4, 2)`的最大值`Q((4, 2), op)`是什么? 我们仅研究了三个动作(**向上****向下****向右**),因此我们将仅基于这些动作来获取最大值。 (此处,我们将不执行`epsilon`贪婪策略;我们仅选择具有最大值的操作。)
W
wizardforcel 已提交
140

W
wizardforcel 已提交
141
因此,基于先前的`Q`表,我们可以将值替换为:
W
wizardforcel 已提交
142

W
wizardforcel 已提交
143 144 145 146 147
```
Q( (3,2), down) = 0.8 + 0.1 ( 0.3 + 1 max [0.3, 0.5, 0.8] - 0.8 )
    = 0.8 + 0.1 ( 0.3 + 1 (0.8) - 0.8)
    =  0.83
```
W
wizardforcel 已提交
148

W
wizardforcel 已提交
149
因此,我们将`Q((3, 2), down)`的值更新为`0.83`
W
wizardforcel 已提交
150

W
wizardforcel 已提交
151
请记住,在选择要采取的操作时,我们将执行`ε`贪婪策略:我们要么探索具有概率`epsilon`的新操作,要么采取具有最大值的概率 1 `epsilon`。 在更新 Q 值时,我们不执行`ε`贪婪策略,我们仅选择具有最大值的操作。
W
wizardforcel 已提交
152

W
wizardforcel 已提交
153
现在我们处于状态`(4, 2)`,我们必须执行一个动作。 我们应该执行什么动作? 我们决定基于`ε`贪婪策略,要么探索具有概率`epsilon`的新操作,要么选择具有概率 *1-epsilon* 的最佳操作。 假设我们选择概率`1-ε`,然后选择最佳操作。 因此,在`(4, 2)`中,向右的操作具有最大值。 因此,我们将选择**向右**操作:
W
wizardforcel 已提交
154 155 156

![](img/00128.jpeg)

W
wizardforcel 已提交
157
现在我们处于状态`(4, 3)`,因为我们对状态`(4, 2)`采取了**向右**动作。 我们如何更新先前状态的值? 像这样:
W
wizardforcel 已提交
158

W
wizardforcel 已提交
159 160 161
```
Q( (4,2), right) = Q( (4,2), right ) + 0.1 ( 0.3 + 1 max [Q( (4,3) action) ]- Q( (4,2), right)
```
W
wizardforcel 已提交
162

W
wizardforcel 已提交
163
如果您查看下面的`Q`表,对于状态`(4, 3)`,我们仅探讨了两个操作(**向上****向下**),因此我们仅根据这些操作得出最大值。 (这里,我们将不执行`ε`贪婪策略;我们只选择具有最大值的操作):
W
wizardforcel 已提交
164

W
wizardforcel 已提交
165 166
```
Q ( (4,2), right) = Q((4,2),right) + 0.1 (0.3 + 1 max [ (Q (4,3), up) , ( Q(4,3),down) ] - Q ((4,2), right )
W
wizardforcel 已提交
167

W
wizardforcel 已提交
168 169 170 171
Q ( (4,2), right) = 0.8 + 0.1 (0.3 + 1 max [ 0.1,0.3] - 0.8)
    = 0.8 + 0.1 (0.3 + 1(0.3) - 0.8)
    = 0.78
```
W
wizardforcel 已提交
172

W
wizardforcel 已提交
173
查看下面的`Q`表:
W
wizardforcel 已提交
174 175 176

![](img/00129.jpeg)

W
wizardforcel 已提交
177
现在我们将状态`Q((4,2), right)`的值更新为`0.78`
W
wizardforcel 已提交
178

W
wizardforcel 已提交
179
因此,这就是我们在 Q 学习中获得状态作用值的方式。 为了决定采取什么行动,我们使用`ε`贪婪策略,并在更新`Q`值时,我们只选择最大的行动; 这是流程图:
W
wizardforcel 已提交
180 181 182 183 184

![](img/00130.gif)

# 使用 Q 学习解决出租车问题

W
wizardforcel 已提交
185
为了演示该问题,我们假设智能体是驱动程序。 有四个地点,智能体必须在一个地点接客并在另一地点下车。 智能体将获得 +20 积分作为成功下车的奖励,而每走一步便获得 -1 积分。 该智能体还将因非法取送丢掉 -10 分。 因此,我们智能体的目标是学会在短时间内在正确的位置上落客而不增加非法乘客。
W
wizardforcel 已提交
186

W
wizardforcel 已提交
187
这里显示的环境中,字母(`R``G``Y``B`)代表不同的位置,并且一个小矩形是驾驶出租车的智能体:
W
wizardforcel 已提交
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226

![](img/00131.gif)

让我们看一下编码部分:

```py
import gym
import random
```

现在,我们使用`gym`创建环境:

```py
env = gym.make("Taxi-v1")
```

这种出租车的环境如何? 像这样:

```py
env.render()
```

好的,首先让我们初始化学习率`alpha``epsilon`值和`gamma`

```py
alpha = 0.4
gamma = 0.999
epsilon = 0.017
```

然后我们初始化一个 Q 表; 它有一个字典,将状态-操作值对存储为(状态,操作):

```py
q = {}
for s in range(env.observation_space.n):
    for a in range(env.action_space.n):
        q[(s,a)] = 0.0
```

W
wizardforcel 已提交
227
我们将通过 Q 学习更新规则定义用于更新 Q 表的函数; 如果您看下面的函数,您将看到我们采取的状态/动作对具有最大值的动作并将其存储在`qa`变量中。 然后,我们通过更新规则更新先前状态的`Q`值,如下所示:
W
wizardforcel 已提交
228 229 230 231 232 233 234 235 236

![](img/00132.jpeg)

```py
def update_q_table(prev_state, action, reward, nextstate, alpha, gamma):
    qa = max([q[(nextstate, a)] for a in range(env.action_space.n)])
    q[(prev_state,action)] += alpha * (reward + gamma * qa -q[(prev_state,action)])
```

W
wizardforcel 已提交
237
然后,我们定义一个函数以执行`ε`贪婪策略,并在其中传递状态和`epsilon`值。 我们生成一些均匀分布的随机数,如果该数小于`epsilon`,则在状态中探索不同的动作,否则我们将利用具有最大 q 值的动作:
W
wizardforcel 已提交
238 239 240 241 242 243 244 245 246 247

```py

def epsilon_greedy_policy(state, epsilon):
    if random.uniform(0,1) < epsilon:
        return env.action_space.sample()
    else:
        return max(list(range(env.action_space.n)), key = lambda x: q[(state,x)])
```

W
wizardforcel 已提交
248
我们将结合所有这些函数,了解如何进行 Q 学习:
W
wizardforcel 已提交
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321

```py
# For each episode
for i in range(8000):

    r = 0
    #first we initialize the environment

    prev_state = env.reset()
    while True:

        #In each state we select action by epsilon greedy policy
        action = epsilon_greedy_policy(prev_state, epsilon)

        #then we take the selected action and move to the next state
        nextstate, reward, done, _ = env.step(action)

        #and we update the q value using the update_q_table() function 
        #which updates q table according to our update rule.

        update_q_table(prev_state, action, reward, nextstate, alpha, gamma)

        #then we update the previous state as next stat
        prev_state = nextstate

        #and store the rewards in r
        r += reward

        #If done i.e if we reached the terminal state of the episode 
        #if break the loop and start the next episode
        if done:
            break

    print("total reward: ", r)

env.close()
```

完整的代码在这里给出:

```py

import random
import gym

env = gym.make('Taxi-v1')

alpha = 0.4
gamma = 0.999
epsilon = 0.017

q = {}
for s in range(env.observation_space.n):
 for a in range(env.action_space.n):
 q[(s,a)] = 0

def update_q_table(prev_state, action, reward, nextstate, alpha, gamma):
 qa = max([q[(nextstate, a)] for a in range(env.action_space.n)])
 q[(prev_state,action)] += alpha * (reward + gamma * qa - q[(prev_state,action)])

def epsilon_greedy_policy(state, epsilon):
 if random.uniform(0,1) < epsilon:
 return env.action_space.sample()
 else:
 return max(list(range(env.action_space.n)), key = lambda x: q[(state,x)])

for i in range(8000):
    r = 0
    prev_state = env.reset()    
    while True:

        env.render()

W
wizardforcel 已提交
322
        # In each state, we select the action by ε-greedy policy
W
wizardforcel 已提交
323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349
        action = epsilon_greedy_policy(prev_state, epsilon)

        # then we perform the action and move to the next state, and 
        # receive the reward
        nextstate, reward, done, _ = env.step(action)

        # Next we update the Q value using our update_q_table function
        # which updates the Q value by Q learning update rule

        update_q_table(prev_state, action, reward, nextstate, alpha, gamma)

        # Finally we update the previous state as next state
        prev_state = nextstate

        # Store all the rewards obtained
        r += reward

        #we will break the loop, if we are at the terminal 
        #state of the episode
        if done:
            break

    print("total reward: ", r)

env.close()
```

W
wizardforcel 已提交
350
# SARSA
W
wizardforcel 已提交
351

W
wizardforcel 已提交
352
**状态-动作-奖励-状态-动作****SARSA**)是一种策略上的 TD 控制算法。 就像我们在 Q 学习中所做的一样,这里我们也关注状态-动作值,而不是状态-值对。 在 SARSA 中,我们根据以下更新规则更新 Q 值:
W
wizardforcel 已提交
353 354 355

![](img/00133.jpeg)

W
wizardforcel 已提交
356
在前面的等式中,您可能会注意到,没有最大的`Q(s', a')`,就像在 Q 学习中一样。 这里只是`Q(s', a')`。 我们可以通过执行一些步骤来详细了解这一点。 SARSA 涉及的步骤如下:
W
wizardforcel 已提交
357

W
wizardforcel 已提交
358
1.  首先,我们将`Q`值初始化为一些任意值
W
wizardforcel 已提交
359 360
2.  我们通过`ε`贪婪策略(`ε > 0`)选择一个动作,然后从一种状态转移到另一种状态
3.  我们遵循更新规则`Q(s, a) = Q(s, a) + α(r + γQ(s', a') - Q(s, a))`来更新`Q`值的先前状态,其中`a'`是由`ε`贪婪策略(`ε > 0`)选择的操作
W
wizardforcel 已提交
361

W
wizardforcel 已提交
362
现在,我们将逐步了解算法。 让我们考虑相同的冰冻湖的例子。 假设我们处于`(4, 2)`状态。 我们根据`ε`贪婪策略决定采取的措施。 假设我们使用概率为 1 `epsilon`并选择最佳操作,即**向右**
W
wizardforcel 已提交
363 364 365

![](img/00137.jpeg)

W
wizardforcel 已提交
366
现在,我们在状态`(4, 2)`下执行了**向右**动作之后,就处于`(4, 3)`状态。 我们如何更新先前状态`(4, 2)`的值? 让我们将`alpha`设为`0.1`,将奖励设为`0.3`和折扣系数`1`
W
wizardforcel 已提交
367 368 369

![](img/00138.jpeg)

W
wizardforcel 已提交
370 371 372
```
Q( (4,2), right) = Q( (4,2),right) + 0.1 ( 0.3 + 1 Q( (4,3), action)) - Q((4,2) , right)
```
W
wizardforcel 已提交
373

W
wizardforcel 已提交
374
我们如何选择`Q((4, 3), action)`的值? 在这里,与 Q 学习不同,我们不只是获取`max Q((4, 3), action)`。 在 SARSA 中,我们使用`ε`贪婪策略。
W
wizardforcel 已提交
375

W
wizardforcel 已提交
376
查看下面的 Q 表。 在状态`(4, 3)`中,我们探索了两个动作。 与 Q 学习不同,我们不会直接选择最大动作:
W
wizardforcel 已提交
377 378 379

![](img/00139.jpeg)

W
wizardforcel 已提交
380
我们在这里也遵循`ε`贪婪策略。 我们要么以概率`epsilon`进行探索,要么以概率 1 `epsilon`进行利用。 假设我们选择概率`ε`并探索新的动作。 我们探索一个新动作**向右**,然后选择该动作:
W
wizardforcel 已提交
381 382 383

![](img/00140.jpeg)

W
wizardforcel 已提交
384 385
```
Q ( (4,2), right) = Q((4,2),right) + 0.1 (0.3 + 1 (Q (4,3), right) - Q ((4,2), right )
W
wizardforcel 已提交
386

W
wizardforcel 已提交
387 388 389 390
Q ( (4,2), right) = 0.8 + 0.1 (0.3 + 1(0.9) - 0.8)
    = 0.8 + 0.1 (0.3 + 1(0.9) - 0.8)
    = 0.84
```
W
wizardforcel 已提交
391

W
wizardforcel 已提交
392
因此,这就是我们在 SARSA 中获取状态操作值的方式。 我们使用`ε`贪婪策略采取措施,并且在更新 Q 值的同时,我们使用`ε`贪婪策略采取措施。
W
wizardforcel 已提交
393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421

下图说明了 SARSA 算法:

![](img/00141.gif)

# 使用 SARSA 解决出租车问题

现在,我们将使用 SARSA 解决相同的出租车问题:

```py
import gym
import random
env = gym.make('Taxi-v1')
```

另外,我们将初始化学习率`gamma``epsilon`。 Q 表有一个字典:

```py

alpha = 0.85
gamma = 0.90
epsilon = 0.8

Q = {}
for s in range(env.observation_space.n):
    for a in range(env.action_space.n):
        Q[(s,a)] = 0.0
```

W
wizardforcel 已提交
422
和往常一样,我们为探索定义了`epsilon_greedy`策略:
W
wizardforcel 已提交
423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547

```py
def epsilon_greedy(state, epsilon):
    if random.uniform(0,1) < epsilon:
        return env.action_space.sample()
    else:
        return max(list(range(env.action_space.n)), key = lambda x: Q[(state,x)])
```

现在,出现了实际的 SARSA 算法:

```py
for i in range(4000):

    #We store cumulative reward of each episodes in r
    r = 0

    #Then for every iterations, we initialize the state,
    state = env.reset()

    #then we pick up the action using epsilon greedy policy
    action = epsilon_greedy(state,epsilon)

    while True:

        #Then we perform the action in the state and move the next state
        nextstate, reward, done, _ = env.step(action)

        #Then we pick up the next action using epsilon greedy policy 
        nextaction = epsilon_greedy(nextstate,epsilon) 

        #we calculate Q value of the previous state using our update rule
        Q[(state,action)] += alpha * (reward + gamma * Q[(nextstate,nextaction)]-Q[(state,action)])

```

```py
        #finally we update our state and action with next action 
        # and next state
        action = nextaction
        state = nextstate
        r += reward

        #we will break the loop, if we are at the terminal 
        #state of the episode
        if done:
            break

env.close()
```

您可以运行该程序,然后查看 SARSA 如何找到最佳路径。

完整的程序在这里给出:

```py
#Like we did in Q learning, we import necessary libraries and initialize environment

import gym
import random
env = gym.make('Taxi-v1')

alpha = 0.85
gamma = 0.90
epsilon = 0.8

#Then we initialize Q table as dictionary for storing the state-action values
Q = {}
for s in range(env.observation_space.n):
    for a in range(env.action_space.n):
        Q[(s,a)] = 0.0

#Now, we define a function called epsilon_greedy for performing action 
#according epsilon greedy policy 
def epsilon_greedy(state, epsilon):
    if random.uniform(0,1) < epsilon:
        return env.action_space.sample()
    else:
        return max(list(range(env.action_space.n)), key = lambda x: Q[(state,x)])

```

```py
for i in range(4000):

    #We store cumulative reward of each episodes in 
    r = 0

    #Then for every iterations, we initialize the state,
    state = env.reset()

    #then we pick up the action using epsilon greedy policy
    action = epsilon_greedy(state,epsilon)

    while True:

        #Then we perform the action in the state and move the next state
        nextstate, reward, done, _ = env.step(action)

        #Then we pick up the next action using epsilon greedy policy 
        nextaction = epsilon_greedy(nextstate,epsilon) 

        #we calculate Q value of the previous state using our update rule
        Q[(state,action)] += alpha * (reward + gamma * Q[(nextstate,nextaction)]-Q[(state,action)])

        #finally we update our state and action with next action 
        #and next state
        action = nextaction
        state = nextstate
        r += reward

        #we will break the loop, if we are at the terminal 
        #state of the episode
        if done:
            break

env.close()
```

# Q 学习和 SARSA 之间的区别

Q 学习和 SARSA 对许多人来说总是很困惑。 让我们分解一下两者之间的差异。 在此处查看流程图:

![](img/00142.gif)

W
wizardforcel 已提交
548
您看得出来差别吗? 在 Q 学习中,我们使用`ε`贪婪策略采取行动,并且在更新 Q 值的同时,我们仅采取最大行动。 在 SARSA 中,我们使用`ε`贪婪策略采取措施,并且在更新 Q 值的同时,我们使用`ε`贪婪策略采取措施。
W
wizardforcel 已提交
549

W
wizardforcel 已提交
550
# 总结
W
wizardforcel 已提交
551 552 553 554 555 556 557 558

在本章中,我们学习了一种克服了蒙特卡洛方法局限性的不同的无模型学习算法。 我们看到了预测和控制方法。 在 TD 预测中,我们根据下一个状态更新了状态的状态值。 在控制方法方面,我们看到了两种不同的算法:Q 学习和 SARSA。

# 问题

问题列表如下:

1.  TD 学习与蒙特卡洛方法有何不同?
W
wizardforcel 已提交
559
2.  TD 误差到底是什么?
W
wizardforcel 已提交
560
3.  TD 预测和控制之间有什么区别?
W
wizardforcel 已提交
561
4.  如何使用 Q 学习构建智能体?
W
wizardforcel 已提交
562
5.  Q 学习和 SARSA 有什么区别?
W
wizardforcel 已提交
563 564 565

# 进一步阅读

W
wizardforcel 已提交
566
[**萨顿的原始 TD 论文**](https://pdfs.semanticscholar.org/9c06/865e912788a6a51470724e087853d7269195.pdf)