AirSim 中的强化学习#

我们将在下面描述如何使用 AirSim API 的 OpenAI gym 封装器,以及使用标准 RL 算法的 stable-baselines 实现,在 AirSim 中实现 DQN。我们建议安装 stable-baselines3 来运行这些示例(请参阅 https://github.com/DLR-RM/stable-baselines3)

免责声明#

这仍在积极开发中。我们下面分享的是一个可以扩展和调整以获得更好性能的框架。

Gym 封装器#

为了将 AirSim 用作 gym 环境,我们扩展并重新实现了 AirSim 和感兴趣任务特有的基本方法,例如 step_get_obs_compute_rewardreset。这些示例中用于汽车和无人机的示例环境可以在 PythonClient/reinforcement_learning/*_env.py 中看到

汽车强化学习#

源代码

此示例适用于发布版本中提供的 AirSimNeighborhood 环境。

首先,我们需要从模拟中获取图像并对其进行适当的转换。下面,我们展示如何从自我摄像机获取深度图像并将其转换为网络的 84X84 输入。(您也可以使用其他传感器模式和传感器输入——当然,您必须相应地修改代码)。

responses = client.simGetImages([ImageRequest(0, AirSimImageType.DepthPerspective, True, False)])
current_state = transform_input(responses)

我们进一步定义了智能体可以执行的六种动作(刹车、带油门直行、带油门全左转、带油门全右转、带油门半左转、带油门半右转)。这是通过函数 interpret_action 完成的

def interpret_action(action):
    car_controls.brake = 0
    car_controls.throttle = 1
    if action == 0:
        car_controls.throttle = 0
        car_controls.brake = 1
    elif action == 1:
        car_controls.steering = 0
    elif action == 2:
        car_controls.steering = 0.5
    elif action == 3:
        car_controls.steering = -0.5
    elif action == 4:
        car_controls.steering = 0.25
    else:
        car_controls.steering = -0.25
    return car_controls

然后我们在 _compute_reward 中将奖励函数定义为车辆行驶速度和其偏离中心线的程度的凸组合。当智能体快速移动并保持在车道中心时,它会获得高奖励。

def _compute_reward(car_state):
    MAX_SPEED = 300
    MIN_SPEED = 10
    thresh_dist = 3.5
    beta = 3

    z = 0
    pts = [np.array([0, -1, z]), np.array([130, -1, z]), np.array([130, 125, z]), np.array([0, 125, z]), np.array([0, -1, z]), np.array([130, -1, z]), np.array([130, -128, z]), np.array([0, -128, z]), np.array([0, -1, z])]
    pd = car_state.position
    car_pt = np.array(list(pd.values()))

    dist = 10000000
    for i in range(0, len(pts)-1):
        dist = min(dist, np.linalg.norm(np.cross((car_pt - pts[i]), (car_pt - pts[i+1])))/np.linalg.norm(pts[i]-pts[i+1]))

    #print(dist)
    if dist > thresh_dist:
        reward = -3
    else:
        reward_dist = (math.exp(-beta*dist) - 0.5)
        reward_speed = (((car_state.speed - MIN_SPEED)/(MAX_SPEED - MIN_SPEED)) - 0.5)
        reward = reward_dist + reward_speed

    return reward

计算奖励函数随后还会确定剧集是否已终止(例如由于碰撞)。我们查看车辆的速度,如果它低于阈值,则认为剧集已终止。

done = 0
if reward < -1:
    done = 1
if car_controls.brake == 0:
    if car_state.speed <= 5:
        done = 1
return done

主循环然后依次获取图像,根据当前策略计算要采取的动作,获取奖励等等。如果剧集终止,我们通过 reset() 将车辆重置为原始状态

client.reset()
client.enableApiControl(True)
client.armDisarm(True)
car_control = interpret_action(1) // Reset position and drive straight for one second
client.setCarControls(car_control)
time.sleep(1)

一旦在 car_env.py 中定义了 gym 风格的环境封装器,我们就可以使用 stable-baselines3 来运行 DQN 训练循环。DQN 训练可以配置如下,如 dqn_car.py 所示。

model = DQN(
    "CnnPolicy",
    env,
    learning_rate=0.00025,
    verbose=1,
    batch_size=32,
    train_freq=4,
    target_update_interval=10000,
    learning_starts=200000,
    buffer_size=500000,
    max_grad_norm=10,
    exploration_fraction=0.1,
    exploration_final_eps=0.01,
    device="cuda",
    tensorboard_log="./tb_logs/",
)

可以定义一个训练环境和一个评估环境(请参阅 dqn_car.py 中的 EvalCallback)。评估环境可以与训练不同,具有不同的终止条件/场景配置。Tensorboard 日志目录也作为 DQN 参数的一部分定义。最后,model.learn() 启动 DQN 训练循环。同样,PPO、A3C 等的实现也可以从 stable-baselines3 中使用。

请注意,在执行 dqn_car.py 之前,模拟需要启动并运行。下面的视频展示了 DQN 训练的前几集。

Reinforcement Learning - Car

四旋翼飞行器强化学习#

源代码

此示例适用于发布版本中提供的 AirSimMountainLandscape 环境。

我们也可以类似地将强化学习应用于各种四旋翼自主飞行场景。下面是一个示例,说明如何使用强化学习来训练四旋翼飞行器跟随高压输电线(例如,用于能源基础设施检查的应用)。这里有七个离散动作,对应于四旋翼飞行器可以移动的不同方向(六个方向 + 一个悬停动作)。

def interpret_action(self, action):
    if action == 0:
        quad_offset = (self.step_length, 0, 0)
    elif action == 1:
        quad_offset = (0, self.step_length, 0)
    elif action == 2:
        quad_offset = (0, 0, self.step_length)
    elif action == 3:
        quad_offset = (-self.step_length, 0, 0)
    elif action == 4:
        quad_offset = (0, -self.step_length, 0)
    elif action == 5:
        quad_offset = (0, 0, -self.step_length)
    else:
        quad_offset = (0, 0, 0)

奖励再次是四旋翼飞行速度以及它离已知输电线有多远的函数。

def compute_reward(quad_state, quad_vel, collision_info):
    thresh_dist = 7
    beta = 1

    z = -10
    pts = [np.array([-0.55265, -31.9786, -19.0225]),np.array([48.59735, -63.3286, -60.07256]),np.array([193.5974, -55.0786, -46.32256]),np.array([369.2474, 35.32137, -62.5725]),np.array([541.3474, 143.6714, -32.07256]),]

    quad_pt = np.array(list((self.state["position"].x_val, self.state["position"].y_val,self.state["position"].z_val,)))

    if self.state["collision"]:
        reward = -100
    else:
        dist = 10000000
        for i in range(0, len(pts) - 1):
            dist = min(dist, np.linalg.norm(np.cross((quad_pt - pts[i]), (quad_pt - pts[i + 1]))) / np.linalg.norm(pts[i] - pts[i + 1]))

        if dist > thresh_dist:
            reward = -10
        else:
            reward_dist = math.exp(-beta * dist) - 0.5
            reward_speed = (np.linalg.norm([self.state["velocity"].x_val, self.state["velocity"].y_val, self.state["velocity"].z_val,])- 0.5)
            reward = reward_dist + reward_speed

如果无人机偏离已知输电线坐标太远,我们就认为剧集终止,然后将无人机重置到其起点。

一旦在 drone_env.py 中定义了 gym 风格的环境封装器,我们就可以使用 stable-baselines3 来运行 DQN 训练循环。DQN 训练可以配置如下,如 dqn_drone.py 所示。

model = DQN(
    "CnnPolicy",
    env,
    learning_rate=0.00025,
    verbose=1,
    batch_size=32,
    train_freq=4,
    target_update_interval=10000,
    learning_starts=10000,
    buffer_size=500000,
    max_grad_norm=10,
    exploration_fraction=0.1,
    exploration_final_eps=0.01,
    device="cuda",
    tensorboard_log="./tb_logs/",
)

可以定义一个训练环境和一个评估环境(请参阅 dqn_drone.py 中的 EvalCallback)。评估环境可以与训练不同,具有不同的终止条件/场景配置。Tensorboard 日志目录也作为 DQN 参数的一部分定义。最后,model.learn() 启动 DQN 训练循环。同样,PPO、A3C 等的实现也可以从 stable-baselines3 中使用。

这是训练期间前几集的视频。

Reinforcement Learning - Quadrotor

另请参阅 Microsoft 深度学习和机器人车库分会提供的《自动驾驶烹饪手册》