Dueling Network

news2024/11/22 14:19:57

Dueling Network —— Dueling Network Architectures for Deep Reinforcement Learning

  • 论文下载地址

  • 论文介绍

    在这里插入图片描述

    图9. Dueling Network 模型结果示意图

    Dueling Network与传统DQN的区别在于神经网络结构的不同,Dueling Netowrk在传统DQN的基础上只进行了微小的改动,但能大幅提升DQN的表现。从图9中可以看出,在传统DQN中,DQN的神经网络直接输出Q函数的值,即某个状态下不同动作对应的动作价值,输出层的前一层是全连接层。

    Dueling Network对DQN的结构改进主要在全连接层上,它在全连接层和输出层之间进行修改,将全连接层改为两条流,其中一条输出关于状态的价值,另外一条输出关于动作的优势函数的值,最终将两条流合并得到Q动作价值。

    在某些情况下,Dueling Network可以了解哪些状态有价值或没有价值,而不必了解每个动作对状态的影响(在一些状态中,不管选择哪个动作的影响都不大),这在agent的行为不会以任何方式影响到环境的情况下特别有用。
    在这里插入图

    图10. 不同情况下agent的侧重点

    如图10所示,agent注意力集中的部分被标记为橙色,当agent前面没有车时,agent自身动作对于环境并没有太大差异,此时agent更加关注状态价值,当agent前面有车时(agent需要躲避车辆或者超车),agent需要关注不同动作优势值的差异。

  • 理论分析

    假设在Atari游戏中,智能体在时间步 t t t根据由 M M M个视频帧组成的 s t = ( x t − M + 1 , . . . , x t ) ∈ S s_t=(x_{t-M+1},...,x_t)\in S st=(xtM+1,...,xt)S,从动作空间 A = { 1 , . . . , ∣ A ∣ } \mathcal{A}=\{1,...,|\mathcal{A}|\} A={1,...,A}选择动作 a t a_t at ,并观测由模拟器产生的奖励信号 r t r_t rt

    在一局游戏中,把从起始到结束的所有奖励记作 r 1 , . . . , r t , . . . , r n r_1,...,r_t,...,r_n r1,...,rt,...,rn,定义折扣回报率为 γ ∈ [ 0 , 1 ] \gamma \in [0,1] γ[0,1]。折扣回报的定义如公式(1)所示: R t = r t + γ ⋅ r t + 1 + γ 2 ⋅ r t + 2 + ⋯ + γ n − t ⋅ r n (1) R_t=r_t+\gamma \cdot r_{t+1}+\gamma^2 \cdot r_{t+2}+\cdots+\gamma^{n-t} \cdot r_n \tag{1} Rt=rt+γrt+1+γ2rt+2++γntrn(1)在游戏尚未结束的 t t t时刻, R t R_t Rt是一个随机变量,其随机性来自于 t t t时刻之后的所有状态和动作。动作价值函数的定义如公式(2)所示: Q π ( s t , a t ) = E [ R t ∣ S t = s t , A t = a t ] (2) Q_\pi\left(s_t, a_t\right)=\mathbb{E}\left[R_t \mid S_t=s_t, A_t=a_t\right] \tag{2} Qπ(st,at)=E[RtSt=st,At=at](2)公式(2)中的期望消除了 t t t时刻之后的所有状态 S t + 1 , . . . , S n S_{t+1},...,{S_n} St+1,...,Sn 与所有动作 A t + 1 , . . . , A n A_{t+1},...,A_n At+1,...,An,期望只与当前的状态 s t s_t st和动作 a t a_t at相关。上面介绍的状态动作价值函数可以用动态规划递归计算,如公式(3)所示: Q π ( s t , a t ) = E S t + 1 [ r + γ E A t + 1 [ Q π ( s t + 1 , a t + 1 ) ] ∣ S t = s t , A t = a t ] (3) Q_\pi(s_t, a_t)=\mathbb{E}_{S_{t+1}}\left[r+\gamma \mathbb{E}_{A_{t+1} }\left[Q_\pi\left(s_{t+1}, a_{t+1}\right)\right] \mid S_t=s_t, A_t=a_t\right] \tag{3} Qπ(st,at)=ESt+1[r+γEAt+1[Qπ(st+1,at+1)]St=st,At=at](3) 动作价值函数 Q π ( s t , a t ) Q_\pi(s_t,a_t) Qπ(st,at)依赖于 s t s_t st a t a_t at π \pi π,不依赖于 t + 1 t+1 t+1时刻及之后的状态和动作,因为随机变量 S t + 1 , A t + 1 , . . . , S n , A n S_{t+1},A_{t+1},...,S_n,A_n St+1,At+1,...,Sn,An 都被期望消除了。

    为了消除策略 π \pi π的影响,只评价当前状态 s t s_t st和动作 a t a_t at的好坏,引出了最优动作价值函数,如公式(4)所示: Q ⋆ ( s t , a t ) = max ⁡ π Q π ( s t , a t ) , ∀ s t ∈ S , a t ∈ A (4) Q_{\star}\left(s_t, a_t\right)=\max _\pi Q_\pi\left(s_t, a_t\right), \quad \forall s_t \in \mathcal{S}, \quad a_t \in \mathcal{A} \tag{4} Q(st,at)=πmaxQπ(st,at),stS,atA(4)最优动作价值函数可以理解为有很多种策略函数 π \pi π可以选择,我们选择最好的策略函数,如公式(5)所示: π ⋆ = argmax ⁡ π Q π ( s t , a t ) , ∀ s t ∈ S , a t ∈ A (5) \pi^{\star}=\underset{\pi}{\operatorname{argmax}} Q_\pi\left(s_t, a_t\right), \quad \forall s_t \in \mathcal{S}, \quad a_t \in \mathcal{A} \tag{5} π=πargmaxQπ(st,at),stS,atA(5)

    状态价值函数的定义如公式(6)所示: V π ( s t ) = E A t ∼ π ( ⋅ ∣ s t ) [ Q π ( s t , A t ) ] = ∑ a ∈ A π ( a ∣ s t ) ⋅ Q π ( s t , a ) . (6) \begin{aligned} V_\pi\left(s_t\right) & =\mathbb{E}_{A_t \sim \pi\left(\cdot \mid s_t\right)}\left[Q_\pi\left(s_t, A_t\right)\right] \\ & =\sum_{a \in \mathcal{A}} \pi\left(a \mid s_t\right) \cdot Q_\pi\left(s_t, a\right) . \end{aligned} \tag{6} Vπ(st)=EAtπ(st)[Qπ(st,At)]=aAπ(ast)Qπ(st,a).(6)公式(6)中把动作 A t A_t At作为随机变量,然后关于 A t A_t At求期望,把 A t A_t At消掉。状态价值函数 V π ( s t ) V_{\pi}(s_t) Vπ(st)只依赖于策略 π \pi π与当前状态 s t s_t st,不依赖于动作。状态价值函数 V π ( s t ) V_{\pi}(s_t) Vπ(st)也是折扣回报 R t R_t Rt的期望,如公式(7)所示: V π ( s t ) = E A t , S t + 1 , A t + 1 , ⋯   , S n , A n [ R t ∣ S t = s t ] (7) V_\pi\left(s_t\right)=\mathbb{E}_{A_t, S_{t+1}, A_{t+1}, \cdots, S_n, A_n}\left[R_t \mid S_t=s_t\right] \tag{7} Vπ(st)=EAt,St+1,At+1,,Sn,An[RtSt=st](7)公式(7)中消除了 R t R_t Rt依赖的随机变量 A t , S t + 1 , A t + 1 , . . . , S n , A n A_t,S_{t+1},A_{t+1},...,S_n,A_n At,St+1,At+1,...,Sn,An,状态价值函数值越大,表示当前状态 S t S_t St回报的期望越大,用状态价值可以衡量策略 π \pi π与状态 s t s_t st的好坏。

    为了消除策略 π \pi π的影响,只评价当前状态 s t s_t st的好坏,引出了最优状态价值函数,如公式(8)所示: V ⋆ ( s ) = max ⁡ π V π ( s ) , ∀ s ∈ S (8) V_{\star}(s)=\max _\pi V_\pi(s), \quad \forall s \in \mathcal{S} \tag{8} V(s)=πmaxVπ(s),sS(8)

    我们定义优势函数,将状态值函数和状态动作值函数联系起来,如公式(9)所示: A π ( s , a ) = Q π ( s , a ) − V π ( s ) (9) A_\pi(s, a)=Q_\pi(s, a)-V_\pi(s) \tag{9} Aπ(s,a)=Qπ(s,a)Vπ(s)(9) 公式(9)中, V ( s ) V(s) V(s)可以理解为在该状态 s s s下所有可能动作所对应的动作值函数乘以采取该动作的概率之和;通俗来说,值函数 V ( s ) V(s) V(s)是该状态下所有动作值函数关于动作概率的期望。而动作价值函数 Q ( s , a ) Q(s,a) Q(s,a)是单个动作所对应的值函数, Q ( s , a ) − V ( s ) Q(s,a)-V(s) Q(s,a)V(s)表示当前动作值函数相对于平均值的大小。

    所以优势函数表示的是当前动作值函数相比于当前状态值函数的优势,如果优势值大于零,表示当前动作比平均动作好,如果优势函数值小于0,表示当前动作比平均动作差。优势函数表示在当前状态下各个动作的相对好坏程度。

    根据优势函数的定义,我们可以知道优势函数有以下性质,如公式(10)所示: E a ∼ π ( s ) [ A π ( s , a ) ] = E a ∼ π ( s ) [ Q π ( s , a ) − V π ( s ) ] = E a ∼ π ( s ) [ Q π ( s , a ) ] − V π ( s ) = V π ( s ) − V π ( s ) = 0 (10) \mathbb{E}_{a \sim \pi(s)}\left[A^\pi(s, a)\right]= \mathbb{E}_{a \sim \pi(s)}\left[Q_\pi(s, a)-V_\pi(s)\right] = \mathbb{E}_{a \sim \pi(s)}\left[Q_\pi(s, a)\right]-V_\pi(s)= V_\pi(s) - V_\pi(s) = 0\tag{10} Eaπ(s)[Aπ(s,a)]=Eaπ(s)[Qπ(s,a)Vπ(s)]=Eaπ(s)[Qπ(s,a)]Vπ(s)=Vπ(s)Vπ(s)=0(10)

    优势函数刻画的是某个动作相对于平均值函数的“优势”。例如,在状态 s s s下有3个动作 a 1 a_1 a1 a 2 a_2 a2 a 3 a_3 a3,对应的 Q Q Q函数分别为 Q ( s , a 1 ) = 0.9 Q(s,a_1)=0.9 Q(s,a1)=0.9 Q ( s , a 2 ) = 1 Q(s,a_2)=1 Q(s,a2)=1 Q ( s , a 3 ) = 1.1 Q(s,a_3)=1.1 Q(s,a3)=1.1状态 s s s的状态值函数为: V ( s ) = E a [ Q ( s , a ) ] = ( 0.9 + 1 + 1.1 ) / 3 = 1.0 V(s)=\mathbb{E}_a[Q(s,a)]=(0.9+1+1.1)/3=1.0 V(s)=Ea[Q(s,a)]=(0.9+1+1.1)/3=1.0根据优势函数的定义,三个动作的优势函数值分别为: A ( s , a 1 ) = − 0.1 A(s,a_1)=-0.1 A(s,a1)=0.1 A ( s , a 2 ) = 0 A(s,a_2)=0 A(s,a2)=0 A ( s , a 3 ) = 0.1 A(s,a_3)=0.1 A(s,a3)=0.1因此 a 1 a_1 a1对于平均水平(由 V V V定义)的优势为-0.1,表示该动作低于平均的值函数水平, a 2 a_2 a2等于平均水平, a 3 a_3 a3的优势高于平均水平,因此如果按照贪心策略来选择动作,应该选择动作 a 3 a_3 a3,最优动作的选择可以仅通过优势函数 A ( s , a ) A(s,a) A(s,a)得到,即如公式(11)所示: a ∗ = a r g   max ⁡ a A ( s , a ) = a r g   max ⁡ a [ A ( s , a ) + V ( s ) ] = a r g   max ⁡ a Q ( s , a ) (11) a^*=arg\space \max_{a}A(s,a)=arg \space \max_{a} [A(s,a) + V(s)] = arg \space \max_{a}Q(s,a) \tag{11} a=arg amaxA(s,a)=arg amax[A(s,a)+V(s)]=arg amaxQ(s,a)(11)

    Dueling Network的核心思想是将动作值 Q ( s , a ) Q(s,a) Q(s,a)的计算分解成两部分:状态值和优势函数,即如公式(12)所示: Q ( s , a ) = V ( s ) + A ( s , a ) (12) Q(s,a)=V(s)+A(s,a) \tag{12} Q(s,a)=V(s)+A(s,a)(12)但是Dueling Network并不是直接基于公式(12)实现的,因为这会导致不唯一性。假如基于公式(12)实现Dueling Network,那么 V ( s ) V(s) V(s) A ( s , a ) A(s,a) A(s,a)可以随意上下波动,比如一个增大100,另一个减小100,这样的上下波动不影响最终的输出,如公式(13)所示: V ( s ; w ~ V ) ≜ V ( s ; w V ) + 100 , A ( s , a ; w ~ A ) ≜ A ( s , a ; w A ) − 100 V ( s ; w V ) + A ( s , a ; w A ) = V ( s ; w ~ V ) + A ( s , a ; w ~ A ) (13) \begin{aligned} V\left(s ; \tilde{\boldsymbol{w}}^V\right) & \triangleq V\left(s ; \boldsymbol{w}^V\right)+100, \\ A\left(s, a ; \tilde{\boldsymbol{w}}^A\right) & \triangleq A\left(s, a ; \boldsymbol{w}^A\right)-100 \tag{13}\\ V\left(s ; \boldsymbol{w}^V\right)+A\left(s, a ; \boldsymbol{w}^A\right) & =V\left(s ; \tilde{\boldsymbol{w}}^V\right)+A\left(s, a ; \tilde{\boldsymbol{w}}^A\right) \end{aligned} V(s;w~V)A(s,a;w~A)V(s;wV)+A(s,a;wA)V(s;wV)+100,A(s,a;wA)100=V(s;w~V)+A(s,a;w~A)(13)这意味着 V V V D D D的参数可以很随意的变化却不会影响输出的 Q Q Q,这会导致训练过程中参数的不稳定,这不是我们希望看到的。为了解决这个问题,论文中强制令动作的优势函数的最大值最大只能为0,即对每个动作的优势函数减去最优动作的优势函数值,如公式(14)所示: Q ( s , a ; θ , α , β ) = V ( s ; θ , β ) + ( A ( s , a ; θ , α ) − max ⁡ a ′ ∈ ∣ A ∣ A ( s , a ′ ; θ , α ) ) (14) Q(s, a ; \theta, \alpha, \beta)=V(s ; \theta, \beta)+ \left(A(s, a ; \theta, \alpha)-\max _{a^{\prime} \in|\mathcal{A}|} A\left(s, a^{\prime} ; \theta, \alpha\right)\right) \tag{14} Q(s,a;θ,α,β)=V(s;θ,β)+(A(s,a;θ,α)aAmaxA(s,a;θ,α))(14)在公式(12)的基础上加上 max ⁡ a ′ ∈ ∣ A ∣ A ( s , a ′ ; θ , α ) \max _{a^{\prime} \in|\mathcal{A}|} A\left(s, a^{\prime} ; \theta, \alpha\right) maxaAA(s,a;θ,α)之后,它使得 V V V A A A不能随意上下波动。假如让 V V V变大00,让 A A A变小100,则Dueling Network的输出会增大100,不会再是公式(13)展示的结果,其影响如公式(15)所示: V ( s ; w V ) + A ( s , a ; w A ) − m a x a A ( s , a ; w A ) + 100 = V ( s ; w ~ V ) + A ( s , a ; w ~ A ) − m a x a A ( s , a ; w ~ A ) (15) V\left(s ; \boldsymbol{w}^V\right)+A\left(s, a ; \boldsymbol{w}^A\right) - max_aA(s,a;{\boldsymbol{w}}^{A}) + 100=V\left(s ; \tilde{\boldsymbol{w}}^V\right)+A\left(s, a ; \tilde{\boldsymbol{w}}^A\right) - max_aA(s,a;\tilde{\boldsymbol{w}}^A) \tag{15} V(s;wV)+A(s,a;wA)maxaA(s,a;wA)+100=V(s;w~V)+A(s,a;w~A)maxaA(s,a;w~A)(15)基于当前状态 s s s的最优动作 a ⋆ a^{\star} a的获取如公式(16)所示: a ⋆ = a r g   m a x a ′ ∈ A Q ( s , a ′ ; θ , α , β ) = a r g   m a x a ′ ∈ A A ( s , a ′ ; θ , α , β ) (16) a^{\star}=arg\space max_{a' \in \mathcal{A}}Q(s,a';\theta,\alpha,\beta)=arg\space max_{a' \in \mathcal{A}}A(s,a';\theta,\alpha,\beta) \tag{16} a=arg maxaAQ(s,a;θ,α,β)=arg maxaAA(s,a;θ,α,β)(16)根据公式(14)和公式(16),可以得到 Q ( s , a ∗ ; θ , α , β ) = V ( s ; θ , β ) Q\left(s, a^* ; \theta, \alpha, \beta\right)=V(s;\theta,\beta) Q(s,a;θ,α,β)=V(s;θ,β)除了使用 m a x max max方法外,论文中提到可以使用期望的方式来求解 Q Q Q动作价值函数,如公式(17)所示: Q ( s , a ; θ , α , β ) = V ( s ; θ , β ) + ( A ( s , a ; θ , α ) − 1 ∣ A ∣ ∑ a ′ A ( s , a ′ ; θ , α ) ) (17) \begin{aligned} & Q(s, a ; \theta, \alpha, \beta)=V(s ; \theta, \beta)+ \left(A(s, a ; \theta, \alpha)-\frac{1}{|\mathcal{A}|} \sum_{a^{\prime}} A\left(s, a^{\prime} ; \theta, \alpha\right)\right) \end{aligned} \tag{17} Q(s,a;θ,α,β)=V(s;θ,β)+(A(s,a;θ,α)A1aA(s,a;θ,α))(17)公式(14)和公式(17)使用了两种不同的方式来展示Dueling Network的工作原理,两个公式分别通过求解最大值或者期望的形式使得Dueling Network训练过程更加稳定(这也使得 V V V A A A失去了其原始语义,因为它们现在偏离目标一个常量)。

    Dueling Network的优势在于其能够有效学习状态值函数 V V V,随着Dueling Network更新 Q Q Q动作价值函数, V V V状态价值函数也会更新,这与传统的DQN或者Double DQN是不相同的,传统的DQN或者Double DQN只更新对应动作的 Q Q Q动作价值函数,其它动作的 Q Q Q并不会更新。在Dueling Network中,更新 V V V可以影响其它动作的 Q Q Q动作价值函数,使得Dueling Network能够有更好的训练效果。

  • 基于gym的Dueling Network代码实现:

    • requirement:

      • python: 3.8
      • gym: 0.17.3
      • tensorflow: 2.9
    • code(代码主要参考书籍【动手学强化学习】(张伟楠,沈键,俞勇),京东购买链接 | 当当购买链接)

    import gym
    import random
    import tf_rl_utils
    import collections
    import numpy as np
    from tqdm import tqdm
    import tensorflow as tf
    import matplotlib.pyplot as plt
    
    
    class ReplayBuffer:
        """
        经验回放池
        """
        def __init__(self, capacity):
            self.buffer = collections.deque(maxlen=capacity)  # 队列,先进先出
    
        def add(self, state, action, reward, next_state, done):  # 将数据加入buffer
            self.buffer.append((state, action, reward, next_state, done))
    
        def sample(self, batch_size):  # 从buffer中采样数据,数量为batch_size
            transitions = random.sample(self.buffer, batch_size)
            state, action, reward, next_state, done = zip(*transitions)
            return np.array(state), action, reward, np.array(next_state), done
    
        def size(self):  # 目前buffer中数据的数量
            return len(self.buffer)
    
    
    class VAnet(tf.keras.Model):
        """ 只有一层隐藏层的A网络和V网络 """
        def __init__(self, hidden_dim, action_dim):
            super(VAnet, self).__init__()
            self.fc1 = tf.keras.layers.Dense(hidden_dim, activation=tf.keras.activations.relu)  # 共享网络部分
            self.fc_A = tf.keras.layers.Dense(action_dim)
            self.fc_V = tf.keras.layers.Dense(1)
    
        def call(self, x):
            A = self.fc_A(self.fc1(x))
            V = self.fc_V(self.fc1(x))
            Q = V + A - tf.reduce_mean(A, axis=1, keepdims=True)  # Q值由V值和A值计算得到
            return Q
    
    
    class DQN:
        def __init__(self, hidden_dim, action_dim, learning_rate, gamma,
                     epsilon, target_update, dqn_type='VanillaDQN'):
            self.action_dim = action_dim
            self.q_net = VAnet(hidden_dim, self.action_dim)  # Q网络
            # 目标网络
            self.target_q_net = VAnet(hidden_dim, self.action_dim)
            # 使用Adam优化器
            self.optimizer = tf.optimizers.Adam(learning_rate=learning_rate)
            self.gamma = gamma  # 折扣因子
            self.epsilon = epsilon  # epsilon-贪婪策略
            self.target_update = target_update  # 目标网络更新频率
            self.count = 0  # 计数器,记录更新次数
            self.dqn_type = dqn_type
    
        def take_action(self, state):  # epsilon-贪婪策略采取动作
            if np.random.random() < self.epsilon:
                action = np.random.randint(self.action_dim)
            else:
                state = tf.cast(tf.expand_dims(state, axis=0), dtype=tf.float32)
                action = tf.argmax(self.q_net.call(state), axis=1).numpy()[0]
            return action
    
        def max_q_value(self, state):
            state = tf.cast(tf.expand_dims(state, axis=0), dtype=tf.float32)
            return tf.reduce_max(self.q_net.call(state)).numpy()
    
        def update(self, transition_dict):
            states = tf.cast(transition_dict['states'], dtype=tf.float32)
            actions = tf.reshape(transition_dict['actions'], shape=(-1))
            rewards = tf.reshape(tf.cast(transition_dict['rewards'], dtype=tf.float32), shape=(-1, 1))
            next_states = tf.cast(transition_dict['next_states'], dtype=tf.float32)
            dones = tf.reshape(tf.cast(transition_dict['dones'], dtype=tf.float32), shape=(-1, 1))
            with tf.GradientTape() as tape:
                q_values = tf.gather(self.q_net.call(states), actions, batch_dims=1)  # Q值
                # 下个状态的最大Q值
                if self.dqn_type == 'DoubleDQN':  # DQN与Double DQN的区别
                    max_action = tf.argmax(self.q_net.call(next_states), axis=1, output_type=tf.int32)
                    max_next_q_values = tf.reshape(tf.gather(self.target_q_net.call(next_states), max_action, batch_dims=1), shape=(-1,1))  # Q值
                else:
                    max_next_q_values = tf.reduce_max(self.target_q_net.call(next_states), axis=1, keepdims=True)
                q_targets = rewards + self.gamma * max_next_q_values * (1 - dones)  # TD误差目标
                loss_func = tf.keras.losses.MeanSquaredError()
                dqn_loss = tf.reduce_mean(loss_func(q_values, q_targets))  # 均方误差损失函数
            grads = tape.gradient(dqn_loss, self.q_net.trainable_variables)
            self.optimizer.apply_gradients(zip(grads, self.q_net.trainable_variables))
            if self.count % self.target_update == 0:
                self.target_q_net.set_weights(self.q_net.get_weights())  # 更新目标网络
            self.count += 1
    
    
    lr = 1e-2
    num_episodes = 200
    hidden_dim = 128
    gamma = 0.98
    epsilon = 0.01
    target_update = 50
    buffer_size = 5000
    minimal_size = 1000
    batch_size = 64
    
    
    env_name = 'Pendulum-v0'
    env = gym.make(env_name)
    state_dim = env.observation_space.shape[0]
    action_dim = 11  # 将连续动作分成11个离散动作
    
    
    def dis_to_con(discrete_action, env, action_dim):  # 离散动作转回连续的函数
        action_lowbound = env.action_space.low[0]  # 连续动作的最小值
        action_upbound = env.action_space.high[0]  # 连续动作的最大值
        return action_lowbound + (discrete_action / (action_dim - 1)) * (action_upbound - action_lowbound)
    
    
    def train_DQN(agent, env, num_episodes, replay_buffer, minimal_size,
                  batch_size):
        return_list = []
        max_q_value_list = []
        max_q_value = 0
        for i in range(10):
            with tqdm(total=int(num_episodes / 10),
                      desc='Iteration %d' % i) as pbar:
                for i_episode in range(int(num_episodes / 10)):
                    episode_return = 0
                    state = env.reset()
                    done = False
                    while not done:
                        action = agent.take_action(state)
                        max_q_value = agent.max_q_value(
                            state) * 0.005 + max_q_value * 0.995  # 平滑处理
                        max_q_value_list.append(max_q_value)  # 保存每个状态的最大Q值
                        action_continuous = dis_to_con(action, env,
                                                       agent.action_dim)
                        next_state, reward, done, _ = env.step([action_continuous])
                        replay_buffer.add(state, action, reward, next_state, done)
                        state = next_state
                        episode_return += reward
                        if replay_buffer.size() > minimal_size:
                            b_s, b_a, b_r, b_ns, b_d = replay_buffer.sample(
                                batch_size)
                            transition_dict = {
                                'states': b_s,
                                'actions': b_a,
                                'next_states': b_ns,
                                'rewards': b_r,
                                'dones': b_d
                            }
                            agent.update(transition_dict)
                    return_list.append(episode_return)
                    if (i_episode + 1) % 10 == 0:
                        pbar.set_postfix({
                            'episode':
                            '%d' % (num_episodes / 10 * i + i_episode + 1),
                            'return':
                            '%.3f' % np.mean(return_list[-10:])
                        })
                    pbar.update(1)
        return return_list, max_q_value_list
    
    random.seed(0)
    np.random.seed(0)
    env.seed(0)
    tf.random.set_seed(0)
    replay_buffer = ReplayBuffer(buffer_size)
    agent = DQN(hidden_dim, action_dim, lr, gamma, epsilon, target_update, "DoubleDQN")
    return_list, max_q_value_list = train_DQN(agent, env, num_episodes,
                                              replay_buffer, minimal_size,
                                              batch_size)
    
    episodes_list = list(range(len(return_list)))
    mv_return = tf_rl_utils.moving_average(return_list, 5)
    plt.plot(episodes_list, mv_return)
    plt.xlabel('Episodes')
    plt.ylabel('Returns')
    plt.title('Double DQN on {}'.format(env_name))
    plt.show()
    
    
  • result
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/841156.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python 合并多个excel文件

