基于深度强化学习的DQN模型实现自动玩俄罗斯方块游戏(附详细代码讲解)

news/2024/5/16 20:47:16/文章来源:https://blog.csdn.net/weixin_40651515/article/details/131980389

一、DQN(Deep Q-Network)方法概述

        DQN(Deep Q-Network)是一种强化学习方法,通过结合Q-learning算法和深度神经网络来解决强化学习问题。它是深度强化学习的里程碑之一,由DeepMind在2013年提出,被广泛应用于各种复杂的强化学习任务。DQN方法的概述如下:

1.强化学习问题:在强化学习中,智能体与环境进行交互,通过观察环境的状态并采取动作,来最大化累积奖励。智能体在环境中移动并与之交互,不断学习并优化策略,以在不同的状态下选择最优动作。

2.Q-learning算法:Q-learning是一种经典的强化学习算法,用于学习最优Q函数。Q函数表示在给定状态下采取某个动作的预期累积奖励值。Q-learning使用迭代更新的方式逼近最优Q函数,其核心思想是使用贝尔曼方程来更新Q值。贝尔曼方程表示当前状态下采取动作的Q值可以通过下一个状态的最大Q值和立即奖励来进行递归更新。

3.DQN的创新点:DQN的创新之处在于使用深度神经网络来逼近Q函数。传统的Q-learning方法使用表格存储Q值,但在大型状态空间问题中,表格变得不可行。DQN通过使用神经网络来表示Q函数,将状态作为输入,输出对应于每个动作的Q值,从而可以对大型状态空间进行近似求解。

4.Experience Replay(经验回放):DQN使用经验回放技术来存储智能体的经验,包括状态、动作、奖励和下一个状态。在训练过程中,DQN从经验回放缓冲区中随机抽样,以打破数据之间的关联性,从而更有效地使用经验数据进行训练。

5.Target Network(目标网络):为了稳定训练过程,DQN引入了目标网络。在训练过程中,有两个神经网络:一个是用于选择动作的主网络,另一个是用于计算目标Q值的目标网络。目标网络的参数比主网络的参数更新更慢,这有助于减少训练中的目标Q值估计的波动性。

6.Double Q-learning:DQN还采用了Double Q-learning的思想,用于更准确地估计Q值。在目标网络和主网络中分别选择最大动作,并结合它们的Q值来更新目标Q值。

        DQN方法的训练过程是迭代的,通过反复与环境交互、更新神经网络权重和优化策略,使得智能体逐渐学习到最优的Q函数,并从中得到最佳决策策略。DQN在很多复杂的强化学习任务中取得了显著的成功,并为后续深度强化学习算法的发展奠定了基础。

二、强化学习代码实现及训练过程

        本文将实现一个使用DQN算法和深度神经网络的强化学习代理,通过逼近Q函数来优化决策策略。代理以单一分数来表示每个状态的预期得分,并使用神经网络训练来逼近这些Q值。在训练过程中,代理通过经验回放和目标网络来稳定训练,并通过探索与利用策略优化决策能力。

        首先,我们基于DQN实现一个DQNAgent类,该类实现了一个基于深度强化学习的代理,使用DQN(Deep Q-Network)算法来解决强化学习问题。代码逻辑功能概述如下:

1.这个代理使用DQN算法来学习最优的决策策略。
2.代理的目标是找到所有可能状态的最佳最终状态的组合,而不是传统方法中找到特定状态的最佳动作。
3.通过使用深度神经网络来逼近Q函数,代理可以处理大型状态空间的问题。
4.代码中使用经验回放技术和目标网络来优化训练过程,提高稳定性和效率。

实现的代码如下:

