Atari 游戏训练 -- 2. 基于jupyter,图片处理 + state更新 + 经验回放数据初始化

本文详细介绍使用OpenCV对游戏帧进行预处理的方法,包括图片灰度化、非游戏区域剪切、图片缩放至84*84,以及如何初始化和迭代state,通过叠加连续的4帧图片来提取游戏角色的移动趋势特征。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

帧图片处理 openCV

step1.图片灰度处理

图片灰度处理后,三通道(RGB) ===>> 单通道

两种方式:

  1. 常用的公式对三通道进行处理:ray = R0.299 + G0.587 + B*0.114
  2. openCV 直接灰度处理:img_grey=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
step2.图片剪切,减去非游戏区域
step3.缩小图片至84*84

#别问我图片为什么不灰

import gym
import time
import cv2 
import torch
import torch.nn as nn
import numpy as np
import matplotlib.pyplot as plt         
import matplotlib.image as mpimg   


#chage the image size from 210*160*3 to 84*84
#change the RGB image into grey image

def preprocess(obs):
    img = obs.astype(np.float32)
    
    #step1: a common formula converting  converting RGB images into gray images: 
    #ray = R*0.299 + G*0.587 + B*0.114
    img_grey = img[:, :, 0] * 0.299 + img[:, :, 1] * 0.587 + img[:, :, 2] * 0.114  #shape = (210,160,1)  
    #img_grey=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    print('img_grey shape =', np.shape(img_grey))
    plt.imshow(img_grey) 
    plt.show()
    
    #step2: Crop out the non-game area of the image 
    image_gameArea = img_grey[0:172,:]      #shape = (172,160,1)  
    print('image_gameArea shape =', np.shape(image_gameArea))
    plt.imshow(image_gameArea) 
    plt.show()
    
    #step3: reduce the scale of the picture into 84*84
    image_small = cv2.resize(image_gameArea, (84, 84), interpolation=cv2.INTER_AREA)  # shape(84,84)
    print('image_small shape =', np.shape(image_small))
    plt.imshow(image_small) 
    plt.show()

在这里插入图片描述


state的初始化和迭代

设置定义:
observation:一帧图片
state: state是最近的、连续的4帧图片叠加。
在这里插入图片描述

为什么要叠加4帧图片呢?因为有的游戏需要提取移动趋势特征,比如有两帧相同的图片(相同的observation),游戏角色在相同的位置,但是运动趋势不一样,一个是从左往右移动到这个位置,一个是从右往左移动到这个位置,提取游戏角色的移动趋势特征更有利于训练出准确的动作预测。

由上图可见,state会做为CNN的输入,经过多层卷集处理,输出是各个action对应的Q-value.后面文章会详细说明。

当刚加载游戏时,游戏处于第一帧图片时,这时自然是没有前3帧,怎么办呢?把这一帧图片复制4份叠加。

def init_state(self, obs):
        x = self.preprocess(obs) 
        state_initial = np.stack((x, x, x, x), axis=0)      # shape(4, 84, 84)      
        #print('shape_ state_initial  =', np.shape(state_initial)) 
        return state_initial

之后就不断迭代state:
在每做完一个动作后,会产生reward和next observation,把这个observation添加进state,然后最老的那个observation剔除出去,组成next state

    def next_state(self, state, obs):
        x = self.preprocess(obs)
        #state  = np.reshape(state, (4,84,84))
        next_state = np.append(state[1:, :, :], np.expand_dims(x, 0), axis=0)    # shape(4, 84, 84)
        #print('shape_next_state  =', np.shape(next_state))      
        return next_state

用于经验回放 的经验库的初始化 replay experience initialization

经验回放之后的文章会介绍,这里先说经验数据需要哪些字段
如果你学过Q-learning(Reinforcement Learning 的一种方式), 你就会知道在其学习过程中,会需要: state, action, reward, next_state,这里也一样(就是多个个游戏是否结束的状态done)。

当然一样啦,因为经验回放就是用于Deep Q-learning Network 的学习的。

for epis in range(experience):        
    action = env.action_space.sample()
    obs, reward, done, _ = env.step(action)
    next_state = state_update(state,obs)          #shape_next_state  = (4, 84, 84)
    memory.append((state, action, reward, next_state, done))

附上完整代码,可以跑的那种

import gym
import time
import cv2 
import torch
import torch.nn as nn
import numpy as np
from collections import deque
import matplotlib.pyplot as plt         
import matplotlib.image as mpimg   


#chage the image size from 210*160*3 to 84*84
#change the RGB image into grey image

