《深入浅出强化学习:原理入门》学习笔记(2)

2. 马尔可夫决策过程

2.1 马尔可夫决策过程理论讲解

1.马尔可夫性:

  • 所谓马尔科夫性是指系统的下一个状态st+1 仅与当前状态st 有关,而与以前的状态无关。

  • 定义:状态st 是马尔科夫的,当且仅当P[st+1 |st ]=P[st+1 |s1 ,…,st ]。

    定义中可以看到,当前状态st 其实是蕴含了所有相关的历史信息s1 ,…,st ,一旦当前状态已知,历史信息将会被抛弃。马尔科夫性描述的是每个状态的性质,但真正有用的是如何描述一个状态序列。数学中用来描述随机变量序列的学科叫随机过程。所谓随机过程就是指随机变量序列。若随机变量序列中的每个状态都是马尔科夫的,则称此随机过程为马尔科夫随机过程

2. 马尔可夫过程:

  • 马尔科夫过程的定义:马尔科夫过程是一个二元组(S,P),且满足:S是有限状态集合,P是状态转移概率。状态转移概率矩阵为:
    P = [ P 11 ⋯ P 1 n ⋮ ⋮ ⋮ P n 1 ⋯ P n n ] P=\begin{bmatrix} P_{11}& \cdots & P_{1n} \\ \vdots& \vdots & \vdots \\ P_{n1} & \cdots & P_{nn}\\ \end{bmatrix} P=P11Pn1P1nPnn

3. 马尔可夫决策过程:

  • 马尔科夫决策过程由元组(S,A,P,R,γ)描述,其中:
    S 为有限的状态集;A 为有限的动作集;P 为状态转移概率;R 为回报函数;γ 为折扣因子,用来计算累积回报。
  • 注意,跟马尔科夫过程不同的是,马尔科夫决策过程的状态转移概率是包含动作的,即:
    P s s ′ a = P [ S t + 1 = s ′ ∣ S t = s , A t = a ] P_{ss'}^{a}=P[S_{t+1}=s'|S_{t}=s,A_{t}=a] Pssa=P[St+1=sSt=s,At=a]
  • 强化学习的目标是给定一个马尔科夫决策过程,寻找最优策略。所谓策略是指状态到动作的映射,策略常用符号π表示,它是指给定状态s时,动作集上的一个分布,即 π ( a ∣ s ) = p [ A t = a ∣ S t = s ] \pi(a|s)=p[A_{t}=a|S_{t}=s] π(as)=p[At=aSt=s]

策略的定义是用条件概率分布给出的,可见,强化学习的理论基础,概率论是必不可少的。

2.2 MDP中的概率学基础讲解

1. 随机变量。
随机变量是指可以随机地取不同值的变量,常用小写字母表示。在MDP中随机变量指的是当前的动作,用字母a表示。随机变量可以是离散的也可以是非离散的。
2. 概率分布。
概率分布用来描述随机变量在每个可能取到的值处的可能性大小。离散型随机变量的概率分布常用概率质量函数来描述,即随机变量在离散点处的概率。连续型随机变量的概率分布则用概率密度函数来描述。
3. 条件概率。
策略π(a|s)是条件概率。条件概率是指在其他事件发生时,我们所关心的事件所发生的概率。
4. 期望和方差。

  • 最常用的概率分布也就是最常用的随机策略:

