目录
动态规划方法有策略迭代和值迭代。都是先对策略进行评估,得到评估后的值函数,再利用该评估的值函数进行策略改进你,如此循环进行策略评估和策略改进。
策略迭代:对当前的策略进行充分的评估,即等到值函数收敛后再进行策略改进。
值迭代:对值函数进行一次评估后立即进行策略改进。
3.1 策略迭代与值迭代
值函数的物理意义是衡量策略的好坏。
强化学习算法最基本的思路是利用汇报改善智能体的策略,而值函数正是汇报的一种体现。基于值函数的强化学习算法的基本思路就是:计算策略Π下的值函数,然后利用值函数改善策略,得到更好的策略。
计算策略下的值函数又称为策略评估,因此强化学习的基本算法是交叉迭代进行策略评估和策略改善。
3.1.1策略迭代算法原理
策略迭代算法便是迭代地实现策略评估和策略改善。
1.策略评估
2.策略改进
有了当前策略的值函数后,可以利用策略改善理论得到一个更好的策略。
策略改善理论->如果存在一个策略,使得在状态s时,使用策略,而后记状态仍然采取策略所得到的行为值函数要>=当前策略在状态s处的状态值函数,那么该策略,不比原来的策略差,甚至更好。
策略改善理论给我们一个启示:只要在状态s处找到一个策略,使得该策略满足
那么如何找?一个很显然的符合该条件的策略为Greedy policy,即贪婪策略,
式3-5表示。当知道当前的策略Π所对应的行为值函数时,贪婪策略是指该状态s处使得行为值函数最大的那个动作。
有了策略评估和策略改善方法,下面总结策略迭代算法,伪代码如下。
第3行:第三行实现策略Π的策略评估。
第4行利用策略改善理论,即利用贪婪策略改善当前的策略,得到第l+1次的策略。
其中第3行的伪代码如下。
由于模型已知,状态为有限个,因此在马尔可夫决策过程中,对策略进行评估的时候,需要对整个状态空间进行遍历,得到整个状态空间中每个状态处的值函数。
3.1.2 值迭代算法原理
值迭代和策略迭代的基本框架相同,包括两个过程,策略评估和策略改善。不同的是,策略迭代在策略评估子程序中要等到值函数收敛之后再进行策略改善。而值迭代不同,值迭代是在策略评估子函数中只要值函数一经改变就直接进入策略改善子程序。
从名字上看,策略迭代是指在算法的整个外循环中策略不断地发生变化,值迭代是指算法在整个外循环中值不断地变化。
值迭代的伪代码如下。
第4行:完成了策略评估和策略改善。
经过第4行后,第l+1次迭代的值函数得到了更新。同时为
3.2 策略迭代和值迭代的代码实现
3.2.1 鸳鸯环境的修改
如图3.5所示,为了渲染值迭代和策略选代算法训练出来的策略效果,我们在第2章介绍的鸯环境类中加人路径渲染项,以便显示我们采用了学到的策略后雄性鸯所走过的路径。
首先我们在鸳鸯环境类中的初始化子函数中声明路径self.path=[],然后在渲染子函数rende0中画出路径点,渲染的方法是利用矩形标识雄性鸳鸯所走过的路径,在矩形框中标识出路径顺序。在PyGame中,我们用pygame.draw.rect()来画矩形,font 来显示路径顺序。
def render()中添加
3.2.2 策略迭代算法代码实现
如3.1.1节所述,策略迭代算法包括策略评估和策略改善。我们先声明一个名为DP_Policy_Iter 的类,该类包括初始化子函数、策略评估子函数、策略改善子函数、策略迭代子函数。接下来我们对代码进行解释。
首先,导人random包和time包,以便生成随机数和调用时间延迟函数。将YuanYangEnv 加载到当前文件中。声明动态规划的策略迭代类DP_policy_Iter。在类的初始化函数中,yuanyang为类的初始化参数,用于调用鸯游戏系统,将鸳鸯游戏系统的状态空间和动作空间赋给当前类的状态和动作,利用v来表示值函数,声明一个数据结构为字典以便存储策略,利用随机函数初始化策略。
import random
import time
from yuanyang_env import YuanYangEnv #同路径下的python文件yuanyang_env.py,YuanYangEnv是里面的类
class DP_Policy_Iter:
def __init__(self,yuanyang):
self.states=yuanyang.states
self.actions=yuanyang.actions
self.v=[0.0 for i in range(len(self.states)+1)]
self.pi=dict()
self.yuanyang=yuanyang
self.gamma=yuanyang.gamma
#初始化策略
for state in self.states:
flag1=0
flag2=0
flag1=yuanyang.collide(yuanyang.state_to_position(state))
flag2=yuanyang.find(yuanyang.state_to_position(state))
if flag1==1 or flag2==1:continue
self.pi[state]=self.actions[int(random.random()*len(self.actions))]
然后,我们就可以利用式(3.3)实现策略评估了。在策略评估中包括两个训练,内层循环遍历状态空间中的每个状态,利用贝尔曼算子更新每个状态处的值函数;外循环则迭代计算整个值函数。我们利用新旧值函数的累积和来控制策略评估是否结束。如果累积和小于1e-6,那么说明值函数的值已经收敛,不再发生变化,此时便退出策略评估程序,具体代码如下:
def policy_evaluate(self):
#策略评估再计算值函数
for i in range(100):
delta=0.0
for state in self.states:
flag1=0
flag2=0
flag1=yuanyang.collide(yuanyang.state_yo_position(state))
flag2=yuanyang.find(yuanyang.state_to_position(state))
if flag1==1 or flag2==1:continue
action=self.pi[state]
s,r,t=yuanyang.transform(state,action)
#更新值
new_v=r+self.gamma*self.v[s]
delta+=abs(self.v[state]-new_v)
#更新值替换原来的值函数
self.v[state]=new_v
if delta<1e-6:
print("策略评估迭代次数",i)
break
有了值函数,就可以利用贪婪策略来对当前的此策略进行改善。再进行策略改善时,需要对状态空间中的每个状态处的策略进行改善,因此外循环是一个状态遍历,在每个状态处,利用当前的值函数找到对应的使之最大的动作即为当前的贪婪策略。
def policy_improve(self):
#更新后的值函数进行策略改善
for state in self.states:
flag1=0
flag2=0
flag1=yuanyang.collide(self.state_to_position(state))
flag2=yuanyang.find(self.state_to_position(state))
if flag1==1 or flag2==1:
continue
a1=self.actions[0]
s,r,t=yuanyang.transform(state,a1)
v1=r+self.gamma*self.v[s]
#找状态s时,采用哪种动作,值函数最大
for action in self.actions:
s,r,t=yuanyang.transform(state,action)
if v1<r+self.gamma*self*v[s]:
a1=action
v1=r+self.gamma*self.v[s]
#贪婪策略,进行更新
self.pi[state]=a1
最后,有了策略评估子函数和策略改善子函数,就可以写策略迭代的算法了,即循环进行策略评估和策略改善,当策略不再改变时,结束策略迭代算法。
至此,就实现了整个迭代算法。
下面写一个主函数,看看写的迭代算法是否有效。首先,实例化一个鸳鸯游戏,然后,将之作为参数传入策略迭代类中实例化一个策略迭代类policy_value,利用该类调用策略迭代子函数policy_iterate()完成策略的学习。
对学到的策略进行测试,初始状态为s=0,当前路径(path)还不存在。将策略迭代中学到的值函数给到游戏中的值函数,以便将值函数渲染出来。
下面是将智能体学习到的策略Π与游戏环境进行交互,并将交互的结果渲染出来,在雌鸟移动的过程中,我们将移动的状态和动作都打印出来。
终端输出
渲染路径如下
3.2.3 值迭代算法代码实现
① 值迭代的实现更容易,同样导入random和tim包,加载YuanYangEnv鸳鸯游戏环境。跟策略迭代一样,在初始化子函数中初始化当前状态空间、动作空间、值函数和随机初始化一个策略。
②将值迭代算法策略评估和策略改善放在一起,首先进行策略评估,然后取贪婪策略。
③跟策略迭代一样,写一个主函数,看看值迭代是不是有效。首先,实例化一个鸳鸯类YuanYang,然后,将其作为参数传入策略迭代类中,实例化一个策略迭代类policy_value,利用该类调用迭代子函数value_iteration(),完成策略的学习。
④对学到的策略进行测试,初始状态为s=0,当前路径(path)还不存在。将策略迭代中学到的值函数给到游戏中的值函数,以便将值函数渲染出来。
⑤下面是将智能体学习到的策略Π与游戏环境进行交互,并将交互的结果渲染出来,在雌鸟移动的过程中,我们将移动的状态和动作都打印出来。
最后的打印结果如下。可以看到值迭代一共进行了14次,比策略迭代的总次数10次要多。但是,值函数只进行了14次策略评估,而策略迭代进行了131次策略评估。由此可见,值迭代的计算量比策略迭代的要小很多,因此算法的效率更高。
本章完整代码
dp_policy_iteration.py
import random
import time
from yuanyang_env import YuanYangEnv
class DP_Policy_Iter:
def __init__(self, yuanyang):
self.states = yuanyang.states
self.actions = yuanyang.actions
self.v = [0.0 for i in range(len(self.states)+1)]
self.pi = dict()
self.yuanyang = yuanyang
self.gamma = yuanyang.gamma
#初始化策略
for state in self.states:
flag1=0
flag2=0
flag1=yuanyang.collide(yuanyang.state_to_position(state))
flag2=yuanyang.find(yuanyang.state_to_position(state))
if flag1==1 or flag2==1: continue
self.pi[state] = self.actions[int(random.random()*len(self.actions))]
def policy_evaluate(self):
#策略评估在计算值函数#高斯塞德尔迭代
for i in range(100):
delta = 0.0
for state in self.states:
flag1 = 0
flag2 = 0
flag1 = yuanyang.collide(yuanyang.state_to_position(state))
flag2 = yuanyang.find(yuanyang.state_to_position(state))
if flag1 == 1 or flag2 == 1: continue
action = self.pi[state]
s, r, t = yuanyang.transform(state, action)
#更新值
new_v = r + self.gamma * self.v[s]
delta += abs(self.v[state] - new_v)
#更新值替换原来的值函数
self.v[state] = new_v
if delta < 1e-6:
print("策略评估迭代次数",i)
break
def policy_improve(self):
#利用更新后的值函数,进行策略改进v
for state in self.states:
flag1 = 0
flag2 = 0
flag1 = yuanyang.collide(yuanyang.state_to_position(state))
flag2 = yuanyang.find(yuanyang.state_to_position(state))
if flag1 == 1 or flag2 == 1: continue
a1 = self.actions[0]
s, r, t = yuanyang.transform(state, a1)
v1 = r + self.gamma * self.v[s]
#找状态s时,采用哪种动作,值函数最大
for action in self.actions:
s, r, t = yuanyang.transform(state, action)
if v1 < r + self.gamma * self.v[s]:
a1 = action
v1 = r + self.gamma * self.v[s]
#贪婪策略,进行更新
self.pi[state] = a1
def policy_iterate(self):
for i in range(100):
#策略评估,变的时v
self.policy_evaluate()
#策略改进
pi_old = self.pi.copy()
#变的是pi
self.policy_improve()
if (self.pi == pi_old):
print("策略改善次数",i)
break
if __name__ == "__main__":
yuanyang = YuanYangEnv()
policy_value = DP_Policy_Iter(yuanyang)
policy_value.policy_iterate()
flag=1
s=0
path = []
#将v值打印出来
for state in range(100):
i = int(state/10)
j = state % 10
yuanyang.value[j,i]=policy_value.v[state]
step_num=0
#将最优路径打印出来
while flag:
# 渲染路径点
path.append(s)
yuanyang.path = path
a=policy_value.pi[s]
print('%d->%s\t'%(s, a))
yuanyang.bird_male_position=yuanyang.state_to_position(s)
yuanyang.render()
time.sleep(0.2)
step_num+=1
s_,r,t=yuanyang.transform(s,a)
if t==True or step_num>200:
flag=0
s=s_
# 渲染最后的路径点
yuanyang.bird_male_position = yuanyang.state_to_position(s)
path.append(s)
yuanyang.render()
while True:
yuanyang.render()
dp_value_iteration.py
import random
import time
from yuanyang_env import YuanYangEnv
import os
class DP_Value_Iter:
def __init__(self, yuanyang):
self.states = yuanyang.states
self.actions = yuanyang.actions
self.v = [ 0.0 for i in range(len(self.states) + 1)]
self.pi = dict()
self.yuanyang = yuanyang
self.gamma = yuanyang.gamma
for state in self.states:
flag1 = 0
flag2 = 0
flag1 = yuanyang.collide(yuanyang.state_to_position(state))
flag2 = yuanyang.find(yuanyang.state_to_position(state))
if flag1 == 1 or flag2 == 1: continue
self.pi[state] = self.actions[int(random.random() * len(self.actions))]
def value_iteration(self):
for i in range(1000):
delta = 0.0
for state in self.states:
flag1 = 0
flag2 = 0
flag1 = yuanyang.collide(yuanyang.state_to_position(state))
flag2 = yuanyang.find(yuanyang.state_to_position(state))
if flag1 == 1 or flag2 == 1: continue
a1= self.actions[int(random.random()*4)]
s, r, t = yuanyang.transform( state, a1 )
#策略评估
v1 = r + self.gamma * self.v[s]
#策略改进
for action in self.actions:
s, r, t = yuanyang.transform( state, action )
if v1 < r + self.gamma * self.v[s]:
a1 = action
v1 = r + self.gamma * self.v[s]
delta+= abs(v1 - self.v[state])
self.pi[state] = a1
self.v[state] = v1
if delta < 1e-6:
print("迭代次数为",i)
break
if __name__ == "__main__":
yuanyang = YuanYangEnv()
policy_value = DP_Value_Iter(yuanyang)
policy_value.value_iteration()
# 将v值打印出来
s = 0
path = []
for state in range(100):
i = int(state / 10)
j = state % 10
yuanyang.value[j, i] = policy_value.v[state]
flag = 1
step_num = 0
# 将最优路径打印出来
while flag:
#渲染路径点
path.append(s)
yuanyang.path = path
a = policy_value.pi[s]
print('%d->%s\t' % (s, a))
yuanyang.bird_male_position = yuanyang.state_to_position(s)
yuanyang.render()
time.sleep(0.2)
# os.system("pause")
step_num += 1
s_, r, t = yuanyang.transform(s, a)
if t == True or step_num > 20:
flag = 0
s = s_
#渲染最后的路径点
yuanyang.bird_male_position = yuanyang.state_to_position(s)
path.append(s)
yuanyang.render()
while True:
yuanyang.render()
下面两个文件参考第2章