def preprocess(obs):
    img = obs.astype(np.float32)
    
    # a common formula converting  converting RGB images into gray images: ray = R*0.299 + G*0.587 + B*0.114
    img_grey = img[:, :, 0] * 0.299 + img[:, :, 1] * 0.587 + img[:, :, 2] * 0.114            #shape = (210,160,1)   
    #print('img_grey shape =', np.shape(img_grey))
    #plt.imshow(img_grey) 
    #plt.show()
    
    #Crop out the non-game area of the image 
    image_gameArea = resized_screen = img_grey[0:172,:]      #shape = (172,160,1)  
    #print('image_gameArea shape =', np.shape(image_gameArea))
    #plt.imshow(image_gameArea) 
    #plt.show()
    
    #reduce the scale of the picture into 84*84
    image_small = cv2.resize(image_gameArea, (84, 84), interpolation=cv2.INTER_AREA)   # shape(84,84)
    #print('image_small shape =', np.shape(image_small))
    #plt.imshow(image_small) 
    #plt.show()

    return image_small.astype(np.float32) / 255.0



def init_state(obs):
    x = preprocess(obs) 
    state_initial = np.stack((x, x, x, x), axis=0)      # shape(4, 84, 84)      
    #print('shape_ state_initial  =', np.shape(state_initial)) 
    return state_initial


def state_update(state, obs):
    x = preprocess(obs)
    #state  = np.reshape(state, (4,84,84))
    next_state = np.append(state[1:, :, :], np.expand_dims(x, 0), axis=0)    # shape(4, 84, 84)
    #print('shape_next_state  =', np.shape(next_state))      
    return next_state
    
    
    
experience = 1000  
memory = deque(maxlen=experience)    
env = gym.make('MsPacman-v0')
#print(env.observation_space)

obs = env.reset()  
state = init_state(obs)
#print('state  =', np.shape(state))
            
for epis in range(experience):        
    action = env.action_space.sample()
    obs, reward, done, _ = env.step(action)
    next_state = state_update(state,obs)          #shape_next_state  = (4, 84, 84)
    memory.append((state, action, reward, next_state, done))
        
        
    if done:
        print('done')
        obs = env.reset()               
        state = init_state(obs)             
    else:
        state = next_state
            
    time.sleep(0.05) # sleep for 1 second to observe the whole process
    env.render()      

env.close()