使用 openpyxl 思路&#xff1a; 读取n个excel的文件&#xff0c;存储在一个二维数组中&#xff0c;注意需要转置。将二维数组的数据写入excel。 安装软件&#xff1a; pip install openpyxl源代码&#xff1a; import os import openpyxl # 将n个excel文件数据合并到一个…

jupyter lab环境配置

1.jupyterlab 使用虚拟环境 conda install ipykernelpython -m ipykernel install --user --name tf --display-name "tf" #例&#xff1a;环境名称tf2. jupyter lab kernel管理 show kernel list jupyter kernelspec listremove kernel jupyter kernelspec re…

微软研究院展示Project Rumi项目;参数高效微调(PEFT)

&#x1f989; AI新闻 &#x1f680; 微软研究院展示Project Rumi项目&#xff0c;通过多模态方法增强人工智能理解能力 摘要&#xff1a;微软研究院展示了Project Rumi项目&#xff0c;该项目通过结合文本、音频和视频数据&#xff0c;并采用多模态副语言提示的方法&#xf…

VL 模型 Open-Set Domain Adaptation with Visual-Language Foundation Models 论文阅读笔记

Open-Set Domain Adaptation with Visual-Language Foundation Models 论文阅读笔记 一、Abstract 写在前面 又是一周周末&#xff0c;在家的时间感觉过得很快呀。今天没得时间写博客&#xff0c;留下个标题&#xff0c;明天搞完。 论文地址&#xff1a;Open-Set Domain Adapta…

