【问题标题】:How to deal with different state space size in reinforcement learning?如何处理强化学习中不同的状态空间大小?
【发布时间】:2020-09-03 17:27:14
【问题描述】:

我正在从事 A2C 强化学习,我的环境中代理的数量不断增加和减少。由于代理数量的增加和减少,状态空间也会发生变化。我曾尝试以这种方式解决改变状态空间的问题:

  • 如果状态空间超过选择的最大状态空间 如n_input,多余的状态空间将由 np.random.choice 其中随机选择提供了一种在将状态空间转换为概率后从状态空间创建随机样本的方法。

  • 如果状态空间小于我填充状态的最大状态 带零的空格。

    def get_state_new(state):
     n_features =  n_input-len(get_state(env))
     # print("state",len(get_state(env)))
     p = np.array(state)
     p = np.exp(p)
     if p.sum() != 1.0:
         p = p * (1. / p.sum())
     if len(get_state(env)) > n_input:
         statappend = np.random.choice(state, size=n_input, p=p)
         # print(statappend)
     else:
         statappend = np.zeros(n_input)
         statappend[:state.shape[0]] = state
     return statappend
    

它可以工作,但结果不如预期,我不知道这是否正确。

我的问题

有没有参考论文处理这样的问题以及如何处理状态空间的变化?

