首页 > 解决方案 > 连续 DDPG 似乎没有收敛于二维空间搜索问题(“Hunt the Thimble”)

问题描述

我尝试使用连续动作空间 DDPG来解决以下控制问题。目标是通过在每一步被告知一个人与目标位置的距离(类似于这个儿童游戏,玩家由“温度”水平引导,热和冷)。

在设置中,目标位置是固定的,而代理的起始位置因情节而异。目标是学习尽可能快地向目标位置行走的策略。代理的观察仅包括其当前位置。关于奖励设计,我考虑了Reacher 环境,因为它涉及类似的目标,并且类似地使用控制奖励距离奖励(参见下面的代码)。越来越接近目标会产生更大的奖励,并且代理越接近它应该越倾向于较小的动作。

对于实现,我考虑了openai/spinningup包。关于网络架构,我认为,如果目标位置已知,则最佳action = target - position动作将pi(x) -> aa = W @ x + b收敛(理想情况下),W = -np.eye(2)b = target。由于环境施加了动作限制,因此可能无法在单个步骤中达到目标位置,因此我手动将计算的动作缩放为a = a / tf.norm(a) * action_limit. 这保留了朝向目标的方向,因此仍然类似于最佳动作。我将此自定义架构用于策略网络以及具有 3 个隐藏层的标准 MLP 架构(请参见下面的代码和结果)。

结果

在 MLP 案例中运行了大约 400 集的算法,在自定义策略案例中运行了 700 集之后,每集 1000 步,它似乎没有学到任何有用的东西。在测试运行期间,平均回报没有增加,当我检查三个不同起始位置的行为时,它总是走向(0, 1)区域的角落;即使它从目标位置旁边开始,它也会经过它,前往(0, 1)拐角处。我注意到的是自定义策略架构代理导致的标准要小得多。开发。测试集的返回。

问题

我想了解为什么该算法似乎没有为给定的设置学习任何东西,以及需要更改哪些内容才能使其收敛。我怀疑实现或超参数的选择存在问题,因为我无法发现在给定设置中学习策略的任何概念问题。但是我无法查明问题的根源,所以如果有人可以提供帮助,我会很高兴。


平均测试回报(自定义策略架构):

平均测试回报(自定义策略架构)

(垂直条表示测试集返回的标准开发)

平均测试回报(MLP 策略架构):

平均测试回报(MLP 策略架构)

测试用例(自定义策略架构):

测试用例(自定义策略架构)

测试用例(MLP 策略架构):

测试用例(MLP 策略架构)

代码

import logging
import os
import gym
from gym.wrappers.time_limit import TimeLimit
import numpy as np
from spinup.algos.ddpg.ddpg import core, ddpg
import tensorflow as tf


class TestEnv(gym.Env):
    target = np.array([0.7, 0.8])
    action_limit = 0.01
    observation_space = gym.spaces.Box(low=np.zeros(2), high=np.ones(2), dtype=np.float32)
    action_space = gym.spaces.Box(-action_limit * np.ones(2), action_limit * np.ones(2), dtype=np.float32)

    def __init__(self):
        super().__init__()
        self.pos = np.empty(2, dtype=np.float32)
        self.reset()

    def step(self, action):
        self.pos += action
        self.pos = np.clip(self.pos, self.observation_space.low, self.observation_space.high)
        reward_ctrl = -np.square(action).sum() / self.action_limit**2
        reward_dist = -np.linalg.norm(self.pos - self.target)
        reward = reward_ctrl + reward_dist
        done = abs(reward_dist) < 1e-9
        logging.debug('Observation: %s', self.pos)
        logging.debug('Reward: %.6f (reward (ctrl): %.6f, reward (dist): %.6f)', reward, reward_ctrl, reward_dist)
        return self.pos, reward, done, {}

    def reset(self):
        self.pos[:] = np.random.uniform(self.observation_space.low, self.observation_space.high, size=2)
        logging.info(f'[Reset] New position: {self.pos}')
        return self.pos

    def render(self, *args, **kwargs):
        pass


def mlp_actor_critic(x, a, hidden_sizes, activation=tf.nn.relu, action_space=None):
    act_dim = a.shape.as_list()[-1]
    act_limit = action_space.high[0]
    with tf.variable_scope('pi'):
        # pi = core.mlp(x, list(hidden_sizes)+[act_dim], activation, output_activation=None)  # The standard way.
        pi = tf.layers.dense(x, act_dim, use_bias=True)  # Target position should be learned via the bias term.
        pi = pi / (tf.norm(pi) + 1e-9) * act_limit  # Prevent division by zero.
    with tf.variable_scope('q'):
        q = tf.squeeze(core.mlp(tf.concat([x,a], axis=-1), list(hidden_sizes)+[1], activation, None), axis=1)
    with tf.variable_scope('q', reuse=True):
        q_pi = tf.squeeze(core.mlp(tf.concat([x,pi], axis=-1), list(hidden_sizes)+[1], activation, None), axis=1)
    return pi, q, q_pi


if __name__ == '__main__':
    log_dir = 'spinup-ddpg'
    if not os.path.exists(log_dir):
        os.mkdir(log_dir)
    logging.basicConfig(level=logging.INFO)
    ep_length = 1000
    ddpg(
        lambda: TimeLimit(TestEnv(), ep_length),
        mlp_actor_critic,
        ac_kwargs=dict(hidden_sizes=(64, 64, 64)),
        steps_per_epoch=ep_length,
        epochs=1_000,
        replay_size=1_000_000,
        start_steps=10_000,
        act_noise=TestEnv.action_limit/2,
        gamma=0.99,  # Use large gamma, because of action limit it matters where we walk to early in the episode.
        polyak=0.995,
        max_ep_len=ep_length,
        save_freq=10,
        logger_kwargs=dict(output_dir=log_dir)
    )

标签: pythonpython-3.xmachine-learningreinforcement-learningopenai-gym

解决方案


您正在使用一个巨大的网络(64x64x64)来解决一个非常小的问题。仅此一项就可能是一个大问题。您还在内存中保留了 1M 样本,同样,对于一个非常简单的问题,这可能是有害且收敛缓慢的。首先尝试使用更简单的设置(32x32 网络和 100,000 内存,甚至是具有多项式特征的线性逼近器)。另外,您如何更新目标网络?是什么polyak?最后,像这样规范化操作可能不是一个好主意。最好只剪辑它或在最后使用 tanh 层。


推荐阅读