1. 无模型问题
在很多时候,我们无法得知模型信息,比如前几节的蛇棋中,我们不知道棋盘梯子的信息和骰子的信息,用数学化的方法来说,就是我们用于决策的智能体不知道状态转移概率
P
P
P。和有模型问题使用
V
V
V计算的方法相比,我们需要保存并更新
Q
Q
Q,很容易波动不收敛,因此需要的迭代次数一般需要更多。
首先介绍蒙特卡洛法,这是一种策略迭代方法。
2. 采样的方法
2.1 计算公式
当我们无法得知
P
P
P的时候,一个直观的想法就是使用大量的采样去进行估计。
为了方便,我们把策略迭代算法中策略评估的公式进行一下拆解:
Q
=
P
(
R
+
γ
V
)
Q=P(R+\gamma V)
Q=P(R+γV)
V
=
Π
Q
V=\Pi Q
V=ΠQ
Q
Q
Q无法使用迭代的方法计算得到,因此使用蒙特卡洛法,采样得到大量的样本序列:
s
0
,
a
0
,
r
0
,
s
1
1
,
a
1
1
,
r
1
1
.
.
.
{s_0,a_0,r_0,s^1_1,a^1_1,r^1_1...}
s0,a0,r0,s11,a11,r11...
s
0
,
a
0
,
r
0
,
s
1
2
,
a
1
2
,
r
1
2
.
.
.
{s_0,a_0,r_0,s^2_1,a^2_1,r^2_1...}
s0,a0,r0,s12,a12,r12...
s
0
,
a
0
,
r
0
,
s
1
3
,
a
1
3
,
r
1
3
.
.
.
{s_0,a_0,r_0,s^3_1,a^3_1,r^3_1...}
s0,a0,r0,s13,a13,r13...
…
s
0
,
a
0
,
r
0
,
s
1
N
,
a
1
N
,
r
1
N
.
.
.
{s_0,a_0,r_0,s^N_1,a^N_1,r^N_1...}
s0,a0,r0,s1N,a1N,r1N...
状态行动集(
s
0
s_0
s0,
a
0
a_0
a0)的值函数可以近似为:
Q
=
1
N
(
r
0
+
γ
r
1
1
+
γ
2
r
2
1
.
.
.
+
r
0
+
γ
r
1
2
+
γ
2
r
2
2
.
.
.
+
r
0
+
γ
r
1
N
+
γ
2
r
2
N
+
.
.
.
)
Q=\frac{1}{N}(r_0+\gamma r^1_1+\gamma ^2r^1_2...+r_0+\gamma r^2_1+\gamma^2 r^2_2...+r_0+\gamma r^N_1+\gamma^2 r^N_2+...)
Q=N1(r0+γr11+γ2r21...+r0+γr12+γ2r22...+r0+γr1N+γ2r2N+...)。再根据策略
Π
\Pi
Π就可以计算出
V
V
V了。
具体计算时,我们是使用更新的方法计算
Q
Q
Q,而不是等遍历完再取均值。令
q
i
=
r
0
+
γ
r
1
i
+
γ
2
r
2
i
.
.
.
q^i = r_0+\gamma r^i_1+\gamma ^2r^i_2...
qi=r0+γr1i+γ2r2i...
则更新公式为:
Q
i
=
Q
i
−
1
+
1
i
(
q
i
−
Q
i
−
1
)
Q^i=Q^{i-1}+\frac{1}{i}(q^i-Q^{i-1})
Qi=Qi−1+i1(qi−Qi−1)
可以证明:
Q
N
=
1
N
(
q
1
+
.
.
.
+
q
N
)
Q^N=\frac{1}{N}(q^1+...+q^N)
QN=N1(q1+...+qN)
更新公式和梯度下降法非常相像。
2.2 采样随机探索
在使用蒙特卡洛法采样的时候,我们有很多前进的方法。一方面,我们要保证行动
a
a
a的最优性,这样才能准确估计出
v
v
v;另一方面,我们要保证行动的随机性,这样我们才能访问到更多状态,避免陷入局部最优。
一种常见的策略是在采样的时候加入一定的随机性,比如
ϵ
\epsilon
ϵ-greedy策略,即以一定的概率采取随机行动,其他情况采取最优策略行动。
2.3 every visit和first visit
加入我们在行动的过程中,又碰到了
(
s
0
,
a
0
)
(s_0,a_0)
(s0,a0)怎么办?一种方法是将其加入
Q
Q
Q的计算之中,称为every visit方法;另一种方法是不加入,称为first visit方法。
在有限状态的序贯决策问题中,不同时间段访问同样状态的
V
V
V值可能会差很大。这种情况下建议使用first visit方法,减少
q
q
q值的方差,加快收敛速度。
3. 代码与测试
class MonteCarlo(object):
def __init__(self, epsilon=0.0):
self.epsilon = epsilon
# 一轮蒙特卡洛采样
def monte_carlo_eval(self, agent, env):
state = env.reset()
episode = []
while True:
ac = agent.play(state, self.epsilon)
next_state, reward, terminate, _ = env.step(ac)
episode.append((state, ac, reward))
state = next_state
if terminate:
break
value = []
return_val = 0
# 逆向计算q值
for item in reversed(episode):
return_val = return_val * agent.gamma + item[2]
value.append((item[0], item[1], return_val))
# 进行更新
for item in reversed(value):
if agent.value_n[item[0]][item[1]] == 0: # 这里是first visit方法;every visit把这句判断删除即可
agent.value_n[item[0]][item[1]] += 1 # 访问次数
agent.value_q[item[0]][item[1]] += (item[2] - \
agent.value_q[item[0]][item[1]]) / \
agent.value_n[item[0]][item[1]]
def policy_improve(self, agent):
new_policy = np.zeros_like(agent.pi)
for i in range(1, agent.s_len):
new_policy[i] = np.argmax(agent.value_q[i,:])
if np.all(np.equal(new_policy, agent.pi)):
return False
else:
agent.pi = new_policy
return True
# monte carlo法
def monte_carlo_opt(self, agent, env):
for i in range(10): # 进行10轮迭代
for j in range(100): # 每次采样100轮
self.monte_carlo_eval(agent, env)
self.policy_improve(agent)
对比测试结果如下:
ladders info:
{14: 65, 18: 48, 41: 68, 30: 45, 68: 41, 48: 18, 49: 89, 71: 79, 65: 14, 70: 18, 73: 41, 45: 30, 89: 49, 79: 71}
Iter 3 rounds converge
Timer PolicyIter COST:0.2772650718688965
return_pi=64
Timer MonteCarlo COST:0.22463107109069824
return_pi=30
MonteCarlo法的效果一般,主要是因为前几轮迭代的值方差很大,而我们对迭代次数进行了限制,因此较难收敛。下一节将介绍可以减小方差的时序差分法。