机器学习应用——强化学习&课程总结 实例 “自主学习Flappy Bird游戏”(MDP&蒙特卡洛强化学习&Q-learning&DRL&DQN)
Posted 柠檬茶@
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了机器学习应用——强化学习&课程总结 实例 “自主学习Flappy Bird游戏”(MDP&蒙特卡洛强化学习&Q-learning&DRL&DQN)相关的知识,希望对你有一定的参考价值。
前言
本篇将简要介绍强化学习的“自主学习Flappy Bird”实例
读完本篇,你将了解:
一、强化学习
1.相关概念
2.马尔可夫决策过程(MDP)(model base 模型)
3.蒙特卡洛强化学习
4.Q-learning算法
5.深度强化学习(DRL)
6.Deep Q Network(DQN)
二、自主学习Flappy Bird
1.程序基本框架(观察期、探索期、训练期)
2.动作选择模块
3.卷积神经网络-CNN
4.Tensorflow&openCV库
三、关于机器学习专栏的一点总结
1.无监督学习
2.监督学习
3.强化学习。
一、强化学习(增强学习)
1.定义
(1)程序或智能体(agent)通过与环境不断地进行交互学习一个从环境到动作的映射,学习的目标是使累计回报最大化
(2)是一种试错学习,因其在各种状态(环境)下需尽量尝试所有可以选择的动作,通过环境给出的反馈(奖励)来判断动作的优劣,最终获得环境和最优动作的映射关系(策略)
2.举例:吃豆游戏
(1)基本组件
①agent: 大嘴小怪物
②环境:整个迷宫中的所有信息
③奖励:agent每走一步,需要扣除1分,吃掉小球得10分,吃掉敌人得200分,被吃掉游戏结束。
④动作:在每种状态下,agent能够采用的动作,比如上下左右移动。
⑤策略:在每种状态下,采取最优的动作。
⑥学习目标:获得最优的策略,以使累计奖励最大(即Score )。
(2)图示
3.马尔可夫决策过程(MDP)(model base 模型)
(1)马尔可夫决策过程(MarkovDecision Process)通常用来描述一个强化学习问题。
(2)智能体agent根据当前对环境的观察采取动作获得环境的反馈,并使环境发生改变的循环过程。
(3)基本元素
①s∈S:有限状态state集合,s表示某个特定状态
②a∈A:有限动作action集合,a表示某个特定动作
③T(S,a,S’)~Pr(s’|s,a):状态转移模型,根据当前状态s和动作a预测下一个状态s,Pr表示从s采取行动a转移到s‘的概率
④R(s,a):表示agent采取某个动作后的即时奖励,其他表现形式:R(s,a,s’),R(s)
⑤Policy π(s)->a:根据当前state来产生action,可表现为a=π(s)或π(a|s)=P(a|s),后者表示某种状态下执行某个动作的概率
(4)值函数
①状态值函数v表示执行策略π能得到的累计折扣奖励
整理后得
②状态动作值函数Q(s,a)表示在状态s下执行动作a能得到的累计折扣奖励
整理后得
③最优值函数
(5)最优控制
在得到最优值函数之后,可以通过值函数的值得到状态s时应该采取的动作a
4.蒙特卡洛强化学习
(1)免模型学习
①在现实的强化学习任务中,环境的转移概率、奖励函数往往很难得知,甚至很难得知环境中有多少状态。
②若学习算法不再依赖于环境建模,则称为免模型学习,蒙特卡洛强化学习就是其中的一种。
(2)蒙特卡洛强化学习使用多次采样,然后求取平均累计奖赏作为期望累计奖赏的近似。
<s0,a0,s1,a1,r2,…,S(T-1),a(T-1),rT,ST>
(3)直接对状态动作值函数Q(s,a)进行估计,每采样一条轨迹,就根据轨迹中的所有“状态-动作”利用下面的公式对来对值函数进行更新。
(4)贪心策略
①每次采样更新完所有的“状态-动作”对所对应的Q(s,a),就需要更新采样策略n。但由于策略可能是确定性的,即一个状态对应一个动作,多次采样可能获得相同的采样轨迹,因此需要借助ε贪心策略
②如图
5.Q-learning算法
(1)蒙特卡洛强化学习算法需要采样一个完整的轨迹来更新值函数,效率较低,此外该算法没有充分利用强化学习任务的序贯决策结构。
(2)Q-learning算法结合了动态规划与蒙特卡洛方法的思想,使得学习更加高效。
(3)过程
①假设对于状态动作对(s,a)基于t次采样估算出其值函数为∶
②在进行t+1次采样后,依据增量更新得到:
③然后,将,替换成系数α(步长),得到:
④以γ折扣累计奖赏为例∶
⑤则值函数的更新方式如下:
(4)流程
注:请参考周志华老师《机器学习》一书
6.深度强化学习(DRL)
(1)传统强化学习:真实环境中的状态数目过多,求解困难。
(2)深度强化学习:将深度学习和强化学习结合在一起,通过深度神经网络直接学习环境(或观察)与状态动作值函数Q(s,a)之间的映射关系,简化问题的求解。
7.Deep Q Network(DQN)
(1)介绍
①是将神经网络(neural network)和Q-learning结合,利用神经网络近似模拟函数Q(s,a)
②输入是问题的状态(e.g.,图形),输出是每个动作a对应的Q值
③然后依据Q值大小选择对应状态执行的动作,以完成控制。
(2)神经网络的参数︰应用监督学习完成
(3)DQN学习过程
①状态s输入,获得所有动作对应的Q值Q(s,a)
②选择对应Q值最大的动作a’并执行
③执行后环境发生改变,并能够获得环境的奖励r
④利用奖励r更新Q(s,a’)——强化学习
⑤利用新的Q(s,a’)更新网络参数—监督学习
(4)讲解
二、自主学习Flappy Bird游戏项目分析
1.“自主学习Flappy Bird游戏”实例介绍
(1)深度强化学习
①2013年,Deep Mind团队在NIPS上发表《PlayingAtari with Deep Reinforcement Learning》一文,在该文中首次提出Deep Reinforcement Learning—词
②并且提出DQN(DeepQ-Network)算法,实现了从纯图像输入完全通过学习来玩Atari游戏。
(2)Atari游戏
①接下来的学习中,我们将通过python实现的一个开源的自主学习flappy bird游戏的小项目,更细致的讲解有关深度强化学习的实例应用。
②Flappy Bird游戏:由来自越南的独立游戏开发者开发的一款游戏。在游戏中,玩家需要点击屏幕控制小鸟跳跃,跨越由各种不同长度水管组成的障碍。
③Flappy Bird游戏和Atari游戏的操作方法很相似,同样可以使用DQN进行学习。
(3)自主学习Flappy Bird游戏
①目标:使用深度强化学习方法自主学习Flappy Bird游戏策略,达到甚至超过人类玩家的水平。
②技术路线:Deep Q-Network
③使用工具:tensorflow + pygame + cv2
2.Flappy Bird自主学习程序基本框架
(1)程序与模拟器交互
①训练过程也就是神经网络(agent)不断与游戏模拟器(Environment)进行交互
②通过模拟器获得状态,给出动作,改变模拟器中的状态,获得反馈,依据反馈更新策略的过程
(2)训练过程
①观察期(OBSERVE):程序与模拟器进行交互,随机给出动作,获取模拟器中的状态,将状态转移过程存放在D(Replay Memory)中
②探索期(EXPLORE):程序与模拟器交互的过程中,依据Replay Memory中存储的历史信息更新网络参数,并随训练过程降低随机探索率ε
③训练期(TRAIN):ε已经很小,不再发生改变,网络参数随着训练过程不断趋于稳定。
(3)整体框架——观察期
①打开游戏模拟器,不执行跳跃动作,获取游戏的初始状态
②根据ε贪心策略获得一个动作(由于神经网络参数也是随机初始化的,在本阶段参数也不会进行更新,所以统称为随机动作),并根据迭代次数减小ε的大小
③由模拟器执行选择的动作,能够返回新的状态和反馈奖励
④将上一状态s ,动作a,新状态s ‘,反馈r组装成( s , a , s’ ,r)放进Replay Memory中用作以后的参数更新
⑤根据新的状态s ',根据ε贪心策略选择下一步执行的动作,周而复始,直至迭代次数到达探索期
(4)整体框架——探索期
探索期与观察期的唯一区别在于会根据抽样对网络参数进行更新。
①迭代次数达到一定数目,进入探索期,根据当前状态s,使用ε贪心策略选择一个动作(可以是随机动作或者由神经网络选择动作),并根据迭代次数减小ε的值
②由模拟器执行选择的动作,能够返回新的状态和反馈奖励
③将上一状态s ,动作a,新状态s’,反馈r组装成( s , a , s’ ,r)放进Replay Memory中用作参数更新
④从Replay Memory中抽取一定量的样本,对神经网络的参数进行更新
⑤根据新的状态s ',根据s贪心策略选择下一步执行的动作,周而复始,直至迭代次数到达训练期
(5)整体框架——训练期
迭代次数达到一定数目,进入训练期,本阶段跟探索期的过程相同,只是在迭代过程中不再修改ε的值
(6)模拟器
①游戏模拟器
1)使用Python的Pygame模块完成的FlappyBird游戏程序
2)为了配合训练过程,在原有的游戏程序基础上进行了修改。
3)参考以下网址查看游戏源码:https://github.com/sourabhv/FlapPyBird
②图示通过模拟器获取游戏的画面。
③训练过程中使用连续4帧图像作为一个状态s ,用于神经网络的输入。
(7)动作选择模块
①动作选择模块︰为s贪心策略的简单应用,以概率ε随机从动作空间A中选择动作,以1-ε概率依靠神经网络的输出选择动作:
②如图
、
③DQN∶用卷积神经网络对游戏画面进行特征提取,这个步骤可以理解为对状态的提取。
(8)卷积神经网络-CNN
展示卷积操作
①卷积核∶这里的卷积核指的就是移动中3*3大小的矩阵。
②卷积操作∶使用卷积核与数据进行对应位置的乘积并加和,不断移动卷积核生成卷积后的特征。
③池化操作∶对卷积的结果进行操作。最常用的是最大池化操作,即从卷积结果中挑出最大值,如选择一个2*2大小的池化窗口(操作如图示):
④卷积神经网络:把Image矩阵中的每个元素当做一个神经元,那么卷积核就相当于输入神经元和输出神经元之间的链接权重,由此构建而成的网络被称作卷积神经网络。
⑤Flappy Bird-深度神经网络
本实验中使用的深度神经网络结构就是多个卷积操作和池化操作的累加。
1)对采集的4张原始图像进行预处理,得到80804大小的矩阵;
2)使用32个884大小步长4的卷积核对以上矩阵进行卷积,得到202032大小的矩阵;
注:在tensorflow中使用4维向量表示卷积核[输入通道数,高度,宽度,输出通道数],对应于上面的[4,8,8,32],可以理解为32个884大小的卷积核;
3)对以上矩阵进行不重叠的池化操作,池化窗口为22大小,步长为2,得到101032大小的矩阵;
4)使用64个4432大小步长为2的卷积核对以上矩阵进行卷积,得到5564的矩阵;
5)使用64个3364大小步长为1的卷积核对以上矩阵进行卷积,得到5564的矩阵;
6)将输出的5564大小的数组进行reshape,得到11600大小的矩阵;
7)在之后添加一个全连接层,神经元个数为512;
8)最后一层也是一个全连接层,神经元个数为2,对应的是就是两个动作的动作值函数;
⑥通过获得输入s,神经网络就能够:
1)输出Q(s,a1)和Q(s,a2)比较两个值的大小,就能够评判采用动作a1和a2的优劣,从而选择要采取的动作
2)在选择并执行完采用的动作后,模拟器会更新状态并返回回报值,然后将这个状态转移过程存储进D,进行采样更新网络参数。
(9)网络参数更新
①从D中抽取更新使用的样本;
②利用神经网络计算maxQ(s2, a’)和Qold(s1,a1);
③计算Qnew(s1,a1),并通过Qnew(s1,a1)和Qold(s1,a1)更新网络参数
3.相关库的介绍及安装
(1)相关库的简介
①TensorFlow
1)是谷歌2015年开源的一个人工智能学习系统。主要目的是方便研究人员开展机器学习和深度神经网络方面的研究,目前这个系统更具有通用性,也可广泛用于其他计算领域。
2)Tensorflow支持多种前端语言,包括Python(Python也是tensorflow支持最好的前端语言),因此一般大家利用python实现对tensorflow的调用。
②OpenCV
1)是一个开源的跨平台的计算机视觉库,实现了大量的图像处理和计算机视觉方面的通用算法。
2)本实验采用openev对采集的游戏画面进行预处理。
③Pygame
1)是一个跨平台的模块,专为电子游戏设计。
2)Pygame相当于是一款游戏引擎,用户无需编写大量的基础模块,而只需完成游戏逻辑本身就可以了。
3)本实验的模拟器根据pygame实现
(2)相关库的安装
①TensorFlow:在确保网络通畅的情况下,打开windows的DoS命令行窗口,使用pip命令安装:
pip install tensorflow
②OpenCV库安装:
1)在下载地址中找到opencv的相关下载链接,依据Python的具体版本下载对应的文件。
2)找到下载的文件的路径,打开windows的DOS命令行窗口,使用如下命令:
pip install opencv_python-3.2.0-cp35-cp35m-win_amd64.whl
3)如果未提示任何安装错误,则说明安装成功。
③Pygame库安装
1)在确保网络通畅的情况下,打开windows的DOS命令行窗口,使用如下命令:
pip install pygame
(3)测试
打开windows的DOS命令行窗口,进入Python命令行模式,导人包测试,如无错误,则说明安装成功
4.项目实战
(1)tensorflow基本使用
①理解TensorFlow:
1)使用图(graph)来表示计算任务;
2)在被称之为会话(Session)的上下文(context)中执行图;
3)使用tensor(张量)表示数据;
4)通过变量(Variable)维护状态;
5)使用feed和fetch可以为任意的操作(arbitrary operation)赋值或者从其中获取数据。
②TensorFlow是一个编程系统,使用图来表示计算任务。图中的节点被称作op (Operation ) , op可以获得0个或多个tensor,产生0个或多个tensor。
③每个tensor是一个类型化的多维数组。
④例如:可以将一组图像集表示成一个四维的浮点数组,四个维度分别是[batch,height,weight,channels]。
⑤图(graph)描述了计算的过程。为了进行计算,图必须在会话中启动,会话负责将图中的op分发到CPU或GPU上进行计算,然后将产生的tensor返回。在Python中,tensor就是numpy.ndarray对象。
⑥TensorFlow程序通常被组织成两个阶段:构建阶段和执行阶段。
1)构建阶段:op的执行顺序被描迹成一个图
2)执行阶段:使用会话执行图中的op。
3)例如:通常在构建阶段创建一个图来表示神经网络,在执行阶段反复执行图中的op训练神经网络。
import tensorflow as tf
mat1 = tf.constant([[3.,3.]]) #创建一个1*2的矩阵
mat2 = tf.constant([[2.,2.]]) #创建一个2*1的矩阵
product = tf.matmul(mat1,mat2) #创建op执行两个矩阵的算法
sess = tf.session() #启动默认图
res = sess.run(product) #在,默认图中执行op操作
print(res)
sess.close()
⑦交互式会话(InteractiveSession):
为了方便使用Ipython之类的Python交互环境,可以使用交互式会话(InteractiveSession)来代替Session,使用类似Tensor.run()Operation.eval()来代替Session.run(),避免使用一个变量来持有会话。
import tensorflow as tf
sess = tf.InteractiveSession #创建交互式会话
a = tf.Variable([1.0,2.0]) #创建变量数组
b = tf.constant([3.0,4.0]) #创建常量数组
sess.run(tf.global_variables_initializer())#变量初始化
res = tf.add(a,b)#创建加法操作
print(res.eval())#执行操作并输出结果
(2)Feed操作:
①前面的例子中,数据均以变量或常量的形式进行存储。
②Tensorflow还提供了Feed机制,该机制可以临时替代图中任意操作中的tensor。
③最常见的用例是使用tf.placeholder()创建占位符,相当于是作为图中的输人
④然后使用Feed机制向图中占位符提供数据进行计算,具体使用方法见接下来的样例。
import tensorflow as tf
sess = tf.InteractiveSession()#创建交互式会话
input1 = tf.placeholder(tf.float32)#创建占位符
input2 = tf.placeholder(tf.float32)
res = tf.mul(input1,input2)#创建乘法操作
res.eval(feed_dict=input1:[7.],input2:[2.])#求值
(3)自主学习flappy bird实例程序编写
①建立工程,导入相关工具包
②设置超参数
③创建深度神经网络
④训练深度神经网络
⑤开启整个训练过程(创建交互式会话)
#建立工程,导入相关工具包
import cv2 #导入opencv
import sys
import tensorflow as tf
sys.path.append("game/") #添加game目录到系统环境变量
from pygame import wrapped_flappy_bird as game#加载游戏
import random #加载随机模块
import numpy as np
from collections import deque#导入双端队列
#设置超参数
GAME = 'bird'#设置游戏名称
ACTIONS = 2#设置游戏动作数目
GAMMA = 0.99 #设置增强学习更新公式中的累计折扣因子
OBSERVE = 10000 #观察期,1万次迭代(随机指定动作获得d)
EXPLORE = 2000000 #探索期
FINAL_EPSILON = 0.0001#设置ε的最小值
INITIAL_EPSILON = 0.1#设置ε贪心策略中ε的初始值
REPLAY_MEMORY = 50000#设置容量
BATCH = 32 #设置每次网络参数更新时用的样本数目
FRAME_PER_ACTION = 1 #设置几帧图像进行一次动作
# 创建深度神经网络
#首先定义一个函数用于生成形状为shape的张量(高维数组)
def weight_variable(shape):
initial = tf.truncated_normal(shape,stddev=0.01)#张量中的初始化数值服从正态分布,且方差为0.01
return tf.Variable(initial)
#生成另一个函数用于生成偏置项,初始值为0.01
def bias_variable(shape):
initial = tf.constant(0.01,shape = shape)
return tf.Variable(initial)
#定义卷积操作,实现卷积核W在数据x上卷积操作
def conv2d(x,W,stride):
return tf.nn.conv2d(x,W,strides=[1,stride,stride,1],padding = "SAME")#strides为卷积核的移动步长,padding为卷积的一种模式,参数为same表示滑动范围超过边界时
#定义池化函数,调用max_pool执行最大池化操作,大小为2*2,stride步长为2
def max_pool_2x2(x):
return tf.nn.max_pool(x,ksize=[1,2,2,1],strides=[1,2,2,1],padding="SAME")
# 创建深度神经网络之定义网络结构(具体参数可回顾之前的框架)
def createNetwork(): #定义深度神经网络的参数和偏置
#第一个卷积层
W_conv1 = weight_variable([8,8,4,32])
b_conv1 = bias_variable([32])
# 第二个卷积层
W_conv2 = weight_variable([4,4,32,64])
b_conv2 = bias_variable([64])
# 第三个卷积层
W_conv3 = weight_variable([3,3,64,64])
b_conv3 = bias_variable([64])
#第一个全连接层
W_fc1 = weight_variable([1600,512])
b_fc1 = bias_variable([512])
# 第二个全连接层
W_fc2 = weight_variable([512,ACTIONS])
b_fc2 = bias_variable([ACTIONS])
#输入层
s = tf.placeholder("float",[None,80,80,4])#placeholder用于占位,可用作网络的输入
#隐藏层(对各层进行连接)
h_conv1 = tf.nn.relu(conv2d(s,W_conv1,4) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1)
h_conv2 = tf.nn.relu(conv2d(h_pool1,W_conv2,2) + b_conv2)
h_conv3 = tf.nn.relu(conv2d(h_conv2, W_conv3, 1) + b_conv3)
h_conv3_flat = tf.reshape(h_conv3,[-1,1600])
h_fc1 = tf.nn.relu(tf.matmul(h_conv3_flat,W_fc1)+b_fc1)
#输出层
readout = tf.matmul(h_fc1,W_fc2)+b_fc2
#训练深度神经网络
def tarinNetwork(s,readout,h_cf1,sess):
#定义损失函数
a = tf.placeholder("float,"[None,ACTIONS])
y = tf.placeholder("float,"[None])
readout_action = tf.reduce_sum(tf.multiply(readout,a),reduction_indices=1)
cost = tf.reduce_mean(tf.square(y-readout_action))
train_step = tf.train.AdamOptimizer(1e-6).minimize(cost)
#开启游戏模拟器,会打开一个窗口,实时显示游戏的信息
game_state = game.GameState()
#创建双端队列用于存放relay memory
D = deque()
#获取游戏的初始状态,设置动作为不执行跳跃,并将初始状态修改成80*80*4大小
#此处需用OpenCV对图像进行预处理
do_nothing = np.zeros(ACTIONS)
do_nothing[0] = 1 #不执行跳跃
x_t,r_0,terminal = game_state.frame_step(do_nothing)
x_t = cv2.cvtColor(cv2.resize(x_t,(80,80)),cv2.COLOR_BGR2GRAY)
ret,x_t = cv2.threshold(x_t,1,255,cv2.THRESH_BINARY) #将像素值大于等于1的像素点处理成255,也就是黑白二值图
s_t = np.stack((x_t,x_t,x_t,x_t),axis=2) #构造4阵的原始输入
#用于加载或保存网络参数
saver = tf.train.Saver()
sess.run(tf.initializer_all_variables())
checkpoint = tf.train.get_checkpoint_state("saved_networks")
if checkpoint and checkpoint.model_checkpoint_path:
saver.restore(sess,checkpoint.model_checkpoint_path)
print("Successfully loaded:",checkpoint.model_checkpoint_path)
else:
print("could not find old network weights")
#开始训练
epsilon = INITIAL_EPSILON
t = 0
while "flappy bird" !="angry bird":
#使用epsilon贪心策略选择一个动作
readout_t = readout.eval(feed_dict=s:[s_t])[0]
a_t = np.zeros([ACTIONS])
action_index = 0
if t%FRAME_PER_ACTION==0:
#执行一个随机动作
if random.random()<= epsilon:
print("---------Random Action---------")
action_index = random.randrange(ACTIONS)
a_t[random.randrange(ACTIONS)]=1
#由神经网络计算的Q(s,a)值选择对应的动作
else:
action_index = np.argmax(readout_t)
a_t[action_index]=1
else:
a_t[0] = 1 #不执行跳跃动作
#随游戏的进行,不断降低epsilon,减少随机动作
if epsilon>FINAL_EPSILON and t>OBSERVE:
epsilon-=(INITIAL_EPSILON-FINAL_EPSILON)/EXPLORE
#执行选择的动作,并获得下一状态及回报
x_t1_colored,r_t,terminal = game_state.frame_step(a_t)
x_t1 = cv2.cvtColor(cv2.resize(x_t1_colored,(80,80)),cv2.COLOR_BGR2GRAY)
ret,x_t1 = cv2.threshold(x_t1,1,255,cv2.THRESH_BINARY)
x_t1 = np.reshape(x_t1,(80,80,1))
s_t1 = np.append(x_t1,s_t[:,:,:3],axis=2)
#将状态转移过程存储到D中,用于更新参数时采样
D.append((s_t,a_t,r_t,s_t1,terminal))
if len(D)>REPLAY_MEMORY:
D.popleft()
#过了观察期,才会进行网络参数的更新
if t>OBSERVE:
# 从D中随机采样,用于参数更新
minibatch = random.sample(D,BATCH)
# 分别将当前状态、采取的动作、获得的回报、下一状态分组存放
s_j_ba以上是关于机器学习应用——强化学习&课程总结 实例 “自主学习Flappy Bird游戏”(MDP&蒙特卡洛强化学习&Q-learning&DRL&DQN)的主要内容,如果未能解决你的问题,请参考以下文章
《机器学习-原理算法与应用》配套PPT第四部分(深度学习概论自动编码器强化学习聚类算法半监督学习等)