【问题标题】:prioritized experience replay in deep Q-learning深度 Q 学习中的优先经验回放
【发布时间】:2017-12-22 23:33:09
【问题描述】:

我在 openai 健身房的mountain car problem 中实施 DQN。这个问题很特殊,因为正奖励非常稀少。所以我想按照paper by google deep mind 中的建议实施优先体验回放。

有些事情让我感到困惑:

  • 我们如何存储回放内存。我知道 pi 是转换的优先级,有两种方法,但是这个 P(i) 是什么?
  • 如果我们遵循给定的规则,P(i) 不会在每次添加样本时发生变化。
  • 当它说“我们根据这个概率分布进行采样”是什么意思。分布是什么。
  • 最后我们如何从中采样。我知道如果我们将其存储在优先级队列中,我们可以直接采样,但实际上我们将其存储在求和树中。

提前致谢

【问题讨论】:

    标签: deep-learning priority-queue reinforcement-learning q-learning


    【解决方案1】:
    • 根据论文,计算 Pi 有两种方法,根据您的选择,您的实现会有所不同。我假设您选择了比例优先级,那么您应该使用“和树”数据结构来存储一对转换和 P(i)。 P(i) 只是 Pi 的标准化版本,它显示了转换的重要性,或者换句话说,转换对于改善网络的有效性。当 P(i) 很高时,这意味着它对网络来说非常令人惊讶,因此它可以真正帮助网络进行自我调整。
    • 您应该添加具有无限优先级的每个新过渡,以确保它至少会播放一次,并且无需为每个即将到来的新过渡更新所有体验重播内存。在体验回放过程中,您选择一个小批量并更新小批量中这些体验的概率。
    • 每个体验都有一个概率,因此所有体验共同构成一个分布,我们根据该分布选择下一个小批量。
    • 您可以通过此策略从您的 sum-tree 中采样:
    def retrieve(n, s):
        if n is leaf_node: return n
        if n.left.val >= s: return retrieve(n.left, s)
        else: return retrieve(n.right, s - n.left.val)
    

    我已从here 获取代码。

    【讨论】:

    • 仍然没有得到它。批量大小不会根据 s.使用优先级队列也不是一个更好的主意
    • 我们为每个样本调用检索函数。我的意思是,如果您有一个大小为 32 的小批量,那么您应该调用该函数 32 次。堆不适合,因为这在每个步骤中为您提供了最大的概率,并且没有机会选择其他体验,但使用 sum-tree 所有体验都有机会被选择,并且它们也可以有效地更新。
    • 谢谢。我成功地理解并实施了它。最后一件事,我们是否使用求和树来引入一点随机性,否则我无法看到优先级队列有多好
    • 堆的主要用途是在一些值中选择最大值或最小值。在这个领域,我们想根据它们的概率随机选择一些数字。我们不想选择概率最高的经验,所以堆没有太大帮助。
    • @SajadNorouzi 当您说“无限优先”时,您是指一个非常大的数字吗?这个数字的大小有关系吗?
    【解决方案2】:

    您可以重复使用OpenAI Baseline 中的代码或使用SumTree

    import numpy as np
    import random
    
    from baselines.common.segment_tree import SumSegmentTree, MinSegmentTree
    
    
    class ReplayBuffer(object):
        def __init__(self, size):
            """Create Replay buffer.
            Parameters
            ----------
            size: int
                Max number of transitions to store in the buffer. When the buffer
                overflows the old memories are dropped.
            """
            self._storage = []
            self._maxsize = size
            self._next_idx = 0
    
        def __len__(self):
            return len(self._storage)
    
        def add(self, obs_t, action, reward, obs_tp1, done):
            data = (obs_t, action, reward, obs_tp1, done)
    
            if self._next_idx >= len(self._storage):
                self._storage.append(data)
            else:
                self._storage[self._next_idx] = data
            self._next_idx = (self._next_idx + 1) % self._maxsize
    
        def _encode_sample(self, idxes):
            obses_t, actions, rewards, obses_tp1, dones = [], [], [], [], []
            for i in idxes:
                data = self._storage[i]
                obs_t, action, reward, obs_tp1, done = data
                obses_t.append(np.array(obs_t, copy=False))
                actions.append(np.array(action, copy=False))
                rewards.append(reward)
                obses_tp1.append(np.array(obs_tp1, copy=False))
                dones.append(done)
            return np.array(obses_t), np.array(actions), np.array(rewards), np.array(obses_tp1), np.array(dones)
    
        def sample(self, batch_size):
            """Sample a batch of experiences.
            Parameters
            ----------
            batch_size: int
                How many transitions to sample.
            Returns
            -------
            obs_batch: np.array
                batch of observations
            act_batch: np.array
                batch of actions executed given obs_batch
            rew_batch: np.array
                rewards received as results of executing act_batch
            next_obs_batch: np.array
                next set of observations seen after executing act_batch
            done_mask: np.array
                done_mask[i] = 1 if executing act_batch[i] resulted in
                the end of an episode and 0 otherwise.
            """
            idxes = [random.randint(0, len(self._storage) - 1) for _ in range(batch_size)]
            return self._encode_sample(idxes)
    
    
    class PrioritizedReplayBuffer(ReplayBuffer):
        def __init__(self, size, alpha):
            """Create Prioritized Replay buffer.
            Parameters
            ----------
            size: int
                Max number of transitions to store in the buffer. When the buffer
                overflows the old memories are dropped.
            alpha: float
                how much prioritization is used
                (0 - no prioritization, 1 - full prioritization)
            See Also
            --------
            ReplayBuffer.__init__
            """
            super(PrioritizedReplayBuffer, self).__init__(size)
            assert alpha >= 0
            self._alpha = alpha
    
            it_capacity = 1
            while it_capacity < size:
                it_capacity *= 2
    
            self._it_sum = SumSegmentTree(it_capacity)
            self._it_min = MinSegmentTree(it_capacity)
            self._max_priority = 1.0
    
        def add(self, *args, **kwargs):
            """See ReplayBuffer.store_effect"""
            idx = self._next_idx
            super().add(*args, **kwargs)
            self._it_sum[idx] = self._max_priority ** self._alpha
            self._it_min[idx] = self._max_priority ** self._alpha
    
        def _sample_proportional(self, batch_size):
            res = []
            p_total = self._it_sum.sum(0, len(self._storage) - 1)
            every_range_len = p_total / batch_size
            for i in range(batch_size):
                mass = random.random() * every_range_len + i * every_range_len
                idx = self._it_sum.find_prefixsum_idx(mass)
                res.append(idx)
            return res
    
        def sample(self, batch_size, beta):
            """Sample a batch of experiences.
            compared to ReplayBuffer.sample
            it also returns importance weights and idxes
            of sampled experiences.
            Parameters
            ----------
            batch_size: int
                How many transitions to sample.
            beta: float
                To what degree to use importance weights
                (0 - no corrections, 1 - full correction)
            Returns
            -------
            obs_batch: np.array
                batch of observations
            act_batch: np.array
                batch of actions executed given obs_batch
            rew_batch: np.array
                rewards received as results of executing act_batch
            next_obs_batch: np.array
                next set of observations seen after executing act_batch
            done_mask: np.array
                done_mask[i] = 1 if executing act_batch[i] resulted in
                the end of an episode and 0 otherwise.
            weights: np.array
                Array of shape (batch_size,) and dtype np.float32
                denoting importance weight of each sampled transition
            idxes: np.array
                Array of shape (batch_size,) and dtype np.int32
                idexes in buffer of sampled experiences
            """
            assert beta > 0
    
            idxes = self._sample_proportional(batch_size)
    
            weights = []
            p_min = self._it_min.min() / self._it_sum.sum()
            max_weight = (p_min * len(self._storage)) ** (-beta)
    
            for idx in idxes:
                p_sample = self._it_sum[idx] / self._it_sum.sum()
                weight = (p_sample * len(self._storage)) ** (-beta)
                weights.append(weight / max_weight)
            weights = np.array(weights)
            encoded_sample = self._encode_sample(idxes)
            return tuple(list(encoded_sample) + [weights, idxes])
    
        def update_priorities(self, idxes, priorities):
            """Update priorities of sampled transitions.
            sets priority of transition at index idxes[i] in buffer
            to priorities[i].
            Parameters
            ----------
            idxes: [int]
                List of idxes of sampled transitions
            priorities: [float]
                List of updated priorities corresponding to
                transitions at the sampled idxes denoted by
                variable `idxes`.
            """
            assert len(idxes) == len(priorities)
            for idx, priority in zip(idxes, priorities):
                assert priority > 0
                assert 0 <= idx < len(self._storage)
                self._it_sum[idx] = priority ** self._alpha
                self._it_min[idx] = priority ** self._alpha
    
                self._max_priority = max(self._max_priority, priority)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-09-25
      • 2021-08-18
      • 1970-01-01
      • 1970-01-01
      • 2021-01-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多