强化学习自定义环境(二)

欢迎回来!在上一篇文章中,我们学习了如何创建一个简单的网格世界环境。今天,我们将在此基础上,探索如何创建更复杂、更接近真实世界问题的环境。让我们开始吧!

1. 引入连续动作空间

在现实世界中,很多问题的动作空间是连续的。比如,控制机器人的力度或者调整温度。让我们将我们的网格世界升级为一个连续的 2D 平面。

import gym
import numpy as np
from gym import spaces

class Continuous2DWorld(gym.Env):
    def __init__(self):
        super(Continuous2DWorld, self).__init__()
        
        # 动作空间:二维连续空间,范围 [-1, 1]
        self.action_space = spaces.Box(low=-1, high=1, shape=(2,), dtype=np.float32)
        
        # 观察空间:agent 的位置,范围 [0, 10]
        self.observation_space = spaces.Box(low=0, high=10, shape=(2,), dtype=np.float32)
        
        self.agent_pos = None
        self.goal_pos = np.array([8.0, 8.0])
        
    def reset(self):
        self.agent_pos = np.random.uniform(0, 10, size=(2,))
        return self.agent_pos
    
    def step(self, action):
        # 更新 agent 位置
        self.agent_pos += action
        self.agent_pos = np.clip(self.agent_pos, 0, 10)
        
        # 计算到目标的距离
        distance = np.linalg.norm(self.agent_pos - self.goal_pos)
        
        # 计算奖励和是否结束
        reward = -distance  # 负的距离作为奖励
        done = distance < 0.1  # 当距离小于 0.1 时视为到达目标
        
        return self.agent_pos, reward, done, {}

    def render(self):
        print(f"Agent 位置: {self.agent_pos}, 目标位置: {self.goal_pos}")

在这个新环境中:

  • 动作空间是一个 2D 连续空间,表示 agent 在 x 和 y 方向上的移动。
  • 观察空间是 agent 在 2D 平面上的位置。
  • 奖励是 agent 到目标的负距离,鼓励 agent 尽快接近目标。

2. 设计更复杂的奖励函数

好的奖励函数设计对于学习效果至关重要。让我们为我们的环境设计一个更复杂的奖励函数。

def compute_reward(self):
    distance = np.linalg.norm(self.agent_pos - self.goal_pos)
    
    # 基础奖励:负的距离
    base_reward = -distance
    
    # 速度奖励:鼓励 agent 保持移动
    speed_reward = np.linalg.norm(self.last_action) if hasattr(self, 'last_action') else 0
    
    # 接近目标奖励
    proximity_reward = 1.0 if distance < 1.0 else 0.0
    
    # 惩罚项:如果 agent 碰到边界
    boundary_penalty = -1.0 if np.any(self.agent_pos == 0) or np.any(self.agent_pos == 10) else 0.0
    
    return base_reward + 0.1 * speed_reward + proximity_reward + boundary_penalty

def step(self, action):
    self.last_action = action
    self.agent_pos += action
    self.agent_pos = np.clip(self.agent_pos, 0, 10)
    
    reward = self.compute_reward()
    done = np.linalg.norm(self.agent_pos - self.goal_pos) < 0.1
    
    return self.agent_pos, reward, done, {}

这个新的奖励函数考虑了多个因素:

  • 到目标的距离
  • agent 的移动速度
  • 是否接近目标
  • 是否碰到环境边界

这种复杂的奖励函数可以引导 agent 学习更复杂的行为。

3. 添加环境随机性

真实世界是充满不确定性的。让我们给我们的环境添加一些随机性。

class StochasticContinuous2DWorld(Continuous2DWorld):
    def __init__(self, noise_level=0.1):
        super().__init__()
        self.noise_level = noise_level
    
    def step(self, action):
        # 添加噪声到动作
        noisy_action = action + np.random.normal(0, self.noise_level, size=action.shape)
        return super().step(noisy_action)
    
    def reset(self):
        self.agent_pos = np.random.uniform(0, 10, size=(2,))
        self.goal_pos = np.random.uniform(0, 10, size=(2,))  # 目标位置也随机化
        return self.agent_pos

这个版本的环境增加了两种随机性:

  • 动作执行时有噪声,模拟现实世界中的不精确控制。
  • 每次重置时,目标位置也随机化,增加了任务的难度。

4. 实现障碍物

让我们给我们的 2D 世界添加一些障碍物,使环境更加复杂和真实。

class Obstacle2DWorld(StochasticContinuous2DWorld):
    def __init__(self, num_obstacles=5):
        super().__init__()
        self.num_obstacles = num_obstacles
        self.obstacles = []
    
    def reset(self):
        self.agent_pos = np.random.uniform(0, 10, size=(2,))
        self.goal_pos = np.random.uniform(0, 10, size=(2,))
        
        # 生成随机障碍物
        self.obstacles = []
        for _ in range(self.num_obstacles):
            obs_pos = np.random.uniform(0, 10, size=(2,))
            obs_radius = np.random.uniform(0.5, 1.0)
            self.obstacles.append((obs_pos, obs_radius))
        
        return self.agent_pos
    
    def step(self, action):
        new_pos = self.agent_pos + action
        
        # 检查是否碰到障碍物
        for obs_pos, obs_radius in self.obstacles:
            if np.linalg.norm(new_pos - obs_pos) < obs_radius:
                return self.agent_pos, -1, False, {"collision": True}
        
        self.agent_pos = np.clip(new_pos, 0, 10)
        
        distance = np.linalg.norm(self.agent_pos - self.goal_pos)
        reward = -distance
        done = distance < 0.1
        
        return self.agent_pos, reward, done, {}

    def render(self):
        print(f"Agent 位置: {self.agent_pos}")
        print(f"目标位置: {self.goal_pos}")
        print("障碍物:")
        for i, (obs_pos, obs_radius) in enumerate(self.obstacles):
            print(f"  障碍物 {i+1}: 位置 = {obs_pos}, 半径 = {obs_radius}")

这个新版本的环境添加了随机生成的圆形障碍物。如果 agent 碰到障碍物,会得到惩罚并停止移动。

5. 使用 Wrapper 增强环境

Gym 提供了 Wrapper 机制,允许我们在不修改原始环境的情况下增加新的功能。让我们创建一个 Wrapper 来记录 agent 的轨迹。

class TrajectoryRecorder(gym.Wrapper):
    def __init__(self, env):
        super().__init__(env)
        self.trajectory = []
    
    def reset(self):
        self.trajectory = []
        return self.env.reset()
    
    def step(self, action):
        observation, reward, done, info = self.env.step(action)
        self.trajectory.append(observation)
        return observation, reward, done, info
    
    def get_trajectory(self):
        return np.array(self.trajectory)

# 使用方法
env = TrajectoryRecorder(Obstacle2DWorld())

这个 Wrapper 记录了 agent 在每个回合中的完整轨迹,可以用于后续的分析或可视化。

总结

在这篇教程中,我们学习了如何将简单的网格世界升级为更复杂、更真实的环境:

  1. 引入了连续动作空间,更接近真实世界的控制问题。
  2. 设计了更复杂的奖励函数,引导 agent 学习复杂行为。
  3. 添加了环境随机性,增加了任务的难度和真实性。
  4. 实现了障碍物,使环境更加复杂和有挑战性。
  5. 使用 Wrapper 来增强环境功能,而不需要修改原始环境。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值