Q-Learning,DQN

1 概念

Screenshot 2025-12-04 at 19.00.27 Screenshot 2025-12-04 at 18.45.00

 

 

  • state 状态
  • action 行动
  • reward function 奖励
  • policy 策略
  • discount rate 衡量当前奖励与未来奖励

 

2、 Q 与 V

  • 动作的价值 Q:代表智能体选择这个动作A后,一直到最终状态奖励总和的期望。告诉你在这个状态下执行某个具体动作有多好。Q,告诉你在S状态下,应该做什么动作
  • 评估状态的值V,它代表了智能体在这个状态S下,一直到最终状态的奖励总和的期望。告诉你这个state好不好

一个状态的V值,就是这个状态下所有动作的Q值,在策略下的期望。

$$\displaystyle{\displaylines{V_{\pi}(S)=\sum_{A}^{}\pi(A|S)Q_{\pi}(S,A)}}$$
通过贝尔曼更新传播到更早的状态,类似于反向传播,例子
import numpy as np

np.random.seed(42)
Q = np.zeros(4)  # 状态A,B,C,D的Q值(假设每个状态只有一个动作)
alpha, gamma = 0.5, 0.9
reward_D = 10  # 到达D的奖励

print("=== 第一轮探索 ===")
Q[2] = Q[2] + alpha * (reward_D + gamma * Q[3] - Q[2])
print(f"更新Q(C) = {Q[2]:.2f} (用Q(D)={Q[3]:.2f})")
Q[1] = Q[1] + alpha * (-1 + gamma * Q[2] - Q[1])
print(f"更新Q(B) = {Q[1]:.2f} (用Q(C)={Q[2]:.2f})")
Q[0] = Q[0] + alpha * (-1 + gamma * Q[1] - Q[0])
print(f"更新Q(A) = {Q[0]:.2f} (用Q(B)={Q[1]:.2f})")
print(f"\n第一轮后: Q = {Q}")

print("\n=== 第二轮探索 ===")
old_Q_C = Q[2]
Q[2] = Q[2] + alpha * (reward_D + gamma * Q[3] - Q[2])
print(f"更新Q(C): {old_Q_C:.2f} → {Q[2]:.2f}")
old_Q_B = Q[1]
Q[1] = Q[1] + alpha * (-1 + gamma * Q[2] - Q[1])
print(f"更新Q(B): {old_Q_B:.2f} → {Q[1]:.2f} (用更好的Q(C))")
old_Q_A = Q[0]
Q[0] = Q[0] + alpha * (-1 + gamma * Q[1] - Q[0])
print(f"更新Q(A): {old_Q_A:.2f} → {Q[0]:.2f} (用稍好的Q(B))")

输出

=== 第一轮探索 ===
更新Q(C) = 5.00 (用Q(D)=0.00)
更新Q(B) = 1.75 (用Q(C)=5.00)
更新Q(A) = 0.29 (用Q(B)=1.75)

第一轮后: Q = [0.2875 1.75   5.     0.    ]

=== 第二轮探索 ===
更新Q(C): 5.00 → 7.50
更新Q(B): 1.75 → 3.75 (用更好的Q(C))
更新Q(A): 0.29 → 1.33 (用稍好的Q(B))

异策略:主要目的是从非最优行为中学习最优策略,探索只是其行为策略的一部分特性。

 

4、DQN

如果状态空间和动作空间比较小,我们可以用Q表来存储,但是如果状态空间很大,用表格存储状体就不现实了。DQN引入了深度神经网络来近似Q值。输入是状态s,输出是每个动作对应的Q值。

4.1 经验回放机制

在训练过程中,智能体与环境交互产生很多的经验,这些经验可以表示为四元组 (s, a, r, s'),分别是状态、动作、奖励和下一个状态。传统的Q学习是直接用每次获得的经验来更新Q值,但这样会存在一些问题,比如前后经验可能存在很强的相关性,导致学习不稳定。而经验回放是把这些经验存储到一个经验回放池中,然后在训练神经网络的时候,从经验回放池中随机采取一批来更新网络参数。这么做的优点

  • 打破了经验之间的相关性
  • 同样的经验可以被多次使用
  • 早起训练 e 很高,大力探索,收集多样的经验,然后随时间衰减到一个比较小的值

Screenshot 2025-12-08 at 11.46.38

 

代码

class ReplayBuffer:
    def __init__(self, capacity):
        self.buffer = collections.deque(maxlen=capacity)  # 固定大小的队列
        
    def add(self, experience):
        # 添加新经验,如果缓冲区已满,自动移除最旧的经验
        self.buffer.append(experience)
    
    def sample(self, batch_size):
        # 随机采样一批经验
        indices = np.random.choice(len(self.buffer), batch_size, replace=False)
        batch = [self.buffer[i] for i in indices]
        
        # 将批次数据转换为适合训练的格式
        states, actions, rewards, next_states, dones = zip(*batch)
        return np.array(states), np.array(actions), np.array(rewards), 
               np.array(next_states), np.array(dones)

 

经验回放与e-greedy采样的关系:

  1. 观察当前状态s
  2. 使用e-greedy策略选择动作a执行动作a,获得(r, s', done)
  3. 将经验(s, a, r, s', done)存入回放缓冲区
  4. 从缓冲区随机采样一个批次
  5. 用采样的批次更新神经网络
  6. 定期更新目标网络
  7. s'->s,进入下一个时间步,继续循环

代码:

# 在一个训练循环中
for episode in range(num_episodes):
    state = env.reset()
    done = False
    
    while not done:
        # ========== ε-greedy 部分 ==========
        # 选择动作(总是使用ε-greedy)
        if np.random.rand() <= epsilon:
            action = env.action_space.sample()  # 探索
        else:
            action = np.argmax(dqn.predict(state))  # 利用
        
        # 执行动作
        next_state, reward, done, _ = env.step(action)
        
        # ========== 经验回放 部分 ==========
        # 1. 存储经验
        replay_buffer.add(state, action, reward, next_state, done)
        
        # 2. 采样训练(如果缓冲区足够)
        if len(replay_buffer) > batch_size:
            batch = replay_buffer.sample(batch_size)
            dqn.train(batch)  # 训练网络
        
        # 3. 衰减ε
        epsilon = max(epsilon_min, epsilon * epsilon_decay)
        
        state = next_state

 

4.2 目标网络

目标网络是DQN算法中第二个关键创新点(第一个是经验回放),它解决了深度强化学习中的“移动目标问题”。在标准的 Q 学习更新中,我们同时使用同一个网络来计算当前 Q(s,a)值,计算目标 Q(s',a'|θ): r + γ * max_a' Q(s', a'; θ)。在一个时间步(t0->t1->t2....tn)里面,目标值在学习过程中不断变化。example,

$$\displaystyle{\displaylines{L(\theta)=\frac{1}{2}(target-Q(s,a))^{2}}}$$
posted @ 2025-12-04 19:01  ylxn  阅读(15)  评论(0)    收藏  举报