强化学习之Dyna-Q算法——以悬崖漫步环境为例

avatar
作者
猴君
阅读量:0

0.介绍

在强化学习中模型通常指与智能体交互的环境模型,即对环境的状态转移概率和奖励函数进行建模,强化学习依据是否具有环境模型分为基于模型的强化学习(model-based reinforcement learning)以及无模型的强化学习(model-free reinforcement learning)两种。无模型强化学习根据智能体与环境交互采样到的数据直接进行策略提升或者价值估计。基于模型的强化学习中模型事前知道,也可以根据智能体与环境交互采样得到的数据学习得到,然后使用这个模型帮助我们进行策略提升或价值估计。Dyna-Q就是经典的基于模型的强化学习算法,它的环境模型是通过采样数据估计得到的。

强化学习有两个重要评价指标:一个是算法收敛后的策略在初始状态下的期望回报,另一个是样本复杂度,即算法达到收敛结果需要在真实环境中采样的样本数量。基于模型强化学习由于具有一个环境模型,智能体可以额外与环境进行交互,对真实环境中样本的需求量往往减少,因此通常比无模型强化学习算法具有更低的样本复杂度,但是由于环境模型可能不准确,无法完全代替真实环境,因此基于模型强化学习收敛后其策略的期望回报可能不如无模型强化学习。 

Dyna-Q算法作为经典基于模型强化学习算法,使用一种称为Q-planning方法来基于模型生成模拟数据,然后用模拟数据联同真实数据进行策略改进。Q-planning每次选取一个曾经到访的状态s以及采取一个曾经在该状态s下执行过的动作a,通过模型得到转移后的状态s'以及奖励r,并根据这个模拟数据(s,a,r,s')采用Q-learning更新方法更新动作价值函数。

