今天介绍的Sarsa(lambda)算法是Sarsa的改进版,二者的主要区别在于:
其实lambda=0和lambda=1就是单步更新和回合更新的区别,接下来我们来举两个例子来说明回合更新的优势在哪里。
我们以机器人找宝藏为例子说明。
同样是机器人找宝藏。
这是针对于一个state-action值按精力次数的变化。最上面是经历state-action的时间点,第二张图是使用这种方式所带来的"不可或缺性值":
self.eligibility_trace.ix[s, a] += 1
而第三张图是使用下面这种方法带来的"不可或缺性值":
self.eligibility_trace.ix[s, :] *= 0; self.eligibility_trace.ix[s, a] = 1
第一种的更新方式会有一些干扰,在试验中第二种更新方式也确实效果更好,所以下面的实战会采取第二种的方式。
我们还是用上次的上天堂的例子来实战。
使用SarsaLambdaTable
在算法更新迭代的部分,是和之前的SarsaTable
一样的,所以本次就只阐述思维决策的部分。
1class SarsaLambdaTable:
2 # 初始化 (有改变)
3 def __init__(self, actions, learning_rate=0.01, reward_decay=0.9, e_greedy=0.9, trace_decay=0.9):
4
5 # 选行为 (与之前一样)
6 def choose_action(self, observation):
7
8 # 学习更新参数 (有改变)
9 def learn(self, s, a, r, s_):
10
11 # 检测 state 是否存在 (有改变)
12 def check_state_exist(self, state):
和上次一样,我们选择继承的方式,将SarsaLambdaTable
继承到RL
,所以我们将之前的_init_
,check_state_exist
,choose_action
,learn
全部放到这个主结构,之后再作具体修改。
在预设值中,我们添加了trace_decay=0.9
这个就是lambda
的值。这个值会使得拿到reward的每一步都有价值。
1class SarsaLambdaTable(RL):
2 def __init__(self, actions, learning_rate=0.01, reward_decay=0.9, e_greedy=0.9, trace_decay=0.9):
3 super(SarsaLambdaTable, self).__init__(actions, learning_rate, reward_decay, e_greedy)
4
5 # backward view算法,eligibility trace
6 self.lambda_ = trace_decay
7 self.eligibility_trace = self.q_table.copy()#空的eligibility trace表
这里和之前唯一的不同就是考虑了eligibility_trace
1 def check_state_exist(self, state):
2 if state not in self.q_table.index:
3 # append new state to q table
4 to_be_append = pd.Series(
5 [0] * len(self.actions),
6 index=self.q_table.columns,
7 name=state,
8 )
9 self.q_table = self.q_table.append(to_be_append)
10
11 # 同样需要更新eligibility_trace
12 self.eligibility_trace = self.eligibility_trace.append(to_be_append)
1 def learn(self, s, a, r, s_, a_):
2 self.check_state_exist(s_)
3 q_predict = self.q_table.loc[s, a]
4 if s_ != 'terminal':
5 q_target = r + self.gamma * self.q_table.loc[s_, a_] # next state is not terminal
6 else:
7 q_target = r # next state is terminal
8 error = q_target - q_predict
9
10 # 对于经历过的state-action,我们让他+1,证明他是得到reward途中不可或缺的一环
11
12 # Method 1:
13 # self.eligibility_trace.loc[s, a] += 1
14
15 # Method 2:
16 self.eligibility_trace.loc[s, :] *= 0
17 self.eligibility_trace.loc[s, a] = 1
18
19 # Q表更新
20 self.q_table += self.lr * error * self.eligibility_trace
21
22 # 随着时间衰减eligibility_trace的值,离获取reward越远的步,他的"不可或缺性"越小
23 self.eligibility_trace *= self.gamma*self.lambda_
从结果上看,Sarsa(Lambda)由于多了一张eligibility_trace表,那么就有了探索轨迹的记录,且此轨迹对Q_table的value产生了正面或者负面的影响,所以Sarsa(lambda)比Sarsa能更快地学会完成任务,缺点是:由于学得快,但不一定学得精,而且非常容易思维僵化,很喜欢用固定的action完成任务。使用文中的第二种更新方式可以缓解他固执情绪的积累速度,比较好。