探索人工智能 | 计算机视觉 让计算机打开新灵之窗

前言 计算机视觉是一门研究如何使机器“看”的科学&#xff0c;更进一步的说&#xff0c;就是指用摄影机和电脑代替人眼对目标进行识别、跟踪和测量等机器视觉&#xff0c;并进一步做图形处理&#xff0c;使电脑处理成为更适合人眼观察或传送给仪器检测的图像。 文章目录 前言…

安全基础 --- https详解 + 数组(js)

CIA三属性&#xff1a;完整性&#xff08;Confidentiality&#xff09;、保密性&#xff08;Integrity&#xff09;、可用性&#xff08;Availability&#xff09;&#xff0c;也称信息安全三要素。 https 核心技术&#xff1a;用非对称加密传输对称加密的密钥&#xff0c;然后…

第一篇:一文看懂 Vue.js 3.0 的优化

我们的课程是要解读 Vue.js 框架的源码&#xff0c;所以在进入课程之前我们先来了解一下 Vue.js 框架演进的过程&#xff0c;也就是 Vue.js 3.0 主要做了哪些优化。 Vue.js 从 1.x 到 2.0 版本&#xff0c;最大的升级就是引入了虚拟 DOM 的概念&#xff0c;它为后续做服务端渲…

java+springboot+mysql员工工资管理系统

