DQL智能体 Q 学习是一种强化学习算法,除了会考虑来自动作的即时奖励,还会考虑延迟奖励。该算 法归功于 Watkins(1989)以及 Watkins 和 Dayan(1992),并在 Sutton 和 Barto(2018)的 第 6 章中有详细解释。Q 学习解决了神经网络智能体遇到的超越下一个立即奖励的问题。 该算法的工作原理大致如下:有一个动作 – 价值策略 Q,它为每个状态和动作的组合分配 一个值。值越高,从智能体的角度来看动作越好。如果智能体使用策略 Q 选择一个动作, 则它会选择具有最高值的动作。 那么一个动作的价值是如何得出的呢?一个动作的价值由它的直接奖励和下一状态下最优 动作的折现值组成,以下是正式表达。 1 1 ( , ) max ( , ) t t t t a Q S A R γ Q S a = + + + 这里,St 是步骤(时间)t 的状态,At 是状态 St 采取的动作,Rt+1 是动作 At 的直接奖励, 0 < γ < 1 是折扣因子, m 1 ax ( , ) t a Q S a + 是给定当前策略 Q 的最优动作下的最大延迟奖励。强化学习 | 213 在一个只有有限数量的可能状态的简单环境中,Q 可以用一张表格表示,其中列出了每个 状态 – 动作组合的相应值。然而,在更有趣或更复杂的设置中(如 CartPole 环境),状态 数量过多,无法通过穷尽的方式写出 Q,因此,Q 通常被理解为一个函数。 这就是神经网络发挥作用的地方。在现实的设置和环境中,函数 Q 的封闭形式可能不存 在,或者利用动态规划方法很难推导。因此 Q 学习算法通常仅以近似值为目标。神经网络 具有通用逼近能力,是完成 Q 函数逼近的自然选择。 Q 学习的另一个关键要素是重放。DQL 智能体会重放许多经验(状态 – 动作组合)以定期 更新策略函数 Q,这可以大大提高学习效果。此外,下面介绍的 DQL 智能体(DQLAgent) 于学习过程中在探索和利用之间交替。交替会以系统的方式进行,因为智能体仅从探索 开始(一开始它不可能学到任何东西),然后会缓慢但稳定地降低探索率 直到达到最低 水平。3 In [44]: from collections import deque from keras.optimizers import Adam, RMSprop In [45]: class DQLAgent: def __init__(self, gamma=0.95, hu=24, opt=Adam, lr=0.001, finish=False): self.finish = finish self.epsilon = 1.0 ➊ self.epsilon_min = 0.01 ➋ self.epsilon_decay = 0.995 ➌ self.gamma = gamma ➍ self.batch_size = 32 ➎ self.max_treward = 0 self.averages = list() self.memory = deque(maxlen=2000) ➏ self.osn = env.observation_space.shape[0] self.model = self._build_model(hu, opt, lr) def _build_model(self, hu, opt, lr): model = Sequential() model.add(Dense(hu, input_dim=self.osn, activation='relu')) model.add(Dense(hu, activation='relu')) model.add(Dense(env.action_space.n, activation='linear')) model.compile(loss='mse', optimizer=opt(lr=lr)) return model def act(self, state): if random.random() 注 3: 实现类似于博客文章“Deep Q-Learning with Keras and Gym”中的发现。214 | 第 9 章 def replay(self): batch = random.sample(self.memory, self.batch_size) ➐ for state, action, reward, next_state, done in batch: if not done: reward += self.gamma * np.amax( self.model.predict(next_state)[0]) ➑ target = self.model.predict(state) target[0, action] = reward self.model.fit(state, target, epochs=1, verbose=False) ➒ if self.epsilon > self.epsilon_min: self.epsilon *= self.epsilon_decay ➓ def learn(self, episodes): trewards = [] for e in range(1, episodes + 1): state = env.reset() state = np.reshape(state, [1, self.osn]) for _ in range(5000): action = self.act(state) next_state, reward, done, info = env.step(action) next_state = np.reshape(next_state, [1, self.osn]) self.memory.append([state, action, reward, next_state, done]) state = next_state if done: treward = _ + 1 trewards.append(treward) av = sum(trewards[-25:]) / 25 self.averages.append(av) self.max_treward = max(self.max_treward, treward) templ = 'episode: {:4d}/{} | treward: {:4d} | ' templ += 'av: {:6.1f} | max: {:4d}' print(templ.format(e, episodes, treward, av, self.max_treward), end='\r') break if av > 195 and self.finish: break if len(self.memory) > self.batch_size: self.replay() def test(self, episodes): trewards = [] for e in range(1, episodes + 1): state = env.reset() for _ in range(5001): state = np.reshape(state, [1, self.osn]) action = np.argmax(self.model.predict(state)[0]) next_state, reward, done, info = env.step(action) state = next_state强化学习 | 215 if done: treward = _ + 1 trewards.append(treward) print('episode: {:4d}/{} | treward: {:4d}' .format(e, episodes, treward), end='\r') break return trewards ➊ 初始探索率。 ➋ 最小探索率。 ➌ 探索率的衰减率。 ➍ 延迟奖励的折扣因子。 ➎ 重放的批次大小。 ➏ 有限历史的双端队列 deque 集合。 ➐ 随机选择历史批次进行回放。 ➑ 状态 – 动作对的 Q 值。 ➒ 为新的动作 – 价值对更新神经网络。 ➓ 更新探索率。 存储新数据。 根据过去的经验重放以更新策略。 DQL 智能体如何执行?如以下代码所示,它达到了 CartPole 的获胜状态,总奖励为 200。 图 9-2 显示了分数的移动平均线以及它是如何随时间增加的,尽管不是单调增加。相反, 智能体的性能有时会显著下降。除此之外,一直在进行的探索会导致随机操作,这不一定 会导致总奖励方面的良好结果,但可能会为更新策略网络带来有益的经验。 In [46]: episodes = 1000 In [47]: set_seeds(100) agent = DQLAgent(finish=True) In [48]: agent.learn(episodes) episode: 400/1000 | treward: 200 | av: 195.4 | max: 200 In [49]: plt.figure(figsize=(10, 6)) x = range(len(agent.averages)) y = np.polyval(np.polyfit(x, agent.averages, deg=3), x) plt.plot(agent.averages, label='moving average') plt.plot(x, y, 'r--', label='trend') plt.xlabel('episodes') plt.ylabel('total reward') plt.legend();216 | 第 9 章 移动平均线 趋势 总 奖 励 回合 图 9-2:CartPole 的 DQLAgent 平均总奖励 DQL 智能体是否解决了 CartPole 问题?在现有的游戏设置下,考虑到 OpenAI Gym 对成 功的定义,确实解决了。 In [50]: trewards = agent.test(100) episode: 100/100 | treward: 200 In [51]: sum(trewards) / len(trewards) Out[51]: 200.0