【问题讨论】:

    标签: python tensorflow reinforcement-learning


    【解决方案1】:

    对于本文,我将给出与 other post 相同的参考: Benchmarks for reinforcement learning minmixed-autonomy traffic.

    实际上,在这种方法中,预期的代理数量(预期在任何时刻出现在模拟中)是预先确定的。在运行时,然后检索模拟中存在的代理的观察结果并将其压缩到固定大小的容器(张量)中(我们称之为整体观察容器),该容器可以包含尽可能多的观察结果(来自单个代理) 因为在模拟中的任何时候都可能会出现代理。明确一点:size(overall observation container) = expected number of agents * individual observation size。由于模拟中存在的实际代理数量可能因时间步长而异,因此适用以下情况:

    • 如果环境中存在的代理少于预期,因此提供的观测值少于整个观测容器的容量,则使用零填充来填充空的观测槽。
    • 如果代理的数量超过预期的代理数量,则将仅使用所提供的观察值的一个子集。因此,只有从可用代理的随机选择子集中,观察才会被放入固定大小的整体观察容器中。仅对于选定的代理,控制器将计算要执行的操作,而“多余的代理”将在模拟中被视为非受控代理。

    回到您的示例代码,我会做一些不同的事情。

    首先,我想知道为什么你同时拥有变量state(传递给函数get_state_new)和调用get_state(env),因为我希望get_state(env) 返回的信息与存储的信息相同已经在变量state 中。作为提示,如果您可以尝试仅使用 state 变量(如果变量和函数调用确实提供相同的信息),它会使代码更易于阅读。

    我要做的第二件事是你如何处理状态:p = np.exp(p)p = p * (1. / p.sum())。这通过所有单个观察中存在的所有指数值的总和来标准化整个观察容器。相反,我会将每个单独的观察单独标准化。

    这有以下原因:如果您提供少量观测值,那么所有单个观测值中包含的指数值的总和可能会小于对包含在大量观测值中的指数值求和时的值。个人观察。然后用于归一化的总和中的这些差异将导致归一化值的不同幅度(粗略地说,作为单个观察数量的函数)。考虑以下示例:

    import numpy as np
    
    # Less state representations
    state = np.array([1,1,1])
    state = state/state.sum()
    state
    # Output: array([0.33333333, 0.33333333, 0.33333333])
    
    # More state representations
    state = np.array([1,1,1,1,1])
    state = state/state.sum()
    state
    # Output: array([0.2, 0.2, 0.2, 0.2, 0.2])
    

    实际上,由单个代理获得的相同输入状态表示,在归一化后总是会产生相同的输出状态表示,而与当前模拟中存在的代理数量无关。因此,请确保自行标准化所有观察结果。下面我举个例子。

    另外,请确保跟踪哪些代理的观察(以及以何种顺序)已被压缩到您的变量statappend。这很重要,原因如下。

    如果有代理 A1A5,但整个观察容器只能接受三个观察,则将随机选择五分之三的状态表示。假设随机选择要压缩到整个观察容器中的观察来自以下代理,按以下顺序:A2, A5, A1。然后,这些代理的观察将完全按照这个顺序被压缩到整个观察容器中。首先观察A2,然后是A5,最后是A1。相应地,给定上述整体观察容器,强化学习控制器预测的三个动作将分别对应于代理A2A5A1(按顺序!)。换句话说,输入端代理的顺序也决定了输出端的预测动作对应于哪些代理。

    我会提出如下建议:

    import numpy as np
    
    def get_overall_observation(observations, expected_observations=5):
        # Return value:
        #   order_agents: The returned observations stem from this ordered set of agents (in sequence)
    
        # Get some info
        n_observations = observations.shape[0]  # Actual nr of observations
        observation_size = list(observations.shape[1:])  # Shape of an agent's individual observation
    
        # Normalitze individual observations
        for i in range(n_observations):
            # TODO: handle possible 0-divisions
            observations[i,:] = observations[i,:] / observations[i,:].max()
    
        if n_observations == expected_observations:
            # Return (normalized) observations as they are & sequence of agents in order (i.e. no randomization)
            order_agents = np.arange(n_observations)
            return observations, order_agents
        if n_observations < expected_observations:
            # Return padded observations as they are & padded sequence of agents in order (i.e. no randomization)
            padded_observations = np.zeros([expected_observations]+observation_size)
            padded_observations[0:n_observations,:] = observations
            order_agents = list(range(n_observations))+[-1]*(expected_observations-n_observations) # -1 == agent absent
            return padded_observations, order_agents
        if n_observations > expected_observations:
            # Return random selection of observations in random order
            order_agents = np.random.choice(range(n_observations), size=expected_observations, replace=False)
            selected_observations = np.zeros([expected_observations] + observation_size)
            for i_selected, i_given_observations in enumerate(order_agents):
                selected_observations[i_selected,:] = observations[i_given_observations,:]
            return selected_observations, order_agents
    
    
    # Example usage
    n_observations = 5      # Number of actual observations
    width = height =  2     # Observation dimension
    state = np.random.random(size=[n_observations,height,width])  # Random state
    print(state)
    print(get_overall_observation(state))
    

    【讨论】:

    • 感谢您的回答,正如我告诉您的那样,问题是用零填充小状态并选择最大预期代理。我可以通过选择最大值作为预期的最大代理数来使用编码和解码来解决问题,但我将用零填充小状态。另外,我使用归一化来消除负概率。
    • 看看你的代码和我的代码有什么区别tpcg.io/YBlOAbH8
    • 另外,我在上面的代码中添加了一个 TODO,因为代码可能仍然执行 0-divisions。避免这种情况的最简单方法当然是在observations[i,:].max()0 的情况下不进行划分。然而,由于状态也有可能包含负值,它可能仍然应该被某个值除,适当的 0-除法处理本身就是一种设计选择,因此我只在代码中提供了一个 TODO以上。
    • 关于论文。是的,如上所述,RL 算法不会控制过多的代理(只要存在的代理多于控制器可以处理的数量)。关于状态创建:参见第 3.2 节。该论文没有指定代理的观察结果与整体观察/状态表示相匹配的顺序。但是由于最终在控制器的哪个位置处理哪个代理都无关紧要,因此将随机选择的代理以随机顺序拟合到状态表示中不会产生任何损害。只是因为缺乏自然秩序。
    • 概率在哪里发挥作用?考虑以下行:np.random.choice(range(n_observations), size=expected_observations, replace=False)。假设n_observations = 5expected_observations = 4。然后,range 将创建一个类似于列表的对象,其中包含以下值:[0,1,2,3,4]。然后,np.random.choice 将从[0,1,2,3,4] 中获取与参数size 指定的一样多的唯一(因为replace=False)样本。所以,如果是size=4,那么来自[0,1,2,3,4] 的随机样本可能看起来像[4, 2, 0, 1][1, 2, 0, 3]
    【解决方案2】:

    我使用不同的解决方案解决了这个问题,但我发现编码是解决我问题的最佳解决方案

    • 选择具有预先估计最大状态空间的模型,如果 状态空间小于最大状态,我们填充了状态 带零的空格
    • 仅考虑代理本身的状态,而不考虑任何共享 另一个州。
    • 正如论文[1] 提到的,额外连接的自治 车辆(CAV)不包括在该州内,如果它们更少 比最大 CAV 值,状态用零填充。我们可以选择如何 许多代理,我们可以分享他们的状态添加到代理的 状态。
    • 编码状态,它将帮助我们处理输入并将信息压缩为固定长度。在编码器中,每个 LSTM 层中的单元格或带有门控循环单元 (GRU) 的 RNN 返回隐藏状态 (Ht) 和单元状态 (E't)。

    对于编码器,我使用Neural machine translation with attention code

    class Encoder(tf.keras.Model):
      def __init__(self, vocab_size, embedding_dim, enc_units, batch_sz):
        super(Encoder, self).__init__()
        self.batch_sz = batch_sz
        self.enc_units = enc_units
        self.embedding = tf.keras.layers.Embedding(vocab_size, embedding_dim)
        self.gru = tf.keras.layers.GRU(self.enc_units,
                                       return_sequences=True,
                                       return_state=True,
                                       recurrent_initializer='glorot_uniform')
    
      def call(self, x, hidden):
        x = self.embedding(x)
        output, state = self.gru(x, initial_state = hidden)
        return output, state
    
      def initialize_hidden_state(self):
        return tf.zeros((self.batch_sz, self.enc_units))
    
    • LSTM 零填充和掩码,我们用一个特殊值填充状态,以便稍后屏蔽(跳过)。如果我们在没有掩码的情况下进行填充,则 填充值将被视为实际值,因此,它成为噪声 在状态 [2-4]。

    1- Vinitsky, E., Kreidieh, A., Le Flem, L., Kheterpal, N., Jang, K., Wu, C., ... & Bayen, A. M.(2018 年 10 月)。混合自治交通中强化学习的基准。在机器人学习会议上(第 399-409 页)

    2- Kochkina, E.、Liakata, M. 和 Augenstein, I. (2017)。图灵在 semeval-2017 任务 8:使用分支 lstm 进行谣言立场分类的顺序方法。 arXiv 预印本 arXiv:1704.07221。

    3- Ma, L. 和 Liang, L. (2020)。增强 CNN 对具有可变长度的 12 导联心电图分类的噪声鲁棒性。 arXiv 预印本 arXiv:2008.03609。

    4-How to feed LSTM with different input array sizes?

    5- Zhao, X., Xia, L., Zhang, L., Ding, Z., Yin, D., & Tang, J.(2018 年 9 月)。用于页面推荐的深度强化学习。在第 12 届 ACM 推荐系统会议论文集中(第 95-103 页)。

    【讨论】:

      猜你喜欢
      • 2019-08-04
      • 1970-01-01
      • 2019-05-31
      • 2012-02-17
      • 1970-01-01
      • 1970-01-01
      • 2022-06-19
      • 2017-04-07
      • 2021-04-28
      相关资源
      最近更新 更多