(1)贪婪策略
π ∗ ( a ∣ s ) = { 1 i f a = a r g m a x q ∗ ( s , a ) ( a ∈ A ) 0 o t h e r w i s e \pi*(a|s)=\left\{\begin{matrix} 1 & if&a=argmaxq*(s,a) (a\in A)\\ 0 &otherwise \\ \end{matrix}\right. π(as)={10ifotherwisea=argmaxq(s,a)(aA)
贪婪策略是
一个确定性策略,即只有在使得动作值函数q* (s,a)最大的动作处取概率1,选其他动作的概率为0。
(2)ε-greedy策略
π ∗ ( a ∣ s ) ← { 1 − ε + ε ∣ A ( s ) ∣ i f a = a r g m a x a Q ( s , a ) ε ∣ A ( s ) ∣ i f a ≠ a r g m a x a Q ( s , a ) \pi *(a|s)\leftarrow \left\{\begin{matrix} 1-\varepsilon +\frac{\varepsilon }{\left| A(s)\right|} & if & a= argmax_{a}Q(s,a) \\ \frac{\varepsilon }{\left| A(s)\right|} & if & a\neq argmax_{a}Q(s,a) \\ \end{matrix}\right. π(as){1ε+A(s)εA(s)εififa=argmaxaQ(s,a)a=argmaxaQ(s,a)
ε-greedy策略是强化学习最基本最常用随机策略。其含义是选取使得动作值函数最大的动作的概率为 1 − ε + ε ∣ A ( s ) ∣ 1-\varepsilon +\frac{\varepsilon }{\left| A(s)\right|} 1ε+A(s)ε ,而其他动作的概率为等概率,都为 ε ∣ A ( s ) ∣ \frac{\varepsilon }{\left| A(s)\right|} A(s)ε 。ε-greedy平衡了利用(exploitation)和探索(exploration),其中选取动作值函数最大的部分为利用,其他非最优动作仍有概率为探索部分。
(3)高斯策略:
π θ = μ θ + ε , ε ∼ N ( 0 , σ 2 ) \pi _{\theta} = \mu _{\theta } + \varepsilon,\varepsilon\sim N(0,\sigma ^{2}) πθ=μθ+ε,εN(0,σ2)
其中 μ θ \mu _{\theta } μθ为确定性部分, ε为零均值的高斯随机噪声。高斯策略也平衡了利用和探索,其中利用由确定性部分完成,探索由ε完成。高斯策略在连续系统的强化学习中应用广泛。
(4)玻尔兹曼分布
π ( a ∣ s , θ ) = e x p ( Q ( s , a , θ ) ) Σ b e x p ( h ( s , b , θ ) ) \pi \left ( a|s,\theta \right )= \frac{exp(Q(s,a,\theta ))}{\Sigma _{b}exp(h(s,b,\theta ))} π(as,θ)=Σbexp(h(s,b,θ))exp(Q(s,a,θ))
其中Q(s,a,θ)为动作值函数。该策略的含义是,动作值函数大的动作被选中的概率大,动作值函数小的动作被选中的概率小。

2.3 基于gym的MDP实例讲解

本节我们以机器人找金币为例子,构建其MDP框架。

如图3所示为机器人找金币的例子。该网格世界一共8个状态,其中状态6和状态8是死亡区域,状态7是金币区域。机器人的初始位置为网格世界中的任意一个状态,机器人从初始状态出发寻找金币,机器人每探索一次,进入死亡区域或找到金币,本次探索结束。
《深入浅出强化学习:原理入门》学习笔记(2)_第1张图片

图3. 机器人找金币
在2.1节我们已经定义了一个马尔科夫决策过程。我们知道马尔科夫决策过程由元组(S,A,P,R,γ)来描述。下面我们将机器人找金币的例子建模为MDP。

状态空间:S = {1,2,3,4,5,6,7,8} ;动作空间:A = {东,南,西,北} ;状态转移概率为机器人的运动方程,回报函数为:找到金币的回报为 1,进入死亡区域的回报为-1,机器人在状态1~5之间转换时,回报为0。

下面,我们基于gym构建机器人找金币的gym环境。

# -*- coding: utf-8 -*-
"""
@author: cainiao08ge
@project: py_demo
@file: grid_mdp.py
@description: 
"""
import logging
import numpy
import random
from gym import spaces
import gym

logger = logging.getLogger(__name__)

class GridEnv(gym.Env):
    metadata = {
        'render.modes': ['human', 'rgb_array'],
        'video.frames_per_second': 2
    }

    def __init__(self):

        self.states = [1,2,3,4,5,6,7,8] #状态空间
        self.x=[140,220,300,380,460,140,300,460]
        self.y=[250,250,250,250,250,150,150,150]
        self.terminate_states = dict()  #终止状态为字典格式
        self.terminate_states[6] = 1
        self.terminate_states[7] = 1
        self.terminate_states[8] = 1

        self.actions = ['n','e','s','w']

        self.rewards = dict();        #回报的数据结构为字典
        self.rewards['1_s'] = -1.0
        self.rewards['3_s'] = 1.0
        self.rewards['5_s'] = -1.0

        self.t = dict();             #状态转移的数据格式为字典
        self.t['1_s'] = 6
        self.t['1_e'] = 2
        self.t['2_w'] = 1
        self.t['2_e'] = 3
        self.t['3_s'] = 7
        self.t['3_w'] = 2
        self.t['3_e'] = 4
        self.t['4_w'] = 3
        self.t['4_e'] = 5
        self.t['5_s'] = 8
        self.t['5_w'] = 4

        self.gamma = 0.8         #折扣因子
        self.viewer = None
        self.state = None

    def getTerminal(self):
        return self.terminate_states

    def getGamma(self):
        return self.gamma

    def getStates(self):
        return self.states

    def getAction(self):
        return self.actions
    def getTerminate_states(self):
        return self.terminate_states
    def setAction(self,s):
        self.state=s

    def _step(self, action):
        #系统当前状态
        state = self.state
        if state in self.terminate_states:
            return state, 0, True, {}
        key = "%d_%s"%(state, action)   #将状态和动作组成字典的键值

        #状态转移
        if key in self.t:
            next_state = self.t[key]
        else:
            next_state = state
        self.state = next_state

        is_terminal = False

        if next_state in self.terminate_states:
            is_terminal = True

        if key not in self.rewards:
            r = 0.0
        else:
            r = self.rewards[key]


        return next_state, r,is_terminal,{}
    def _reset(self):
        self.state = self.states[int(random.random() * len(self.states))]
        return self.state
    def render(self, mode='human', close=False):
        if close:
            if self.viewer is not None:
                self.viewer.close()
                self.viewer = None
            return
        screen_width = 600
        screen_height = 400

        if self.viewer is None:
            from gym.envs.classic_control import rendering
            self.viewer = rendering.Viewer(screen_width, screen_height)
            #创建网格世界
            self.line1 = rendering.Line((100,300),(500,300))
            self.line2 = rendering.Line((100, 200), (500, 200))
            self.line3 = rendering.Line((100, 300), (100, 100))
            self.line4 = rendering.Line((180, 300), (180, 100))
            self.line5 = rendering.Line((260, 300), (260, 100))
            self.line6 = rendering.Line((340, 300), (340, 100))
            self.line7 = rendering.Line((420, 300), (420, 100))
            self.line8 = rendering.Line((500, 300), (500, 100))
            self.line9 = rendering.Line((100, 100), (180, 100))
            self.line10 = rendering.Line((260, 100), (340, 100))
            self.line11 = rendering.Line((420, 100), (500, 100))
            #创建第一个骷髅
            self.kulo1 = rendering.make_circle(40)
            self.circletrans = rendering.Transform(translation=(140,150))
            self.kulo1.add_attr(self.circletrans)
            self.kulo1.set_color(0,0,0)
            #创建第二个骷髅
            self.kulo2 = rendering.make_circle(40)
            self.circletrans = rendering.Transform(translation=(460, 150))
            self.kulo2.add_attr(self.circletrans)
            self.kulo2.set_color(0, 0, 0)
            #创建金条
            self.gold = rendering.make_circle(40)
            self.circletrans = rendering.Transform(translation=(300, 150))
            self.gold.add_attr(self.circletrans)
            self.gold.set_color(1, 0.9, 0)
            #创建机器人
            self.robot= rendering.make_circle(30)
            self.robotrans = rendering.Transform()
            self.robot.add_attr(self.robotrans)
            self.robot.set_color(0.8, 0.6, 0.4)

            self.line1.set_color(0, 0, 0)
            self.line2.set_color(0, 0, 0)
            self.line3.set_color(0, 0, 0)
            self.line4.set_color(0, 0, 0)
            self.line5.set_color(0, 0, 0)
            self.line6.set_color(0, 0, 0)
            self.line7.set_color(0, 0, 0)
            self.line8.set_color(0, 0, 0)
            self.line9.set_color(0, 0, 0)
            self.line10.set_color(0, 0, 0)
            self.line11.set_color(0, 0, 0)

            self.viewer.add_geom(self.line1)
            self.viewer.add_geom(self.line2)
            self.viewer.add_geom(self.line3)
            self.viewer.add_geom(self.line4)
            self.viewer.add_geom(self.line5)
            self.viewer.add_geom(self.line6)
            self.viewer.add_geom(self.line7)
            self.viewer.add_geom(self.line8)
            self.viewer.add_geom(self.line9)
            self.viewer.add_geom(self.line10)
            self.viewer.add_geom(self.line11)
            self.viewer.add_geom(self.kulo1)
            self.viewer.add_geom(self.kulo2)
            self.viewer.add_geom(self.gold)
            self.viewer.add_geom(self.robot)

        if self.state is None: return None
        #self.robotrans.set_translation(self.x[self.state-1],self.y[self.state-1])
        self.robotrans.set_translation(self.x[self.state-1], self.y[self.state- 1])



        return self.viewer.render(return_rgb_array=mode == 'rgb_array')

这段代码在书中作者的github中有链接: https://github.com/gxnk/reinforcement-learning-code,可以直接下载,本身代码是没有问题的,但在win和linux中运行效果各不相同(书中是在linux中运行),在每个人的电脑环境中更是存在差异,我在两个系统(Ubuntu和win10)中都有测试并运行,期间碰到了各种问题,可能仅仅是我得问题,在此不一一罗列(主要是bug当时没截图,解决了就不想在测试了),问题均已解决,很多问题可能只是我的问题,欢迎读者讨论交流。

你可能感兴趣的:(强化学习,学习,概率论,机器学习)