1. 算法原理
这是一种策略学习算法。
策略学习的关键点是使用策略梯度定理,求取优化目标
J
(
θ
)
J(\boldsymbol{\theta})
J(θ)最大值。
J
(
θ
)
=
E
S
[
V
π
(
S
)
]
J(\boldsymbol{\theta})=\mathbb{E}_{S}\left[V_{\pi}(S)\right]
J(θ)=ES[Vπ(S)]
这就需要用到策略梯度定理,对于目标函数更新
θ
\theta
θ做梯度上升。
而在实际应用中,通常使用近似策略梯度,使用蒙特卡洛抽样计算得到的随机梯度来代替原目标函数梯度。
随机梯度表达式为:
g
(
s
,
a
;
θ
)
≜
Q
π
(
s
,
a
)
⋅
∇
θ
ln
π
(
a
∣
s
;
θ
)
\boldsymbol{g}(s, a ; \boldsymbol{\theta}) \triangleq Q_{\pi}(s, a) \cdot \nabla_{\boldsymbol{\theta}} \ln \pi(a \mid s ; \boldsymbol{\theta})
g(s,a;θ)≜Qπ(s,a)⋅∇θlnπ(a∣s;θ)
随后,依照随机梯度做梯度上升更新
θ
\boldsymbol{\theta}
θ,也就是
θ
←
θ
+
β
∗
g
(
s
,
a
;
θ
)
\boldsymbol{\theta}\leftarrow\boldsymbol{\theta}+\beta*\boldsymbol{g}(s, a ; \boldsymbol{\theta})
θ←θ+β∗g(s,a;θ)
然而在实际情况下随机梯度中的
Q
π
(
s
,
a
)
Q_{\pi}(s, a)
Qπ(s,a)一项并不能被获取,由此就引申出了两种估计方法,分别是REINFORCE与Actor-Critic。
REINFORCE算法用实际观测的回报
u
t
u_t
ut近似估计动作价值函数
Q
π
(
s
,
a
)
Q_{\pi}(s, a)
Qπ(s,a),即将随机梯度更换为
g
~
(
s
t
,
a
t
;
θ
)
=
u
t
⋅
∇
θ
ln
π
(
a
t
∣
s
t
;
θ
)
\tilde{\boldsymbol{g}}\left(s_{t}, a_{t} ; \boldsymbol{\theta}\right)=u_{t} \cdot \nabla_{\boldsymbol{\theta}} \ln \pi\left(a_{t} \mid s_{t} ; \boldsymbol{\theta}\right)
g~(st,at;θ)=ut⋅∇θlnπ(at∣st;θ)
2. 算法伪代码
翻译:当前策略网络控制agent玩完一遍全流程,获得所有的三元组
s
i
,
a
i
,
r
i
s_i,a_i,r_i
si,ai,ri,随后计算回报值
u
t
u_t
ut,然后计算梯度
∇
θ
ln
π
(
a
t
∣
s
t
;
θ
n
o
w
)
\nabla_{\boldsymbol{\theta}} \ln \pi\left(a_{t} \mid s_{t} ; \boldsymbol{\theta}_{now}\right)
∇θlnπ(at∣st;θnow),按照梯度上升更新
θ
\boldsymbol{\theta}
θ,
θ
new
←
θ
now
+
β
⋅
∑
t
=
1
n
γ
t
−
1
⋅
u
t
⋅
∇
θ
ln
π
(
a
t
∣
s
t
;
θ
now
)
⏟
即随机梯度
g
~
(
s
t
,
a
t
;
θ
now
)
\boldsymbol{\theta}_{\text {new }} \leftarrow \boldsymbol{\theta}_{\text {now }}+\beta \cdot \sum_{t=1}^{n} \gamma^{t-1} \cdot \underbrace{u_{t} \cdot \nabla_{\boldsymbol{\theta}} \ln \pi\left(a_{t} \mid s_{t} ; \boldsymbol{\theta}_{\text {now }}\right)}_{\text {即随机梯度 } \tilde{\boldsymbol{g}}\left(s_{t}, a_{t} ; \boldsymbol{\theta}_{\text {now }}\right)}
θnew ←θnow +β⋅∑t=1nγt−1⋅即随机梯度 g~(st,at;θnow )
ut⋅∇θlnπ(at∣st;θnow )。
3. 算法关键代码
class REINFORCE:
def __init__(self, state_dim, hidden_dim, action_dim, learning_rate, gamma, device):
self.policy_net = PolicyNet(state_dim, hidden_dim,action_dim).to(device)
self.optimizer = torch.optim.Adam(self.policy_net.parameters(),lr=learning_rate) # 使用Adam优化器
self.gamma = gamma # 折扣因子
self.device = device
def take_action(self, state): # 根据动作概率分布随机采样
state = torch.tensor([state], dtype=torch.float).to(self.device)
probs = self.policy_net(state)
action_dist = torch.distributions.Categorical(probs)
action = action_dist.sample()
return action.item()
def update(self, transition_dict):
reward_list = transition_dict['rewards']
state_list = transition_dict['states']
action_list = transition_dict['actions']
G = 0
self.optimizer.zero_grad()
for i in reversed(range(len(reward_list))): # 从最后一步算起,越靠后需要乘的gamma次数越高
reward = reward_list[i]
state = torch.tensor([state_list[i]],dtype=torch.float).to(self.device)
action = torch.tensor([action_list[i]]).view(-1, 1).to(self.device)
log_prob = torch.log(self.policy_net(state).gather(1, action)) # ln(π(at|st;θ))
G = self.gamma * G + reward
loss = -log_prob * G # 每一步的损失函数,随机梯度g(at|st;θ)
loss.backward() # 反向传播计算梯度
self.optimizer.step() # 计算完所有的随机梯度与ut乘积和后,梯度下降(前面加负号了)
4. 算法特点
同策略(on-policy)算法,目标策略与行为策略相同,不能够使用经验回放。