项目介绍&#xff1a; 使用javaspringbootmysql开发的员工工资管理系统&#xff0c;系统包含超级管理员&#xff0c;系统管理员、员工角色&#xff0c;功能如下&#xff1a; 超级管理员&#xff1a;管理员管理&#xff1b;部门管理&#xff1b;员工管理&#xff1b;奖惩管理&…

电脑技巧:七个非常神奇有趣的网站,值得收藏

目录 1、Airpano 2、AI创作家 3、The Useless Web 4、全球高清实况摄像头 5、MyFreeMP3 6、世界名画拼图 7、纪妖&#xff08;中国古今妖怪集&#xff09; 互联网是一个神奇的世界&#xff0c;存在着许多令人惊叹的网站&#xff0c;这里就给大家分享七个非常神奇有趣的网…

快速排序【Java算法】

文章目录 1. 概念2. 思路3. 代码实现 1. 概念 快速排序是一种比较高效的排序算法&#xff0c;采用 “分而治之” 的思想&#xff0c;通过多次比较和交换来实现排序&#xff0c;在一趟排序中把将要排序的数据分成两个独立的部分&#xff0c;对这两部分进行排序使得其中一部分所有…

接口测试—知识速查(Postman)

文章目录 接口测试1. 概念2. 原理3. 测试流程4. HTTP协议4.1 URL的介绍4.2 HTTP请求4.2.1 请求行4.2.2 请求头4.2.3 请求体4.2.4 完整的HTTP请求示例 4.3 HTTP响应4.3.1 状态行4.3.2 响应头4.3.3 响应体4.3.4 完整的HTTP请求示例 5. RESTful接口规范6. 测试用例的设计思路6.1 单…