class DQNAgent:def __init__(self, state_size, mem_size=10000, discount=0.95, epsilon=1, epsilon_min=0, epsilon_stop_episode=500,n_neurons=[32, 32], activations=('relu', 'relu', 'linear'), loss='mse', optimizer='adam',replay_start_size=None):# 初始化DQNAgent代理assert len(activations) == len(n_neurons) + 1self.state_size = state_sizeself.memory = deque(maxlen=mem_size)self.discount = discountself.epsilon = epsilonself.epsilon_min = epsilon_minself.epsilon_decay = (self.epsilon - self.epsilon_min) / epsilon_stop_episodeself.n_neurons = n_neuronsself.activations = activationsself.loss = lossself.optimizer = optimizerif not replay_start_size:replay_start_size = mem_size / 2self.replay_start_size = replay_start_sizeself.model = self.build_model()# 创建一个深度神经网络模型def build_model(self) -> Model:model = Sequential()model.add(Dense(self.n_neurons[0], input_dim=self.state_size, activation=self.activations[0]))for i in range(1, len(self.n_neurons)):model.add(Dense(self.n_neurons[i], activation=self.activations[i]))model.add(Dense(1, activation=self.activations[-1]))model.compile(loss=self.loss, optimizer=self.optimizer)return model# 将动作过程添加到经验回放缓冲区中def add_to_memory(self, current_state, next_state, reward, done):self.memory.append((current_state, next_state, reward, done))# 为某个动作分配一个随机得分def random_value(self):return random.random()# 预测给定状态的得分def predict_value(self, state: np.ndarray) -> float:return self.model.predict(state)[0]# 返回给定状态的预期得分def act(self, state):state = np.reshape(state, [1, self.state_size])if random.random() <= self.epsilon:return self.random_value()else:return self.predict_value(state)# 返回给定状态集合中的最佳状态def best_state(self, states):max_value = Nonebest_state = Noneif random.random() <= self.epsilon:return random.choice(list(states))else:for state in states:value = self.predict_value(np.reshape(state, [1, self.state_size]))if not max_value or value > max_value:max_value = valuebest_state = statereturn best_state# 训练神经网络模型def train(self, batch_size=32, epochs=3):n = len(self.memory)if n >= self.replay_start_size and n >= batch_size:batch = random.sample(self.memory, batch_size)# 获取下一个状态的预期得分next_states = np.array([x[1] for x in batch])next_qs = [x[0] for x in self.model.predict(next_states)]x = []y = []# 构建训练数据的输入输出结构for i, (state, _, reward, done) in enumerate(batch):if not done:new_q = reward + self.discount * next_qs[i]  # 更新预期得分(Q值)else:new_q = rewardx.append(state)y.append(new_q)# 使用训练数据拟合模型self.model.fit(np.array(x), np.array(y), batch_size=batch_size, epochs=epochs, verbose=0)# 更新探索变量if self.epsilon > self.epsilon_min:self.epsilon -= self.epsilon_decay

代码中DQNAgent类:

state_size:输入域(状态空间)的大小。
mem_size:回放缓冲区的大小。
discount:未来奖励相对于即时奖励的重要性(折扣因子)[0,1]。
epsilon:开始时的探索概率(以给定概率执行随机动作)。
epsilon_min:当代理停止减少探索概率时的最小值。
epsilon_stop_episode:代理停止减少探索变量的回合数。
n_neurons:每个隐藏层中神经元的数量的列表。
activations:每个隐藏层和输出层中使用的激活函数的列表。
loss:用于训练神经网络的损失函数。
optimizer:用于训练神经网络的优化器。
build_model():方法用于创建和编译基于指定结构(神经元数量和激活函数)的Keras神经网络模型。
add_to_memory():方法用于将一个经验元组(当前状态、下一个状态、奖励、完成标志)添加到回放缓冲器中。
random_value():方法返回一个随机值(用于在探索时为某个动作分配随机分数)。
predict_value():方法接收一个状态作为输入,并预测该状态的预期分数,使用训练好的神经网络。
act():方法根据当前状态选择一个动作(值)。它根据探索概率(epsilon)决定是进行探索(随机动作)还是利用(预测动作)。
best_state():方法接收一个状态集合,并根据预测的最高分数返回最佳状态。它可以根据一定概率(epsilon)进行探索或利用最佳预测状态。
train():方法用于训练神经网络,使用从回放缓冲器中抽样的经验。它使用Q-learning的更新规则来调整神经网络权重,以更好地逼近Q函数。

        将写好的俄罗斯方块游戏和DQNAgent类的强化学习策略进行结合,通过训练和评估在Tetris游戏中的性能,以寻找最佳策略来玩这个游戏。实现的过程如下:

        1.定义了run_model函数,用于训练和评估DQN代理的性能。在每个回合(episode)中,代理在Tetris游戏环境中执行动作,并收集游戏得分。代码实现如下:

def run_model(dir_name, episodes=100, render=False):env = Tetris()epsilon_stop_episode = 1500mem_size = 20000discount = 0.95replay_start_size = 2000n_neurons = [32, 32]activations = ['relu', 'relu', 'linear']agent = DQNAgent(env.get_state_size(), n_neurons=n_neurons, activations=activations,epsilon_stop_episode=epsilon_stop_episode, mem_size=mem_size, discount=discount,replay_start_size=replay_start_size)model_path = '../checkpoints/' + dir_name + '/model.hdf'agent.model = load_model(model_path)agent.epsilon = 0scores = []for episode in range(episodes):env.reset()game_over = Falsewhile not game_over:next_states = env.get_next_states()best_state = agent.best_state(next_states.values())# find the action, that corresponds to the best statebest_action = Nonefor action, state in next_states.items():if state == best_state:best_action = actionbreak_, game_over = env.hard_drop([best_action[0], 0], best_action[1], render)scores.append(env.score)print(f'episode {episode} => {env.score}')return scores

        2.定义run_model_helper函数,用于运行多个训练过程并评估它们的性能。该函数加载预先训练好的模型,并在每个目录下执行run_model函数,输出训练得分的最大值和对应目录的名称。代码如下:

def run_model_helper(episodes=128, render=False):dirs = [name for name in os.listdir('../checkpoints') if os.path.isdir(os.path.join('../checkpoints', name))]dirs.sort(reverse=True)dirs = [dirs[0]]max_scores = []for directory in dirs:print(f"Evaluating dir '{directory}'")scores = run_model(directory, episodes, render)max_scores.append((directory, max(scores)))max_scores.sort(key=lambda t: t[1], reverse=True)for k, v in max_scores:print(f"{v}\t{k}")

         训练过程如下:

 三、实现自动玩俄罗斯方块游戏

        首先实现一个简单的俄罗斯方块基本游戏,实现的逻辑过程如下:

  1. 定义游戏地图和方块的常量:在游戏中,定义了游戏地图的大小、方块的大小、颜色等常量,并存储在相应的类属性中。

  2. 初始化游戏状态:在Tetris类的构造函数中,初始化了游戏的各种状态,包括当前方块位置、旋转角度、游戏得分等,以及游戏地图和下一个方块的预览板状态。

  3. 重置游戏状态:通过reset方法,重置游戏状态,重新开始一局游戏。重置后,将清空游戏地图,生成新的随机方块,并更新下一个方块的预览板。

  4. 方块的旋转与移动:游戏中的方块可以通过W键进行顺时针旋转,A键向右移动一列,S键向下移动一行,D键向左移动一列。这些操作在游戏中通过调整当前方块的位置和旋转角度来实现。

  5. 方块的硬降:在游戏中,通过按下空格键,可以将当前方块快速降落到底部。为了实现这个功能,游戏会不断检测方块是否可以继续向下移动,直到无法移动为止。

  6. 方块的落地和消除:当方块无法再继续向下移动时,将方块固定在游戏地图上,并判断是否有可消除的行。如果有,则消除行并增加玩家得分。

  7. 下一个方块的预览:游戏界面上会显示下一个方块的预览板,让玩家提前了解下一个方块的形状。

  8. 游戏结束判断:游戏判断是否结束的条件是当前方块在初始位置无法继续向下移动。

  9. 获取游戏状态特征:游戏通过一系列特征函数来提取当前游戏状态的特征,例如已消除行数、空洞数量、高度差等,用于在强化学习中作为输入来训练智能体。

  10. 图形渲染:游戏界面使用cv2库进行图形渲染,将游戏状态以图形化形式显示在屏幕上。

该游戏可以实现自己玩,控制方法为:

        W - 将方块顺时针旋转90度
        A - 将方块向右移动一列
        S - 将方块向下移动一行
        D - 将方块向左移动一列
        空格键 - 快速落下方块
        ESC - 退出游戏

自己玩游戏的过程如下:

AI方法玩游戏的过程如下:(非常快) 

 

全部代码链接:

https://download.csdn.net/download/weixin_40651515/88114773

运行配置环境:tensorflow==1.14.0 tensorboard==1.14.0 keras==2.2.4 opencv==4.7.0.72 numpy==1.21.6 pillow==5.4.1 tqdm==4.31.1等

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

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI绘画StableDiffusion实操教程:可爱头像奶茶小女孩(附高清图片)

本教程收集于&#xff1a;AIGC从入门到精通教程汇总 今天继续分享AI绘画实操教程&#xff0c;如何用lora包生成超可爱头像奶茶小女孩 放大高清图已放到教程包内&#xff0c;需要的可以自取。 欢迎来到我们这篇特别的文章——《AI绘画StableDiffusion实操教程&#xff1a;可爱…

FPGA2-采集OV5640乒乓缓存后经USB3.0发送到上位机显示

1.场景 基于特权A7系列开发板&#xff0c;采用OV5640摄像头实时采集图像数据&#xff0c;并将其经过USB3.0传输到上位机显示。这是验证数据流能力的很好的项目。其中&#xff0c;用到的软件版本&#xff0c;如下表所示&#xff0c;基本的硬件情况如下。该项目对应FPGA工程源码…

VMware虚拟机中配置静态IP

目录 环境原因基础概念VMnet网络IPV4网络私有地址范围Vmnet8的作用网路通信的过程解决方法1&#xff1a;修改k8s组件重新启动解决方法2&#xff1a;配置静态IP系统网卡设置设置虚拟机网关修改虚拟机网卡 环境 本机系统&#xff1a;windows11虚拟机系统&#xff1a;CentOS-7-x8…

iOS - Apple开发者账户添加新测试设备

获取UUID 首先将设备连接XCode&#xff0c;打开Window -> Devices and Simulators&#xff0c;通过下方位置查看 之后登录(苹果开发者网站)[https://developer.apple.com/account/] &#xff0c;点击设备 点击加号添加新设备 填写信息之后点击Continue&#xff0c;并一路继续…

【EI/SCOPUS会议征稿】第四届机器学习与计算机应用国际学术会议(ICMLCA 2023)

ICMLCA 2023 第四届机器学习与计算机应用国际学术会议 2023 4th International Conference on Machine Learning and Computer Application 第四届机器学习与计算机应用国际学术会议(ICMLCA 2023)定于2023年10月27-29日在中国杭州隆重举行。本届会议将主要关注机器学习和计算…

iOS开发-CAShapeLayer与UIBezierPath实现微信首页的下拉菜单效果

iOS开发-CAShapeLayer与UIBezierPath实现微信首页的下拉菜单效果 之前开发中遇到需要使用实现微信首页的下拉菜单效果。用到了CAShapeLayer与UIBezierPath绘制菜单外框。 一、效果图 二、CAShapeLayer与UIBezierPath 2.1、CAShapeLayer是什么&#xff1f; CAShapeLayer继承自…

《Elasticsearch 源码解析与优化实战》第5章:选主流程

《Elasticsearch 源码解析与优化实战》第5章&#xff1a;选主流程 - 墨天轮 一、简介 Discovery 模块负责发现集群中的节点&#xff0c;以及选择主节点。ES 支持多种不同 Discovery 类型选择&#xff0c;内置的实现称为Zen Discovery ,其他的包括公有云平台亚马逊的EC2、谷歌…

shell中按照特定字符分割字符串,并且在切分后的每段内容后加上特定字符(串),然后再用特定字符拼接起来

文件中的内容&#xff0c;可以这么写&#xff1a; awk -F, -v OFS, {for(i1;i<‌NF;i){$i$i"_suffix"}}1 input.txt-F,&#xff1a;设置输入字段分隔符为逗号&#xff08;,&#xff09;&#xff0c;这将使awk按照逗号分割输入文本。-v OFS‘,’&#xff1a;设置输…

Banana Pi BPI-CM4 评测(计算模块 4),更快性能,旨在替换树莓派CM4

如果您正在寻找可靠的单板计算机来提升您的下一个项目&#xff0c;但无法找到满足您需求的 Raspberry Pi&#xff0c;请看看我是否可以提供帮助。在这篇详细的评论中&#xff0c;我将向您介绍 Banana Pi CM4&#xff0c;这是一款适用于各种任务的多功能且强大的解决方案。从经验…

