文章目录
一、马尔科夫决策过程
马尔科夫过程描述了强化学习的框架。在马尔科夫过程中,环境是完全可以观测的,但是很多时候环境里面有些量是不可观测的,但是这个部分观测的问题也可以转换成一个 MDP 的问题。
在介绍马尔可夫决策过程之前,先梳理一下马尔可夫链、马尔可夫奖励过程。这两个过程是马尔可夫决策过程的一个基础。
1.马尔科夫链
当一个状态满足马尔科夫特征时,要求未来的转移只取决于现在的状态,与过去无关。马尔可夫性质是所有马尔可夫过程的基础。
下图为一个马尔科夫链示例:
这张图中有七个状态,这七个状态不断转移,以s1为例:
- s1有0.6的概率继续存活在s1状态
- s1有0.4的概率转换到s2
其余节点与s1类似。我们可以用一个状态转移方程来描述这种状态转移,每一行描述了从一个节点到达所有其它节点的概率。
2.马尔科夫奖励过程
马尔可夫奖励过程(Markov Reward Process, MRP) 是马尔可夫链再加上了一个奖励函数。
在 MRP 中,转移矩阵跟它的这个状态都是跟马尔可夫链一样的,多了一个奖励函数(reward function) 。奖励函数是一个期望,就是说当到达某一个状态的时候,可以获得多大的奖励,然后这里另外定义了一个 discount factor。
依旧以上面的马尔科夫链为例,将奖励加上,即到达每一个状态时,都会得到一个奖励。例如到达s1时,得到5的奖励,到达s7时,得到10的奖励,其他状态没有任何奖励,所以我们可以用一个向量来表示这个奖励。
一些概念:
- horizon:它说明了同一个 episode 或者是整个一个轨迹的长度,它是由有限个步数决定的。
- return:奖励的逐步叠加,discount factor说明我们其实更希望得到现有的奖励,未来的奖励就要把它打折扣。
- 状态价值函数:某一状态的价值,可以看作关于 return 的期望。也可以看成是一个对未来可能获得奖励的当前价值的一个表现。
- discounted factor:折扣因子,折扣因子在状态价值函数中扮演着重要作用,原因如下:
- 马尔可夫过程是带环的,这个无穷的奖励。
- 希望尽可能快地得到奖励
- 设置为0时,只关心当前奖励,设为1时,未来和当前奖励一样,可作为超参数
依旧以之前的马尔科夫链为例,假设折扣系数为0.5,s1奖励为5,s7奖励为10,其余为0
对于马尔科夫链s4、s5、s6、s7,价值为0+0* 1/2+0* 1/4+10* 1/8=1.25
计算价值函数有如下方法:
(1)贝尔曼公式(Bellman equation)
Bellman Equation 定义了当前状态与未来状态的迭代关系,表示当前状态的值函数可以通过下个状态的值函数来计算。
第一部分为当前立刻可以得到的奖励,第二部分是未来打了折扣的奖励之和。
s’可看作未来的所有状态,P(s’|s)指从当前状态转移到未来状态的概率,V(S’)代表的是未来某一个状态的价值,最后把未来的奖励打折扣。
以矩阵形式表示价值函数:
得到的解析解:
需要注意的是,这种方法时间复杂度很高,只能求比较小的马尔科夫价值。
(2)迭代法
迭代的方法就有几种,比如说动态规划的方法、也可以通过蒙特卡罗办法,即通过采样的办法去计算它、另外可以通过 Temporal-Difference Learning 的办法,这个 Temporal-Difference Learning 叫TD Leanring ,就是动态规划和蒙特卡罗的一个结合。
蒙特卡罗办法
下面是蒙特卡罗方法的伪代码
蒙特卡罗办法的具体思想是当得到一个 MRP 后,从某一个状态开始,随机产生很多轨迹。产生了一个轨迹过后,就会得到一个奖励,直接把它的 discounted 的奖励算出来。算出来后就积累起来,当积累到一定的轨迹数量后,然后直接除以轨迹的数量,然后就会得到它的这个价值。
动态规划方法
下面是动态规划的伪代码:
动态规划办法通过一直去迭代 Bellman Equation,最后达到收敛。即最后更新的状态跟上一个状态变化并不大的时候,这个更新就可以停止,最终输出最新的V(S’)。
3.马尔科夫决策过程
马尔可夫决策过程(Markov Decision Process) 多了一个 action ,其它的定义跟 MRP 都是类似的。状态转移也多了一个条件,就是采取的某一种行为会导致未来的状态会不同。价值函数也多了一个条件,即当前的状态以及你采取的行为会决定当前可能得到的奖励多少。
MDP中的决策(policy):
- Policy 定义了在某一个状态应该采取什么样的行为
- 知道当前状态后,带入 policy function,会得到一个决定采取什么行动的概率或者直接输出一个值
- 决策函数:
- 概率函数是静态的(stationary),不同时间采取的行为都是对 policy function 进行采样。
MDP 跟 MRP 之间可以进行转换。已知一个 MDP 和一个决策函数π的时候,可以把 MDP 转换成MRP。在 MDP 里面,转移函数 是基于它当前状态以及它当前的 action,现在已知 policy function,那么可以直接把这个 action 进行加和,直接把这个 action 去掉,这样就会得到一个类似于 MRP的奖励函数。
MDP的价值函数
-
状态价值函数(state-value function):定义是跟 MRP 是类似,这个期望是基于采取的 policy,通过对 policy 进行采样来得到一个期望,那么就可以计算出它的这个价值函数。
-
Q 函数(action-value function):定义的是在某一个状态采取某一个行为,然后可能得到的 return 的一个期望。这里期望其实也是基于 policy function。所以需要对这个 policy function 进行一个加和,最后得到它的这个价值。
-
对 Q 函数中的行为函数进行加和,就可以得到状态价值函数。
-
通过贝尔曼公式,可以将状态价值函数变换为Q函数
-
Bellman Expectation Equation :对状态-价值函数进行一个分解,得到类似于之前 MRP 的 Bellman Equation。定义了当前状态跟未来状态之间的一个关联。
-
Q 函数的 Bellman Expectation Equation:对于 Q 函数,也可以做类似的分解
-
当前时刻的 Q 函数跟未来时刻的 Q 函数之间的关联
-
当前状态的价值跟未来状态价值之间的关联
-
policy evaluation:计算价值函数的过程,也可以理解成评估这个策略会得到多大的奖励。
例子
假设环境里面有两种行为:往左走和往右走。奖励函数是只要达到s1,会有5的奖励,达到s7,有10的奖励,其余无奖励。对于如下的三种情况:
- 假设采取的策略是不管在任何状态都是往左走,折扣因子是0。那么对于 deterministic policy,最后估算出的价值函数是一致的。直接通过 Bellman Expectation Equation 不停地迭代,最后会收敛。收敛过后的值就是每一个状态的价值。
- 假设采取的策略是不管在任何状态都是往左走,折扣因子是 0.5,通过如下等式进行迭代,最后。就会得到它的状态
- 假设采取的策略是0.5 的概率往左走,有 0.5 的概率往右走,折扣因子是 0.5。开始的时候,可以初始化不同的V(S’)都会有一个值,那么放到Bellman Expectation Equation去迭代,最后是v ,然后就会算出来。
4.马尔科夫决策过程的决策评价
MDP 的Prediction 是给定一个 MDP 以及一个 policy ,去计算value function,就相当于每个状态它的价值函数是多少,可以通过动态规划去解决。
MDP是满足动态规划的要求的,在 Bellman Equation 里可以把它分解成一个递归结构。当我们把它分解成一个递归结构时,如果我们的子问题子状态能得到一个值,那么它的未来状态因为跟子状态是直接相连的,也可以继续推算出来,所以这个价值函数就可以储存它以及重用它的最佳的解。
对于 policy evaluation问题,使用的方法是反复迭代Bellman Expectation Backup直到收敛,Bellman Expectation Backup公式如下:
由于已经给定了这个函数的 policy function,那么可以直接把它简化成一个 MRP 的表达形式,就相当于我们把这个a去掉,如下式所示:
这样它就只有价值函数跟转移函数了。通过去迭代这个函数,我们也可以得到每个状态的价值。因为不管是在 MRP 以及 MDP,价值函数包含的变量都是只跟状态有关,就相当于进入某一个状态,未来可能得到多大的价值。
5.马尔科夫决策过程的控制
MDP 的Control 是去寻找一个最佳的策略,它的 input 就是MDP,输出是最佳价值函数(optimal valuefunction)以及最佳策略(optimal policy),可以通过动态规划去解决。
最佳价值函数
搜索一种 policy ,然后我们会得到每个状态它的状态值最大的一个情况, V*就是到达每一个状态,它的值的极大化情况。
最佳策略
在出现上面的极大化情况是得到的策略。可能有多个最佳的 policy,多个 policy 可以取得相同的最佳价值。
寻找最佳的 policy可以通过对 Q 函数进行极大化,得到最佳价值。当所有东西都收敛后,因为 Q 函数是关于状态跟动作的函数,所以对某一个状态采取一个行为,然后可以使得这个 Q 函数最大化,那么就这个行为就应该是最佳的行为。所以就可以直接提取出它的最佳策略。
Bellman Optimality Equation
整个 MDP 已经到达最佳的状态时满足Bellman Optimality Equation。当到达最佳状态过后,对于 Q 值,取最大的 action 时候的那个值,直接等于最佳 value function。
将该式与Q函数结合就会得到 Q 函数之间的转移
策略搜索办法
- 穷举法:假设我们有有限多个状态、有限多个行为可能性,每个状态可以采取有限种行为的策略。把这些可能的policy穷举一遍,然后算出每种策略的 value function,然后对比一下可以得到最佳策略。这种方法的缺点是非常没有效率。
- policy iteration:这个方法主要有两个步骤,这两个步骤一直在迭代,直到收敛:
-
policy evaluation:先保证 policy 不变,去估计当前的价值,即v函数。
-
policy improvement:取得 v 函数过后可以进一步推算出Q 函数。通过在得到的 Q 函数上面做一个贪心的搜索,这样就会进一步改进它的策略。
-
- Value iteration:将 Bellman Optimality Equation 作为更新规则,不断进行迭代直到收敛
在进行价值迭代后可以通过下式得到最优决策
二、表格型方法
1.Q表格与状态价值
P函数和R函数: P函数反应的是状态转移的概率,即反应的环境的随机性,R函数就是Reward function。但是我们通常处于一个未知的环境(即P函数和R函数是未知的)。
Q表格型表示方法: 表示形式是一种表格形式,其中横坐标为 action(agent)的行为,纵坐标是环境的state,其对应着每一个时刻agent和环境的情况,并通过对应的reward反馈去做选择。一般情况下,Q表格是一个已经训练好的表格,不过,我们也可以每进行一步,就更新一下Q表格,然后用下一个状态的Q值来更新这个状态的Q值(即时序差分方法)。
时序差分(Temporal Difference): 步步更新。不用知道全局,走一步看一步的做自身引导。即此时与下一时刻的价值函数差分(也可以理解是现实与预测值的差距)来近似代替蒙特卡洛中的完整价值。
采用时序差分法的强化学习可以分为两类,一类是在线控制(On-policy Learning),即一直使用一个策略来更新价值函数和选择新的动作,代表就是Sarsa。而另一类是离线控制(Off-policy Learning),会使用两个控制策略,一个策略用于选择新的动作,另一个策略用于更新价值函数,代表就是Q-Learning。
2.Sarsa算法
Sarsa的思想是,如上图从上到下,先基于当前状态S,使用ϵ−贪婪法按一定概率选择动作A,然后得到奖励R,并更新进入新状态S′,基于状态S′,使用ϵ−贪婪法选择A′(即在线选择,仍然使用同样的ϵ−贪婪)。算法每次更新值函数需要知道前一步的状态(state),前一步的动作(action)、奖励(reward)、当前状态(state)、将要执行的动作(action)。
算法流程为:
建立一个Q Table来保存状态s和将会采取的所有动作a,Q(s,a)。在每个回合中,先随机初始化第一个状态,再对回合中的每一步都先从Q Table中使用ϵ−贪婪基于当前状态 s (如果Q表没有该状态就创建s-a的行,且初始为全0)选择动作 a,执行a,然后得到新的状态s’和当前奖励r,同时使用ϵ−贪婪得到在s’时的a’,直接利用a’更新表中Q(s,a)的值,继续循环到终点。
代码实现:
class SarsaAgent(object):
def __init__(self, obs_n, act_n, learning_rate=0.01, gamma=0.9, e_greed=0.1):
self.act_n = act_n # 动作维度,有几个动作可选
self.lr = learning_rate # 学习率
self.gamma = gamma # reward的衰减率
self.epsilon = e_greed # 按一定概率随机选动作
self.Q = np.zeros((obs_n, act_n))
# 根据输入观察值,采样输出的动作值,带探索
def sample(self, obs):
if np.random.uniform(0, 1) < (1.0 - self.epsilon): #根据table的Q值选动作
action = self.predict(obs)
else:
action = np.random.choice(self.act_n) #有一定概率随机探索选取一个动作
return action
# 根据输入观察值,预测输出的动作值
def predict(self, obs):
Q_list = self.Q[obs, :]
maxQ = np.max(Q_list)
action_list = np.where(Q_list == maxQ)[0] # maxQ可能对应多个action
action = np.random.choice(action_list)
return action
# 学习方法,也就是更新Q-table的方法
def learn(self, obs, action, reward, next_obs, next_action, done):
""" on-policy
obs: 交互前的obs, s_t
action: 本次交互选择的action, a_t
reward: 本次动作获得的奖励r
next_obs: 本次交互后的obs, s_t+1
next_action: 根据当前Q表格, 针对next_obs会选择的动作, a_t+1
done: episode是否结束
"""
predict_Q = self.Q[obs, action]
if done:
target_Q = reward # 没有下一个状态了
else:
target_Q = reward + self.gamma * self.Q[next_obs, next_action] # Sarsa
self.Q[obs, action] += self.lr * (target_Q - predict_Q) # 修正q
def run_episode(env, agent, render=False):
total_steps = 0 # 记录每个episode走了多少step
total_reward = 0
obs = env.reset() # 重置环境, 重新开一局(即开始新的一个episode)
action = agent.sample(obs) # 根据算法选择一个动作
while True:
next_obs, reward, done, _ = env.step(action) # 与环境进行一个交互
next_action = agent.sample(next_obs) # 根据算法选择一个动作
# 训练 Sarsa 算法
agent.learn(obs, action, reward, next_obs, next_action, done)
action = next_action
obs = next_obs # 存储上一个观察值
total_reward += reward
total_steps += 1 # 计算step数
if render:
env.render() #渲染新的一帧图形
if done:
break
return total_reward, total_steps
env = gym.make("CliffWalking-v0") # 0 up, 1 right, 2 down, 3 left
# 创建一个agent实例,输入超参数
agent = SarsaAgent(
obs_n=env.observation_space.n,
act_n=env.action_space.n,
learning_rate=0.1,
gamma=0.9,
e_greed=0.1)
# 训练500个episode,打印每个episode的分数
for episode in range(500):
ep_reward, ep_steps = run_episode(env, agent, False)
print('Episode %s: steps = %s , reward = %.1f' % (episode, ep_steps, ep_reward))
3.Q-learning算法
Q-Learnig的思想就是,如上图从上到下,先基于当前状态S,使用ϵ−贪婪法按一定概率选择动作A,然后得到奖励R,并更新进入新状态S′,基于状态S′,直接使用贪婪法从所有的动作中选择最优的A′(即离线选择,不是用同样的ϵ−贪婪)。
算法流程为:
建立一个Q Table来保存状态s和将会采取的所有动作a,Q(s,a)。在每个回合中,先随机初始化第一个状态,再对回合中的每一步都先从Q Table中使用ϵ−贪婪基于当前状态 s (如果Q表没有该状态就创建s-a的行,且初始为全0)选择动作 a,执行a,然后得到新的状态s’和当前奖励r,同时更新表中Q(s,a)的值,继续循环到终点。整个算法就是一直不断更新 Q table 里的值,再根据更新值来判断要在某个 state 采取怎样的 action最好。
代码实现:
class QLearningAgent(object):
def __init__(self, obs_n, act_n, learning_rate=0.01, gamma=0.9, e_greed=0.1):
self.act_n = act_n # 动作维度,有几个动作可选
self.lr = learning_rate # 学习率
self.gamma = gamma # reward的衰减率
self.epsilon = e_greed # 按一定概率随机选动作
self.Q = np.zeros((obs_n, act_n))
# 根据输入观察值,采样输出的动作值,带探索
def sample(self, obs):
if np.random.uniform(0, 1) < (1.0 - self.epsilon): #根据table的Q值选动作
action = self.predict(obs)
else:
action = np.random.choice(self.act_n) #有一定概率随机探索选取一个动作
return action
# 根据输入观察值,预测输出的动作值
def predict(self, obs):
Q_list = self.Q[obs, :]
maxQ = np.max(Q_list)
action_list = np.where(Q_list == maxQ)[0] # maxQ可能对应多个action
action = np.random.choice(action_list)
return action
# 学习方法,也就是更新Q-table的方法
def learn(self, obs, action, reward, next_obs, done):
""" off-policy
obs: 交互前的obs, s_t
action: 本次交互选择的action, a_t
reward: 本次动作获得的奖励r
next_obs: 本次交互后的obs, s_t+1
done: episode是否结束
"""
predict_Q = self.Q[obs, action]
if done:
target_Q = reward # 没有下一个状态了
else:
target_Q = reward + self.gamma * np.max(self.Q[next_obs, :]) # Q-learning
self.Q[obs, action] += self.lr * (target_Q - predict_Q) # 修正q
def run_episode(env, agent, render=False):
total_steps = 0 # 记录每个episode走了多少step
total_reward = 0
obs = env.reset() # 重置环境, 重新开一局(即开始新的一个episode)
while True:
action = agent.sample(obs) # 根据算法选择一个动作
next_obs, reward, done, _ = env.step(action) # 与环境进行一个交互
# 训练 Q-learning算法
agent.learn(obs, action, reward, next_obs, done)
obs = next_obs # 存储上一个观察值
total_reward += reward
total_steps += 1 # 计算step数
if render:
env.render() #渲染新的一帧图形
if done:
break
return total_reward, total_steps
env = gym.make("CliffWalking-v0") # 0 up, 1 right, 2 down, 3 left
# 创建一个agent实例,输入超参数
agent = QLearningAgent(
obs_n=env.observation_space.n,
act_n=env.action_space.n,
learning_rate=0.1,
gamma=0.9,
e_greed=0.1)
# 训练500个episode,打印每个episode的分数
for episode in range(500):
ep_reward, ep_steps = run_episode(env, agent, False)
print('Episode %s: steps = %s , reward = %.1f' % (episode, ep_steps, ep_reward))
4.on-policy与off-policy的区别
首先就判断on-policy和off-policy就在于估计时所用的策略与更新时所用的策略是否为同一个策略。on-policy 在学习的过程中,只存在一种策略,比如Sarsa选了什么动作来估计Q值就一定会用什么动作来更新state,一定会执行该动作(会有贪婪率);而off-policy 在学习的过程中,有两种不同的策略。第一个策略是我们希望学到一个最佳的目标策略,另外一个策略是探索环境的策略,比如Q-Learning,估Q值是一回事,但执行动作时一定是会选max的,即使用了两套策略,属于off-policy。
而之所以要叫on或off是因为,off-policy基本上都是要基于replay memory,即估计出的动作值肯定是最优的,但在生成策略的时候,却选择了价值最大的综合memory的max Q 的action。而on-policy每次都是选择最优的action。
Q-learning 算法被提出的时间更早,Sarsa 算法是 Q-learning 算法的改进。