基于Vue+wangeditor实现富文本编辑

目录 前言分析实现具体解决的问题有具体代码实现如下效果图总结前言 一个网站需要富文本编辑器功能的原因有很多,以下是一些常见的原因: 方便用户编辑内容:富文本编辑器提供了类似于Office Word的编辑功能,使得那些不太懂HTML的用户也能够方便地编辑网站内容。提高用户体验…

关于前端动态调试解密签名校验的分享

首先我们先来看一下&#xff0c;下面这张图是笔者近期测试遇到的问题&#xff0c;那就是程序每次生成请求都会生成signature的验签&#xff0c;该验签生成方式暂不可知&#xff0c;唯一知道的就是用一次就失效&#xff0c;这对测试的成本造成了很不好的影响&#xff0c;那么我们…

setmap使用

目录 set使用 set的模板参数 构造函数 成员函数 insert iterator ​编辑 find count pair pair 的模板参数 make_pair multiset使用 multiset 的模板参数 set 与 multiset 的区别 count map使用 map 的模板参数 构造函数 insert iterator find ​编辑 cou…

ChatGPT: 人机交互的未来

ChatGPT: 人机交互的未来 ChatGPT背景ChatGPT的特点ChatGPT的应用场景结论 ChatGPT ChatGPT是一种基于大数据和机器学习的人工智能聊天机器人模型。它由国内团队发明、开发&#xff0c;并被命名为Mental AI。ChatGPT的目标是通过模拟自然对话的方式&#xff0c;提供高效、智能…