GitLab开启双端认证并登录GitLab

GitLab开启双端认证并登录GitLab 1.介绍双端认证 单重认证——密码验证&#xff0c;这极其容易出现密码被盗&#xff0c;密码泄露等危险事件。 于是为了提高安全性&#xff0c;就出现了双因素认证&#xff0c;多因素认证。登录的时候不仅要输入账号和密码还需要输入一个验证码…

使用mediapipe训练手指数字识别

mediapipe手指数字识别 本文是从0开始创建一个识别手势的机器学习模型&#xff0c;为了识别手势&#xff0c;采用mediapipe模型&#xff0c;这个模型会返回手指的位置&#xff0c;之后再通过训练一个模型将这些位置分类得到手势 一、导入依赖 import cv2 import numpy as np…

MD-MTSP:成长优化算法GO求解多仓库多旅行商问题MATLAB(可更改数据集,旅行商的数量和起点)

一、成长优化算法GO 成长优化算法&#xff08;Growth Optimizer&#xff0c;GO&#xff09;由Qingke Zhang等人于2023年提出&#xff0c;该算法的设计灵感来源于个人在成长过程中的学习和反思机制。学习是个人通过从外部世界获取知识而成长的过程&#xff0c;反思是检查个体自…

excel绘制折线图或者散点图

一、背景 假如现在通过代码处理了一批数据&#xff0c;想看数据的波动情况&#xff0c;是不是还需要写个pyhon代码&#xff0c;读取文件&#xff0c;绘制曲线&#xff0c;看起来也简单&#xff0c;但是还有更简单的方法&#xff0c;就是直接生成csv文件&#xff0c;csv文件就是…

【MyBatis】MyBatis 3.5+版本报错合集(持续更新)

报错&#xff1a;BindingException 1. org.apache.ibatis.binding.BindingException: Type interface xxx is not known to the MapperRegistry. 2. org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): xxx 解决方案 在pom.xml中添加如下代码…

python json保留汉字原始形式,而不是Unicode编码(Unicode码)(加ensure_ascii=False参数)

文章目录 问题解决办法测试 问题 如图&#xff0c;保存汉字的时候变成unicode码了。。。 代码是这样的&#xff1a; 解决办法 在Python中&#xff0c;可以使用json模块的ensure_ascii参数来控制是否将汉字转换为类似\u5730\u9707的Unicode编码。默认情况下&#xff0c;ensure…

SpringBoot整合第三方 Druid、MybatisPlus、Mybatis

整合第三方技术 整合JUnit Respostory 注解&#xff1a;数据类 1、导入测试对应的starter 2、测试类使用 SpringBootTest 修饰 3、使用自动装配的形式添加要测试的对象 classes的属性 其实主要找的是SpringBootApplication中的SpringBootConfiguration这个注解。也就是配置…

【Qt】QML-02:QQuickView用法

1、先看demo QtCreator自动生成的工程是使用QQmlApplicationEngine来加载qml文件&#xff0c;下面的demo将使用QQuickView来加载qml文件 #include <QGuiApplication> #include <QtQuick/QQuickView>int main(int argc, char *argv[]) {QGuiApplication app(argc,…

螺旋矩阵 II

给你一个正整数 n &#xff0c;生成一个包含 1 到 n2 所有元素&#xff0c;且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;[[1,2,3],[8,9,4],[7,6,5]] 示例 2&#xff1a; 输入&#xff1a;n 1 输出&a…

JGJ59-2011建筑施工安全检查标准

为科学评价建筑施工现场安全生产&#xff0c;预防生产安全事故的发生&#xff0c;保障施工人员的安全和健康&#xff0c;提高施工管理水平&#xff0c;实现安全检查工作的标准化&#xff0c;制定本标准。 本标准适用于房屋建筑工程施工现场安全生产的检查评定。 建筑施工安全…

7.28 作业 QT

手动完成服务器的实现&#xff0c;并具体程序要注释清楚: widget.h: #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTcpServer> //服务器类 #include <QTcpSocket> //客户端类 #include <QMessageBox> //对话框类 #include …