每次与环境进行交互执行一次Q-learning后Dyna-Q会执行n次Q-planning,其中Q-planning次数N是事前可以选择的超参数,当其为0时就是普通Q-learning。本Dyna-Q执行在离散并确定的环境中,故当看到一条经验数据(s,a,r,s')时可以直接对模型做出更新,即M(s,a)←r,s'。  

1.导入相关库

import numpy as np import matplotlib.pyplot as plt from tqdm import tqdm import random import time 

2.悬崖漫步环境实现环节

class cliffwalking():     def __init__(self,colnum,rownum,initx,inity,stepr,cliffr):         self.colnum=colnum         self.rownum=rownum         self.initx=initx         self.inity=inity         self.stepr=stepr         self.cliffr=cliffr         self.disaster=list(range((self.rownum-1)*self.colnum+1,self.rownum*self.colnum-1))         self.end=[self.colnum*self.rownum-1]     def step(self,action):         change=[[0,-1],[0,1],[-1,0],[1,0]]         self.x=min(self.colnum-1,max(0,self.x+change[action][0]))         self.y=min(self.rownum-1,max(0,self.y+change[action][1]))         nextstate=self.x+self.y*self.colnum         reward=self.stepr         done=False         if nextstate in self.disaster:             done=True             reward=self.cliffr         if nextstate in self.end:             done=True         return nextstate,reward,done     def reset(self):         self.x=self.initx         self.y=self.inity         return self.x+self.y*self.colnum

3.Dyna-Q算法实现

在Q-learning算法代码基础上进行修改实现Dyna-Q算法代码,修改内容有加入环境模型,环境模型采用字典表示,每次在真实环境中收集到新的数据,就把它加入字典,根据字典的性质,若该数据本身存在于字典中,就不会再一次进行添加,在Dyna-Q的更新中,执行完Q-learning后会立即执行Q-plaaning。

class DynaQ():     """ Dyna-Q算法"""     def __init__(self,colnum,rownum,alpha,gamma,epsilon,n_planning,actionnum=4):         self.colnum=colnum         self.rownum=rownum         self.actionnum=actionnum         self.alpha=alpha         self.gamma=gamma         self.epsilon=epsilon         self.n_planning=n_planning         self.qtable=np.zeros([self.colnum*self.rownum,self.actionnum])         self.model=dict()     def takeaction(self,state):         if np.random.random()<self.epsilon:             action=np.random.randint(self.actionnum)         else:             action=np.argmax(self.qtable[state])         return action     def q_learning(self,s0,a0,r,s1):         tderror=r+self.gamma*self.qtable[s1].max()-self.qtable[s0,a0]         self.qtable[s0,a0]+=self.alpha*tderror     def model_learning(self,s0,a0,r,s1):         self.model[(s0,a0)]=r,s1         for _ in range(self.n_planning):             (s,a),(r0,s_)=random.choice(list(self.model.items()))             self.q_learning(s,a,r0,s_)     def update(self,s0,a0,r,s1):         self.q_learning(s0,a0,r,s1)         self.model_learning(s0,a0,r,s1)

4.Dyna-Q算法在悬崖漫步环境中的训练函数

def DynaQ_cliffwalking(n_planning):     colnum=12     rownum=4     initx=0     inity=rownum-1     stepr=-1     cliffr=-100     epsilon=0.1     alpha=0.1     gamma=0.9     num_episodes=300     pbarnum=10     printreturnnum=10     returnlist=[]     env=cliffwalking(colnum=colnum,rownum=rownum,initx=initx,inity=inity,stepr=stepr,cliffr=cliffr)     agent=DynaQ(colnum=colnum,rownum=rownum,alpha=alpha,gamma=gamma,epsilon=epsilon,n_planning=n_planning,actionnum=4)     for i in range(pbarnum):         with tqdm(total=int(num_episodes/pbarnum),desc='Iteration %d'% i) as pbar:             for episode in range(int(num_episodes/pbarnum)):                 episodereturn=0                 state=env.reset()                 done=False                 while not done:                     action=agent.takeaction(state)                     nextstate,reward,done=env.step(action)                     episodereturn+=reward                     agent.update(state,action,reward,nextstate)                     state=nextstate                 returnlist.append(episodereturn)                 if (episode+1)% printreturnnum==0:                     pbar.set_postfix({'episode':'%d'%(num_episodes/pbarnum*i+episode+1),'return':'%.3f'%(np.mean(returnlist[-printreturnnum:]))})                 pbar.update(1)     return returnlist

5.结果可视化代码

np.random.seed(100) random.seed(100) n_planninglist=[0,2,20] for n_planning in n_planninglist:     print('Q-planning步数为:%d'% n_planning)     time.sleep(0.5)     returnlist=DynaQ_cliffwalking(n_planning)     episodelist=list(range(len(returnlist)))     plt.plot(episodelist,returnlist,label=str(n_planning)+'planning steps') plt.xlabel('Episodes') plt.ylabel('Returns') plt.title('Dyna-Q on {}'.format('Cliff Walking')) plt.legend() plt.show()

通过调整参数,可以观察Q-planning步数对结果的影响。若Q-planning步数为0,Dyna-Q算法退化为Q-learning算法。 

6.结果展示

 Q-planning步数为:0
Iteration 0: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████| 30/30 [00:00<00:00, 676.85it/s, episode=30, return=-151.900]
Iteration 1: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████| 30/30 [00:00<00:00, 699.35it/s, episode=60, return=-103.200]
Iteration 2: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████| 30/30 [00:00<00:00, 1203.27it/s, episode=90, return=-73.000]
Iteration 3: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████| 30/30 [00:00<00:00, 1305.50it/s, episode=120, return=-53.700]
Iteration 4: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████| 30/30 [00:00<00:00, 1583.87it/s, episode=150, return=-50.500]
Iteration 5: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████| 30/30 [00:00<00:00, 1812.24it/s, episode=180, return=-56.600]
Iteration 6: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████| 30/30 [00:00<00:00, 2032.75it/s, episode=210, return=-65.200]
Iteration 7: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████| 30/30 [00:00<00:00, 2313.12it/s, episode=240, return=-73.600]
Iteration 8: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████| 30/30 [00:00<00:00, 2148.06it/s, episode=270, return=-31.300]
Iteration 9: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████| 30/30 [00:00<00:00, 2725.88it/s, episode=300, return=-30.800]

 Q-planning步数为:2
Iteration 0: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████| 30/30 [00:00<00:00, 375.86it/s, episode=30, return=-85.800]
Iteration 1: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████| 30/30 [00:00<00:00, 653.92it/s, episode=60, return=-42.900] 
Iteration 2: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████| 30/30 [00:00<00:00, 790.74it/s, episode=90, return=-42.600] 
Iteration 3: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████| 30/30 [00:00<00:00, 1036.12it/s, episode=120, return=-30.500] 
Iteration 4: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████| 30/30 [00:00<00:00, 1220.46it/s, episode=150, return=-16.100] 
Iteration 5: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████| 30/30 [00:00<00:00, 1367.80it/s, episode=180, return=-25.500] 
Iteration 6: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████| 30/30 [00:00<00:00, 1582.64it/s, episode=210, return=-33.500] 
Iteration 7: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████| 30/30 [00:00<00:00, 1507.98it/s, episode=240, return=-42.600]
Iteration 8: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████| 30/30 [00:00<00:00, 1880.04it/s, episode=270, return=-50.000] 
Iteration 9: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████| 30/30 [00:00<00:00, 1833.01it/s, episode=300, return=-69.000]

 Q-planning步数为:20
Iteration 0: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████| 30/30 [00:00<00:00, 153.51it/s, episode=30, return=-45.000]
Iteration 1: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████| 30/30 [00:00<00:00, 313.20it/s, episode=60, return=-62.100] 
Iteration 2: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████| 30/30 [00:00<00:00, 322.71it/s, episode=90, return=-32.700] 
Iteration 3: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████| 30/30 [00:00<00:00, 337.84it/s, episode=120, return=-31.900] 
Iteration 4: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████| 30/30 [00:00<00:00, 338.02it/s, episode=150, return=-42.000]
Iteration 5: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████| 30/30 [00:00<00:00, 356.60it/s, episode=180, return=-50.700] 
Iteration 6: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████| 30/30 [00:00<00:00, 337.57it/s, episode=210, return=-22.600] 
Iteration 7: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████| 30/30 [00:00<00:00, 366.66it/s, episode=240, return=-60.400] 
Iteration 8: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████| 30/30 [00:00<00:00, 323.30it/s, episode=270, return=-23.200] 
Iteration 9: 100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████| 30/30 [00:00<00:00, 346.09it/s, episode=300, return=-33.300]

7.总结

从上述结果中看出:随着Q-planning步数增长,Dyna-Q算法收敛速度也越快。当然并非所有环境中都是满足这个规律的,这主要取决于环境是否是确定性的和环境模型的精度。在上述悬崖漫步环境中,状态转移是完全确定的,构建的环境模型精度也是最高的,所以可以增加Q-planning步数来直接降低算法的样本复杂度。

 本次内容实现了经典的基于模型的强化学习算法Dyna-Q算法在悬崖漫步环境中的学习过程,并通过调整Q-planning步数直观展示Q-planning步数对算法收敛速度的影响。基于模型的强化学习Dyna-Q算法取得很好的效果。但是这些环境比较简单,模型可以直接通过经验数据学习,若环境比较复杂,状态连续或者状态转移随机而非决定性的,学习一个比较准确的模型就变得具有挑战,直接影响基于模型强化学习算法是否能应用于此等环境并获得比无模型强化学习更好效果。

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!