<think>好的,我现在要解释一下Double DQN。首先,我需要确认自己对这个概念的理解是否正确。Double DQN是深度强化学习中的一种算法,用来解决传统DQN中的过估计问题。对吧? 嗯,传统DQN在计算目标Q值时,使用同一个网络来选择动作和评估Q值,这可能导致某些动作的Q值被高估。Double DQN对此进行了改进,对吧?应该是引入了两个网络,一个用于选择动作,另一个用于评估,从而减少过估计。比如,使用当前网络选择动作,然后用目标网络来计算目标Q值。这样的话,选择和评估是分开的,对吗? 不过,具体是怎么操作的呢?比如,在原来的DQN中,目标Q值的计算公式是目标网络对下一个状态的最大Q值加上奖励。而Double DQN可能改为用当前网络来选择下一个状态的动作,再用目标网络来评估这个动作的Q值。这样的话,两者的解耦应该能减少过高的估计。 那数学表达式应该怎么写?传统DQN的目标Q值是$$ y = r + \gamma \max_{a'} Q_{\text{target}}(s', a') $$。而Double DQN应该是$$ y = r + \gamma Q_{\text{target}}(s', \arg\max_{a'} Q_{\text{current}}(s', a')) $$。对吗?这样,选择动作用的是当前的Q网络,而评估用的是目标网络,避免了同一网络同时进行选择和评估的问题。 不过,这里是不是应该更详细地拆分步骤?比如,在计算目标的时候,首先用当前网络Q_current找出下一个状态s'下最优的动作a*,即a* = argmax Q_current(s', a')。然后用目标网络Q_target来得到这个动作a*对应的Q值,即Q_target(s', a*),再乘以折扣因子γ加上奖励r。这样组合起来就是目标Q值。这样的话,目标Q值的计算就分解成了两个步骤,分别使用不同的网络,从而减少过估计。 那这样做为什么有效呢?可能因为在传统DQN中,max操作会导致估计偏差,因为同一个网络同时估计所有动作的Q值并选择最大值,容易高估。而Double DQN通过解耦选择和评估,让两个网络的不同估计误差相互抵消,从而降低整体的高估。 那Double DQN和DQN在实现上的主要区别是什么?应该是在目标Q值的计算部分。DQN直接使用目标网络的最大值,而Double DQN使用当前网络选择动作,目标网络评估该动作的Q值。其他部分,比如经验回放和目标网络的定期更新,应该保持不变。 不过,用户可能需要一个更结构化的解释。我应该先介绍DQN的过估计问题,然后引出Double DQN的解决方法,再详细说明其原理和实现步骤,最后比较两者的差异和优势。 另外,要确保使用正确的中文术语,比如“过估计”、“目标网络”、“经验回放”等。同时,数学公式需要用$$...$$,行内公式用$...$,比如在解释目标Q值时,正确的LaTeX格式很重要。 可能需要验证一下Double DQN的原始论文中的公式是否正确。根据论文《Deep Reinforcement Learning with Double Q-Learning》,他们的方法确实是将动作选择和值评估分开,用当前网络选择动作,目标网络计算值。这样可以减少偏差,对吗? 总结一下,Double DQN的核心思想是解耦动作选择和Q值评估,使用两个不同的网络来分别处理这两个步骤,从而减少传统DQN中的过高估计问题。这种改进使得Q值估计更准确,从而提升算法的稳定性和性能。</think>Double DQN(双深度Q网络)是深度强化学习中的一种改进算法,旨在解决传统DQN(深度Q网络)中存在的**Q值过估计问题**。以下将逐步解释其原理和实现方式。 --- ### 1. 传统DQN的过估计问题 在DQN中,目标Q值的计算公式为: $$ y = r + \gamma \max_{a'} Q_{\text{target}}(s', a') $$ 其中: - $r$ 是当前奖励 - $\gamma$ 是折扣因子 - $Q_{\text{target}}$ 是目标网络对下一状态$s'$的Q值估计 **问题**:使用同一个目标网络同时选择动作($\max_{a'}$)和评估Q值,可能导致某些动作的Q值被系统性高估。这种高估会传播到整个训练过程,影响策略的稳定性。 --- ### 2. Double DQN的改进思路 Double DQN通过**解耦动作选择与Q值评估**来解决过估计问题: 1. **动作选择**:使用当前网络(训练中的网络)选择最优动作。 2. **Q值评估**:使用目标网络(延迟更新的网络)计算所选动作的Q值。 --- ### 3. 目标Q值的计算公式 Double DQN的目标Q值公式为: $$ y = r + \gamma Q_{\text{target}}\left(s', \arg\max_{a'} Q_{\text{current}}(s', a')\right) $$ - $Q_{\text{current}}$:当前网络,负责选择下一状态$s'$的最优动作。 - $Q_{\text{target}}$:目标网络,负责评估所选动作的Q值。 --- ### 4. 实现步骤 1. **初始化两个网络**: - 当前网络 $Q_{\text{current}}$:实时更新参数。 - 目标网络 $Q_{\text{target}}$:定期从当前网络复制参数(软更新或硬更新)。 2. **经验回放**: 与传统DQN相同,存储转移样本 $(s, a, r, s', \text{done})$ 到回放缓冲区,并随机采样以打破数据相关性。 3. **计算目标Q值**: 使用当前网络选择动作,目标网络评估该动作: $$ a^* = \arg\max_{a'} Q_{\text{current}}(s', a') $$ $$ y = r + \gamma Q_{\text{target}}(s', a^*) $$ 4. **更新当前网络**: 最小化当前Q值与目标Q值的均方误差: $$ \text{Loss} = \mathbb{E}\left[ \left( Q_{\text{current}}(s, a) - y \right)^2 \right] $$ 5. **同步目标网络**: 定期将当前网络的参数复制到目标网络(例如每$C$步)。 --- ### 5. 优势分析 - **减少过估计**:动作选择和Q值评估由不同网络完成,避免了偏差的累积。 - **稳定性更高**:实验表明,Double DQN在Atari游戏等任务中比DQN收敛更快且更稳定。 - **兼容性强**:可与DQN的其他改进(如优先经验回放、Dueling DQN)结合使用。 --- ### 6. 代码示例(伪代码) ```python # 初始化当前网络和目标网络 current_net = DQN() target_net = DQN() target_net.load_state_dict(current_net.state_dict()) # 训练循环 for episode in episodes: state = env.reset() while not done: action = epsilon_greedy(state, current_net) next_state, reward, done, _ = env.step(action) replay_buffer.push(state, action, reward, next_state, done) # 从回放缓冲区采样 batch = replay_buffer.sample() # 计算目标Q值 next_actions = current_net(next_states).argmax(dim=1) target_q = target_net(next_states).gather(1, next_actions.unsqueeze(1)) target = rewards + (1 - dones) * gamma * target_q # 更新当前网络 loss = F.mse_loss(current_net(states).gather(1, actions), target) optimizer.zero_grad() loss.backward() optimizer.step() # 同步目标网络(例如每C步) if step % C == 0: target_net.load_state_dict(current_net.state_dict()) ``` --- ### 总结 Double DQN通过分离动作选择与Q值评估的角色,显著降低了传统DQN中的过估计问题,提升了算法的鲁棒性。其核心思想简单却有效,是深度强化学习中的经典改进方法之一。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Enzo 想砸电脑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值