本方法的基础是马尔可夫决策(MDP)和贝尔曼方程。本文目的在于找到一个使状态值最大的最优策略。本方法都是假设在不确定环境下做的测试,因此求的状态值是概率期望值。
本文描述的方法包括三种:普通的策略迭代、截断策略评估迭代和值迭代方法。
一、普通策略迭代方法
(1)迭代策略评估
用于对特定的策略求解其值函数。
其实现算法如下:
有四个输入参数:
env:这是 OpenAI Gym 环境的实例,其中 env.P 会返回一步动态特性。
policy:这是一个二维 numpy 数组,其中 policy.shape[0] 等于状态数量 (env.nS) , policy.shape[1] 等于动作数量 (env.nA) 。policy[s][a] 返回智能体在状态 s 时根据该策略选择动作 a 的概率。
gamma:这是折扣率。它必须是在 0 到 1(含)之间的值,默认值为:1。
theta:这是一个非常小的正数,用于判断估算值是否足够地收敛于真值函数 (默认值为:1e-8)。
返回以下输出结果:
V:这是一个一维numpy数组,其中 V.shape[0] 等于状态数量 (env.nS)。V[s] 包含状态 s 在输入策略下的估计状态值。
实现代码如下
import numpy as np
def policy_evaluation(env, policy, gamma=1, theta=1e-8):
V = np.zeros(env.nS)#初始值函数值状态假设为0
while True:
delta =0 #保证每次更新完所有状态点后归0,使每次得到所有状态点与前一次状态的差值,
for s in range(env.nS):#更新到每个状态点
vs = 0 #保证每次状态更新前归0
for action,action_prob in enumerate(policy[s]): #得到每个动作的概率
for prob,next_state,reward,done in env.P[s][action]: #得到一个状态下采取某个动作的下个状态和奖励和概率
vs += action_prob*prob*(reward+gamma*V[next_state]) #使用贝尔曼方程得到某个位置的状态
delta = max(delta,np.abs(vs-V[s]))#找出所有差值的最大值
V[s] = vs
if delta < theta:
break
## TODO: complete the function
return V
(2)计算动作值函数
假设智能体在某一个状态已经确定了动作。但是确定了动作,下个状态和奖励还是不确定的。
实现算法如下:
有四个输入参数:
env:这是 OpenAI Gym 环境的实例,其中 env.P 会返回一步动态特性。
V:这是一个一维 numpy 数组,其中 V.shape[0] 等于状态数量 (env.nS)。V[s] 包含状态 s 的估值。
s:这是环境中的状态对应的整数。它应该是在 0 到 (env.nS)-1(含)之间的值。
gamma:这是折扣率。它必须是在 0 到 1(含)之间的值,默认值为:1。
返回以下输出结果:
q:这是一个一维 numpy 数组,其中 q.shape[0] 等于动作数量 (env.nA)。q[a] 包含状态 s 和动作 a 的(估算)值
实现代码如下:
def q_from_v(env, V, s, gamma=1):
q = np.zeros(env.nA)
## TODO: complete the function
for a in range(env.nA):
vs = 0
for prob,next_state,reward,done in env.P[s][a]:
vs += prob*(reward+gamma*V[next_state])
q[a]=vs
return q
(3)策略改进
根据现有的策略得到的动作值估算状态值(state-value),并根据动作值最大的方向(0,1,2,3)返回改进的策略。
实现算法如下:
算法应该有三个输入参数:
env:这是 OpenAI Gym 环境的实例,其中 env.P 会返回一步动态特性。
V:这是一个一维 numpy 数组,其中 V.shape[0] 等于状态数量 (env.nS)。V[s] 包含状态 s 的估值。
gamma:这是折扣率。它必须是在 0 到 1(含)之间的值,默认值为:1。
该算法会返回以下输出结果:
policy:这是一个二维 numpy 数组,其中 policy.shape[0] 等于状态数量 (env.nS) , policy.shape[1] 等于动作数量 (env.nA) 。policy[s][a] 返回智能体在状态 s 时根据该策略选择动作 a 的概率。
实现代码如下:
def policy_improvement(env, V, gamma=1):
policy = np.zeros([env.nS, env.nA]) / env.nA
for s in range(env.nS):
policy[s]=q_from_v(env,V,s,gamma)
# index = policy[s].tolist().index(max(policy[s]))#只返回列表里的第一个值的index
index = np.argwhere(policy[s]==max(policy[s]))
policy[s] = np.zeros_like(policy[s])
policy[s][index]=1
policy[s]=policy[s]/sum(policy[s])
#print(policy)
## TODO: complete the function
return policy
print(policy_improvement(env, V, gamma=1))
(4)策略迭代
策略跌代就是重复进行策略评估(根据策略计算状态值),然后根据得到的状态值计算动作值,并进行策略改进。直到策略不再发生改变。
实现算法如下:
实现代码如下:
有三个输入参数:
env:这是 OpenAI Gym 环境的实例,其中 env.P 会返回一步动态特性。
gamma:这是折扣率。它必须是在 0 到 1(含)之间的值,默认值为:1。
theta:这是一个非常小的正数,用于判断策略评估步骤是否足够地收敛于真值函数 (默认值为:1e-8)。
返回以下输出结果:
policy:这是一个二维 numpy 数组,其中 policy.shape[0] 等于状态数量 (env.nS) , policy.shape[1] 等于动作数量 (env.nA) 。policy[s][a] 返回智能体在状态 s 时根据该策略选择动作 a 的概率。
V:这是一个一维 numpy 数组,其中 V.shape[0] 等于状态数量 (env.nS)。V[s] 包含状态 s 的估值。
import copy
def policy_iteration(env, gamma=1, theta=1e-8):
policy = np.ones([env.nS, env.nA]) / env.nA
## TODO: complete the function
i = 0
while True:
i = i + 1
V = policy_evaluation(env,policy,gamma,theta)
policy_new = policy_improvement(env,V,gamma)
if (policy_new == policy).all():
print(i)
break
policy = policy_new
return policy, V
二、截断策略评估迭代
在对状态空间执行固定次数的遍历后,停止评估步骤,从而将此方法称为截断策略评估。
(1) 截断策略状态值评估
截断策略评估算法如下:
实现代码如下:
env:这是 OpenAI Gym 环境的实例,其中 env.P 会返回一步动态特性。
policy:这是一个二维 numpy 数组,其中 policy.shape[0] 等于状态数量 (env.nS) , policy.shape[1] 等于动作数量 (env.nA) 。policy[s][a] 返回智能体在状态 s 时根据该策略选择动作 a 的概率。
V:这是一个一维 numpy 数组,其中 V.shape[0] 等于状态数量 (env.nS)。V[s] 包含状态 s 的估值。
max_it:这是一个正整数,对应的是经历状态空间的次数(默认值为:1)。
gamma:这是折扣率。它必须是在 0 到 1(含)之间的值,默认值为:1。
返回以下输出结果:
V:这是一个一维 numpy 数组,其中 V.shape[0] 等于状态数量 (env.nS)。V[s] 包含状态 s 的估值。
def truncated_policy_evaluation(env, policy, V, max_it=1, gamma=1):
## TODO: complete the function
i = 0
while i < max_it:
for s in range(env.nS):
vs = 0
for a,action_prob in enumerate(policy[s]):
for prob,next_state,reward,done in env.P[s][a]:
vs += action_prob*prob*(reward+gamma*V[next_state])
V[s] = vs
i = i+1
return V
(2)截断策略迭代
实现算法如下:
实现代码如下:
env:这是 OpenAI Gym 环境的实例,其中 env.P 会返回一步动态特性。
max_it:这是一个正整数,对应的是经历状态空间的次数(默认值为:1)。
gamma:这是折扣率。它必须是在 0 到 1(含)之间的值,默认值为:1。
theta:这是一个非常小的正整数,用作停止条件(默认值为:1e-8)。
返回以下输出结果:
policy:这是一个二维 numpy 数组,其中 policy.shape[0] 等于状态数量 (env.nS) , policy.shape[1] 等于动作数量 (env.nA) 。policy[s][a] 返回智能体在状态 s 时根据该策略选择动作 a 的概率。
V:这是一个一维 numpy 数组,其中 V.shape[0] 等于状态数量 (env.nS)。V[s] 包含状态 s 的估值。
def truncated_policy_iteration(env, max_it=10, gamma=1, theta=1e-8):
V = np.zeros(env.nS)
policy = np.zeros([env.nS, env.nA]) / env.nA
while True:
policy = policy_improvement(env,V,gamma)
V_old = copy.deepcopy(V) #必须使用copy()或者deepcopy(),使用'='只是引用,改变V本身也会改变v_old
V = truncated_policy_evaluation(env,policy,V,max_it,gamma)#改变v是通过改变V的每一项改变V的,如果是用'='会导致v_old与v同步变化.
delta = max(abs(V_old-V)) #为了保证v_old与v不同步变化,我们使用浅copy()or deepcopy()
if delta<theta:
break
## TODO: complete the function
return policy, V
三、值迭代
在动态规划设置中用来估算不同策略对应的状态值。每次对状态空间进行遍历时,都会同时进行策略评估和策略改进。在该算法中,会把求得的每个状态的最大动作值直接作为新的状态值,从而免去了策略改进的步骤,同时会在最后根据最终状态值得到最优策略。
实现算法如下:
实现代码如下:
env:这是 OpenAI Gym 环境的实例,其中 env.P 会返回一步动态特性。
gamma:这是折扣率。它必须是在 0 到 1(含)之间的值,默认值为:1。
theta:这是一个非常小的正整数,用作停止条件(默认值为:1e-8)。
返回以下输出结果:
policy:这是一个二维 numpy 数组,其中 policy.shape[0] 等于状态数量 (env.nS) , policy.shape[1] 等于动作数量 (env.nA) 。policy[s][a] 返回智能体在状态 s 时根据该策略选择动作 a 的概率。
V:这是一个一维 numpy 数组,其中 V.shape[0] 等于状态数量 (env.nS)。V[s] 包含状态 s 的估值。
def value_iteration(env, gamma=1, theta=1e-8):
V = np.zeros(env.nS)
## TODO: complete the function
while True:
delta = 0
for s in range(env.nS):
V_old = copy.copy(V[s])
q = q_from_v(env,V,s,gamma)
V[s] = max(q)
delta = max(delta,abs(V[s]-V_old))
if delta < theta:
policy = policy_improvement(env,V,gamma)
break
return policy, V
```