Pong挑战:基于价值、基于策略和演员-评论家强化学习模型的比较
项目背景
随着人工智能和机器学习领域的迅速发展,强化学习作为其中的核心分支,在解决复杂决策问题方面显示出巨大潜力。尤其在游戏领域,不同类型的强化学习算法已被证实能够有效地处理和解决多种挑战。在本项目中,我们将探讨三种主要的强化学习模型——基于价值的Deep Q-Network(DQN)、基于策略的REINFORCE算法以及演员-评论家方法——在经典游戏Pong中的应用和表现。Pong游戏以其简单规则和直观环境,成为评估和比较这些算法的理想平台。
项目目标
本项目旨在通过实现并比较三种不同的强化学习模型来探索Pong游戏的AI实现。具体目标如下:
- 综合理解强化学习模型:通过实践深入理解DQN、REINFORCE以及演员-评论家模型在强化学习中的应用和特点。
- 多模型环境交互:构建并优化Pong游戏环境,实现这三种不同算法与环境的有效交互。
- 网络设计与性能比较:为每种模型设计适当的网络结构,并通过性能比较来确定各自的优劣。
- 模型训练与效果评估:训练每种模型以掌握Pong游戏,并对它们在不同情况下的表现进行全面评估。
- 策略分析与优化:分析各模型在游戏中的策略,并探索优化方法以提升性能。
项目应用
通过本项目,我们期望实现以下应用:
- 多算法技术展示:展示和比较DQN、REINFORCE和演员-评论家模型在游戏AI领域的应用效果,尤其在复杂决策和控制方面。
- 教育与研究价值:为研究不同强化学习算法的学生和研究人员提供一个综合性的案例研究。
- 深入算法分析与改进:通过对比分析在Pong游戏中的应用效果,探讨各算法的优势、局限性及改进方向。
数据集描述
本项目使用的数据集基于经典的Pong游戏,包括以下关键特征和元素,这些将用于训练和评估DQN模型,其他两种强化学习算法也大多采用以下特征,不同的部分会在代码部分讲解:
- action_placeholder:代表AI在游戏中可能采取的动作,例如上移、下移和不动。
- target_placeholder:用于训练过程中的目标值,即预期的输出结果。
- loss:训练过程中的损失函数,用于评估模型的表现。
- checkpoint:模型的保存和加载点,用于记录训练进度。
- game_agent:游戏代理,用于控制游戏环境和生成游戏数据。
- data_deque:用于存储游戏过程中的数据,例如帧、奖励和动作。
- reward:游戏中给予AI的即时反馈,根据其动作和游戏结果给出。
- action:AI在每一帧中采取的实际动作。
- paddle_1_score 和 paddle_2_score:游戏双方的得分情况,用于评估AI的表现。
- action_pred:由神经网络预测的动作。
- num_frames:记录处理的游戏帧数。
- num_games:记录玩过的游戏次数。
- num_win_games:记录AI赢得的游戏次数。
- minibatch:用于训练的小批量数据。
- reward_batch:小批量数据中的奖励值。
项目实现
本项目通过以下关键步骤实现DQN算法:
- 网络构建:通过
createNetwork
函数构建深度卷积神经网络,使用initWeightVariable
和initBiasVariable
初始化网络权重和偏置。 - 训练流程:利用
train
方法对模型进行训练,包括数据的收集、网络的训练和模型的保存。 - 动作决策:在每一游戏帧中,AI根据网络的预测(
action_pred
)来决定其动作。 - 性能评估:通过统计
num_games
和num_win_games
来评估AI的游戏表现。 - 模型优化:通过分析
loss
和reward_batch
来调整和优化模型。
REINFORCE的区别在于,在动作选择的时候,REINFORCE基于策略网络生成的action_probabilities
(在当前状态下采取每个动作的概率)采取动作。
而AC采取动作时基于演员网络生成的action_probabilities
选择动作action_index
;评论家网络则负责评估当前状态state
的价值,即state_val
。这个价值用于评估当前策略的好坏。
模型选择
在本项目中,我们将使用三种不同的强化学习模型:Deep Q-Network(DQN)、REINFORCE以及演员-评论家模型。以下是对每种模型的详细介绍和所需的依赖库。
Deep Q-Network(DQN)(基于价值的强化学习):
DQN是一种结合了深度学习和强化学习的方法,用于处理具有高维度输入空间的复杂任务。在本项目中,DQN通过卷积神经网络来处理游戏的视觉输入,并学习在游戏中做出最优的决策。与传统的强化学习方法相比,DQN能够更有效地处理具有大规模状态空间的问题,如视频游戏。
REINFORCE(基于策略的强化学习):
REINFORCE是一种基于策略的强化学习算法,它直接优化了策略本身,而不是像DQN那样间接优化值函数。这种方法通过梯度上升来优化策略,以最大化累积奖励。REINFORCE适用于解决具有高维度动作空间的问题。
AC(演员-评论家模型):
演员-评论家方法结合了基于值的和基于策略的强化学习的优点。在这种方法中,"演员"负责生成动作,而"评论家"评估这些动作并引导演员的学习。这种双重机制使得演员-评论家方法在稳定性和效率方面都有所提升。
先来通过一段这三个算法实现经典的Pong游戏的视频,展示一下效果以及Pong游戏的界面。Pong游戏简单来说就是控制拍子去完成击球,击球不得分,但是没有击中球,对手加分,游戏中设置获得20分即赢得一局。画面左边的绿色拍子是由强化学习算法控制的,视频如下所示,点击即可观看。
依赖库
1.TensorFlow:
TensorFlow是一个广泛使用的深度学习框架,支持多种操作系统和平台。在本项目中,它被用来构建和训练DQN模型。TensorFlow的灵活性和强大的计算能力使其成为实现复杂神经网络模型的理想选择。
2.NumPy:
NumPy是Python中用于科学计算的基础包,提供了高性能的多维数组对象及相关工具。在本项目中,NumPy用于数据处理和数值计算,如在模型训练过程中处理游戏帧和奖励数据。
3.OpenCV:
OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习软件库。在本项目中,OpenCV用于处理游戏的图像数据,例如通过调整图像大小来准备输入数据。
注意:要想在计算机上运行相关代码,首先需要下载相关库,代码可以在tensorflow2上运行,如只有tensorflow1可以根据代码中的提示内容去更改一些内容即可。并且请确保保安装的库版本相互兼容,特别是请确保Python版本与TensorFlow 2兼容,建议在Python虚拟环境中安装TensorFlow,以避免版本冲突。使用pip install tensorflow
即可配置环境,如果存在网络限制,可以使用镜像源。
DQN代码实现
1.导入必要的库
import os
import cv2
import random
import numpy as np
import tensorflow as tf
import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()# 禁用 TensorFlow 2 行为,以便在 TensorFlow 1 环境中运行,如果在TensorFlow 1 环境中运行删除这行即可
from collections import deque
from gameAPI.agent import gameAgent
2.创建DQN模型类
class DQN():
def __init__(self, config, **kwargs):
self.config = config # 初始化DQN模型配置
3.DQN模型训练代码
这部分action_pred=np.argmax(action_pred)
体现了DQN基于价值的特点,在选取动作时,DQN会选择得分最高的动作
def train(self, session):
# 创建神经网络
net_in, net_out = self.__createNetwork() # 神经网络的输入和输出
# 定义动作和目标的占位符
action_placeholder = tf.placeholder('float', [None, 3]) # 表示游戏中的动作
target_placeholder = tf.placeholder('float', [None]) # 表示预期目标值
# 定义损失函数
loss = tf.reduce_mean(tf.square(target_placeholder - tf.reduce_sum(tf.multiply(net_out, action_placeholder), reduction_indices=1)))
# 定义训练步骤
train_step = tf.train.AdamOptimizer(self.config.lr).minimize(loss)
# 游戏代理和数据队列
game_agent = gameAgent() # 游戏代理,用于与游戏环境交互
data_deque = deque() # 数据队列,用于存储游戏经验
# 主循环:游戏玩法和网络训练
while True:
# random decide#体现了探索
if random.random() <= prob or frame_pre is None:
frame_now, action, reward, terminal, paddle_1_score, paddle_2_score = game_agent.nextFrame(action=None)
frame_now = cv2.resize(frame_now, self.config.frame_size)
# decide by network
else:#体现了利用
action_pred = net_out.eval(feed_dict={net_in: [frame_pre]})
action_pred = np.argmax(action_pred)#这里说明DQN选取动作考虑的是动作得分的高低,即基于价值
if action_pred == 0:
action_pred = [1, 0, 0]
elif action_pred == 1:
action_pred = [0, 1, 0]
elif action_pred == 2:
action_pred = [0, 0, 1]
else:
raise RuntimeError('Hhhhh, your code in net_out for action should be wrong I think...')
frame_now, action, reward, terminal, paddle_1_score, paddle_2_score = game_agent.nextFrame(action=action_pred)
frame_now = cv2.resize(frame_now, self.config.frame_size) / 255.
pass # 省略具体的游戏逻辑和训练过程
4.神经网络构建函数
def __createNetwork(self):#构建DQN模型的神经网络架构,包括卷积层和全连接层,用于特征提取和动作决策。
w_conv1 = self.__initWeightVariable([8, 8, 3, 32])
b_conv1 = self.__initBiasVariable([32])
# ... 神经网络的具体构建过程 ...
pass # 省略具体的网络构建代码
REINFORCE代码实现
由于这部分代码大体上和DQN代码差别不大,所以只展示它们不同的部分,即:
1.REINFORCE模型训练代码
在这个代码段中,action_probabilities
是由策略网络生成的,表示在当前状态下采取每个动作的概率。然后,np.random.choice
函数基于这些概率来随机选择一个动作执行。
这种方法与基于价值的强化学习方法(如DQN)不同。在基于价值的方法中,动作的选择通常是基于预测的最大值函数(或Q值)来选择的,即选择能带来最大预期回报的动作。而在基于策略的方法(如REINFORCE)中,动作的选择是直接由策略网络输出的概率分布决定的。这就意味着即使某个动作的预期回报不是最高的,只要策略网络给出了一定的概率,这个动作仍然有可能被选择。这样的策略允许算法探索非最优动作,有助于找到全局最优解。
def train(self, session):
# create network
net_in, action_probs = self._create_network() # 策略网络输出动作概率,这里体现REINFORCE基于策略的特点:根据动作动作概率生成策略,最后选择的是某个策略
actions_placeholder = tf.placeholder(tf.int32, [None])
rewards_placeholder = tf.placeholder(tf.float32, [None])
# 获取选中动作的概率
action_masks = tf.one_hot(actions_placeholder, 3) # 假设有3个动作
picked_action_probs = tf.reduce_sum(action_probs * action_masks, axis=1)
# 损失函数和训练步骤
loss = -tf.reduce_mean(tf.log(picked_action_probs) * rewards_placeholder)
train_step = tf.train.AdamOptimizer(self.config.lr).minimize(loss)
# game agent
game_agent = gameAgent()
# 训练循环
for episode in range(self.config.num_episodes):
#--忽略部分代码
while not done:
# 获取动作概率
action_probabilities = session.run(action_probs, feed_dict={net_in: [state]})
action_index = np.random.choice(range(3), p=action_probabilities[0])#体现了REINFORCE这种基于策略的强化学习方法的特点
frame_info = game_agent.nextFrame([1 if i == action_index else 0 for i in range(3)])
next_state = frame_info[0] # 提取 next frame
reward = frame_info[2] # 提取 reward
done = frame_info[3] # 提取 terminal
episode_states.append(state)
episode_actions.append(action_index)
episode_rewards.append(reward)
state = next_state
# 计算累积回报
cumulative_rewards = self._compute_cumulative_rewards(episode_rewards)
AC代码实现:
1.神经网络构建函数
不同于DQN和REINFORCE,AC要构建四个神经网络:2个演员网络,2个评论家网络。
def _create_networks(self):
# 输入层
x = tf.placeholder(tf.float32, [None, *self.config.frame_size, 3])
# 共享网络层
conv1 = tf.layers.conv2d(inputs=x, filters=32, kernel_size=[8, 8], strides=4, activation=tf.nn.relu)
conv2 = tf.layers.conv2d(inputs=conv1, filters=64, kernel_size=[4, 4], strides=2, activation=tf.nn.relu)
conv3 = tf.layers.conv2d(inputs=conv2, filters=64, kernel_size=[3, 3], strides=1, activation=tf.nn.relu)
flattened = tf.layers.flatten(conv3)
# 演员网络
fc_actor = tf.layers.dense(flattened, 512, activation=tf.nn.relu)
action_probs = tf.layers.dense(fc_actor, self.config.num_actions, activation=tf.nn.softmax)
# 评论家网络
fc_critic = tf.layers.dense(flattened, 512, activation=tf.nn.relu)
state_value = tf.layers.dense(fc_critic, 1)
return (x, action_probs), (x, state_value)
2.AC模型训练代码
在演员-评论家(Actor-Critic)模型代码中,动作的选择和评价分别由演员(Actor)网络和评论家(Critic)网络来实现。action_probabilities
由演员网络根据当前状态state
计算了采取每个可能动作的概率,随后根据演员网络输出的动作概率,代码随机选择了一个动作action_index
;同样在这一步中,评论家网络评估了当前状态state
的价值,即state_val
。这个价值用于评估当前策略的好坏。
def train(self, session):
# 创建网络
(actor_in, action_probs), (critic_in, state_value) = self._create_networks()
# 设置占位符
actions_placeholder = tf.placeholder(tf.int32, [None])
rewards_placeholder = tf.placeholder(tf.float32, [None])
advantages_placeholder = tf.placeholder(tf.float32, [None])
# 评论家网络的损失函数
critic_loss = tf.reduce_mean(tf.square(rewards_placeholder - state_value))
# 演员网络的损失函数
action_masks = tf.one_hot(actions_placeholder, self.config.num_actions)
picked_action_probs = tf.reduce_sum(action_probs * action_masks, axis=1)
actor_loss = -tf.reduce_mean(tf.log(picked_action_probs) * advantages_placeholder)
# 优化器
actor_optimizer = tf.train.AdamOptimizer(self.config.lr).minimize(actor_loss)
critic_optimizer = tf.train.AdamOptimizer(self.config.lr).minimize(critic_loss)
saver = tf.train.Saver()
session.run(tf.global_variables_initializer())
# game agent
game_agent = gameAgent()
# 训练循环
for episode in range(self.config.num_episodes):
frame_info = game_agent.nextFrame(None)
state = frame_info[0] # 提取 frame
state = cv2.resize(state, (96, 96)) # 调整 state 大小
episode_rewards = []
episode_actions = []
episode_states = []
episode_values = []
done = False
while not done:
# 获取动作概率和状态价值
action_probabilities, state_val = session.run([action_probs, state_value], feed_dict={actor_in: [state], critic_in: [state]})#演员选择动作,决定了action_probabilities;评论家评价动作,决定了state_val
action_index = np.random.choice(range(3), p=action_probabilities[0])
action = [0, 0, 0]
action[action_index] = 1
frame_info = game_agent.nextFrame(action)
next_state = frame_info[0]
next_state = cv2.resize(next_state, (96, 96))
reward = frame_info[2]
done = frame_info[3]
episode_states.append(state)
episode_actions.append(action_index)
episode_rewards.append(reward)
episode_values.append(state_val[0][0])
state = next_state
# 计算累积回报和优势
cumulative_rewards = self._compute_cumulative_rewards(episode_rewards)
advantages = cumulative_rewards - np.array(episode_values)
项目代码下载
作者
arwin.yu.98@gmail.com