因此,我正在处理的问题可以总结如下:
观察空间是一个 8x1 向量,都是连续值。其中一些在 [-inf, inf] 范围内,一些在 [-360, 360] 范围内。
动作空间是一个 4x1 向量。所有值都在 [-1, 1] 范围内。
目前,我正在尝试使用策略梯度算法,特别是 REINFORCE 算法来解决它。
由于动作空间是连续的,在输出层我得到了 4 mu 和 4 sigma 的值,我将它们用作正态分布的参数来对动作进行采样。
使用神经网络作为函数逼近器和 NN 架构是:
- 输入层:8个神经元
- 隐藏层 1:256 个具有 ReLU 激活的神经元
- 隐藏层 2:具有 ReLU 激活的 256 个神经元
- 输出层:8个神经元
- 没有激活函数的 mu 有 4 个神经元,因此可以取 [-inf, inf] 范围内的任何值。但是,稍后在对动作进行采样后,我将它们的值剪辑在 [-1, 1] 之间。用于 sigma 的 4 个神经元,激活 ELU +0.001,以将标准偏差值保持在 [0.001, inf] 范围内。
我的奖励功能是在一个情节中,
- 在代理处于某个目标区域内的每个时间步长上,它都会获得 +6000 奖励
- 每次不在区域内的时间步都会得到 -20
- 在剧集结束时,如果它不在目标区域内,它会得到 -20000
- 如果它在剧集中进入 BAD 状态,它将获得 -100000 奖励并且剧集立即结束。
损失函数是:
loss = - log_prob(action) * R
解决方案似乎没有收敛,因为平均值不断增加并且 sigma 值停留在 0.001(这是它们的最小可能值)。我想问的问题是:
- 我对动作进行采样的方式是否正确?
- 损失函数看起来对吗?
- 我是否也应该在输入层使用 ReLU 激活(虽然这对我来说听起来不对,但是,在我看到的一些 PPO 算法的实现中,人们也在输入端使用 ReLU)
如果需要指出问题,我也可以共享代码。
也欢迎任何其他建议。
编辑:顺便说一句,我为这个问题编写了自己的健身房环境,这就是为什么您可能会注意到我的代码与用于解决 OpenAI 健身房相关问题的典型 RL 代码之间存在一些不一致的原因。运行 num_episodes 的主循环是:
def main():
global num_episodes, normalized_reward_history, reward_history
env = gym.make('gymXplane-v2')
pi = Policy()
for n_epi in range(1, TOTAL_EPISODES+1):
env.reset()
sleep(2)
done = False
initial_obs = (env.getObservationSpace())
obs= torch.from_numpy(initial_obs).float().squeeze()
steps = 0
while not done:
steps += 1
step_arr.append(steps)
output = pi.forward(obs, softmax_dim=1)
means = output[:int(ACTION_SPACE_SIZE / 2)]
sigs = output[int(ACTION_SPACE_SIZE / 2):]
dists = torch.distributions.Normal(means, sigs)
action_samples = dists.sample().clamp(-1.0, 1.0)
obs_prime, reward, done, info = env.step(action_samples)
pi.put_data((reward), (action_samples, dists))
obs = torch.t(torch.from_numpy(obs_prime).float())[0]
pi.train_net()
env.close()
py.train_net()
如下_
def train_net(self):
global normalized_reward_history, reward_history
R = 0
self.optimizer.zero_grad()
cumulative = 0
discounted_rewards = np.zeros(len(self.reward_arr))
for t in reversed(range(len(self.reward_arr))): # get discounted rewards
cumulative = cumulative * GAMMA + self.reward_arr[t]
discounted_rewards[t] = cumulative
normalized_rewards = discounted_rewards - np.mean(discounted_rewards)
if np.std(discounted_rewards) != 0:
normalized_rewards /= np.std(normalized_rewards)
data = list(zip(normalized_rewards, self.action_arr))
for R, action in data[::-1]:
samples = action[0]
dists = action[1]
loss = - dists.log_prob(samples) * R
loss = loss.mean()
loss.backward()
self.optimizer.step()