Zebec 创始人 Sam 对话社区,“Zebec 生态发展”主题 AMA 回顾总结

近日&#xff0c;Zebec Protocol 创始人 Sam 作为嘉宾&#xff0c;与社区进行了以“Zebec 生态发展”为主题的 AMA 对话。Sam 在线上访谈上对 Zebec 路线图、Zebec 质押、NautChain通证进行了解读&#xff0c;并对 Zebec 的进展、生态建设的愿景进行了展望。本文将对本次 AMA 进…

【C++】语法小课堂 --- auto关键字 typeid查看实际类型 范围for循环 空指针nullptr

文章目录 &#x1f35f;一、auto关键字&#xff08;C11&#xff09;&#x1f369;1、auto的简介&#x1f369;2、auto的使用细则&#x1f6a9;auto与指针和引用结合起来使用&#x1f6a9; 在同一行定义多个变量 &#x1f369;3、auto不能推导的场景1️⃣auto不能作为函数的参数…

GD32F103VE窗口看门狗定时器

GD32F103VE窗口看门狗定时器 看门狗定时器(WDGT)有两个&#xff1a; 1&#xff0c;独立看门狗定时器(FWDGT) 2&#xff0c;窗口看门狗定时器(WWDGT) 窗口看门狗定时器开启后&#xff0c;其7位向下递减计数器工作。 当"向下递减计数器"的计数值达到"预设的窗口…

【Unity3D】消融特效

1 前言 选中物体消融特效中基于 Shader 实现了消融特效&#xff0c;本文将基于 Shader Graph 实现消融特效&#xff0c;两者原理一样&#xff0c;只是表达方式不同&#xff0c;另外&#xff0c;选中物体消融特效中通过 discard 丢弃片元&#xff0c;本文通过 alpha 测试丢弃片元…

Linux中su/su -/sudo的区别

参考Linux中su/su -/sudo的区别 - 知乎 Linux中su/su -/sudo的区别 程序员张同学 ​ 深圳市悦照琉璃科技有限公司 全栈工程师 6 人赞同了该文章 在linux中会经常使用到su/su -/sudo这三个命令&#xff0c;总结一下这三个命令的区别。 su 使用root密码&#xff0c;切换到…