强化学习初探——以gym库中的CartPole环境为例

Cart-Pole问题中的相关概念、定义

Cart-Pole问题

Cart-Pole问题(即推车-杆问题)是Barto、Sutton和Anderson在论文《Neuronlike Adaptive Elements That Can Solve Difficult Learning Control Problem》中提出的一个问题:
一根杆子通过一个非驱动关节连接到一辆推车上,推车沿着一条无摩擦的轨道移动。钟摆直立在车上,目标是通过在推车上施加左右方向的力来平衡杆子,使其尽可能长时间地保持杆子直立。

行为空间(对应Action)

行为空间中有两个行为:

行为含义
0对推车施加向左的力
1对推车施加向右的力

同时,在上述行为的作用下,推车速度降低或提高的速度并不是固定的,而是取决于杆子所指向的方向(因为杆子重心的改变使得移动推车所需的能量改变)。

状态空间(对应State)

状态空间中有四个属性(因此每一个state都有四个值,state=[value0、value1、value2、value3]):

对应下标属性最小值最大值
0推车位置-4.84.8
1推车速度-Inf-Inf
2杆子角度-0.418 rad (-24°)0.418 rad (-24°)
3杆子角速度-Inf-Inf

上述最小值~最大值范围表示每个元素状态空间的可能值,但是它并不反映在整个强化学习训练的迭代过程中状态空间的允许值理解:某些值可以出现,但出现之后不被程序允许,可能导致事件终止),比如:

  • 推车的位置可以取-4.8 ~ 4.8之间的值,但如果推车的位置不在-2.4 ~ 2.4中,那么事件会终止。
  • 杆子的角度可以在-0.418 rad ~ 0. 418 rad/-24° ~ 24°之间,但如果杆子的角度不在-0.2095 rad ~ 0. 2095 rad/-12° ~ 12°之间,那么事件会终止。

奖励(对应Reward)

需要根据目标设置奖励的计算方法,在Cart-Pole问题中,目标是使得杆子尽可能长时间地保持直立,因此采取了在每轮的训练过程中,在未进行下一轮训练前,事件(包括终止事件)的长度
在v1环境中,奖励的最高阈值为475。

Cart-Pole问题的编程实现

初始状态设置

在设置初始状态时,选择赋予所有的观察值一个均匀的随机值(-0.05, 0.05)

    def reset(
        self,
        *,
        seed: Optional[int] = None,
        options: Optional[dict] = None,
    ):
        super().reset(seed=seed)
        # Note that if you use custom reset bounds, it may lead to out-of-bound
        # state/observations.
        low, high = utils.maybe_parse_reset_bounds(
            options, -0.05, 0.05  # default low
        )  # default high
        self.state = self.np_random.uniform(low=low, high=high, size=(4,))
        self.steps_beyond_terminated = None

        if self.render_mode == "human":
            self.render()
        return np.array(self.state, dtype=np.float32), {}

终止条件定义

如果出现以下任何一种情况,事件将会结束:

  1. 事件终止:杆子角度的绝对值大于12°;
  2. 事件终止:推车位置的绝对值大于2.4(推车中心到达图形界面的边缘);
  3. 事件截断:事件长度超过500(v0为200)。
    def step(self, action):
        err_msg = f"{action!r} ({type(action)}) invalid"
        assert self.action_space.contains(action), err_msg
        assert self.state is not None, "Call reset before using step method."
        x, x_dot, theta, theta_dot = self.state		# 获取各属性的值
        force = self.force_mag if action == 1 else -self.force_mag	# 根据action获取力的大小及方向
        costheta = math.cos(theta)
        sintheta = math.sin(theta)

        # For the interested reader:
        # https://coneural.org/florian/papers/05_cart_pole.pdf
        temp = (
            force + self.polemass_length * theta_dot**2 * sintheta
        ) / self.total_mass
        thetaacc = (self.gravity * sintheta - costheta * temp) / (
            self.length * (4.0 / 3.0 - self.masspole * costheta**2 / self.total_mass)
        )
        xacc = temp - self.polemass_length * thetaacc * costheta / self.total_mass

        if self.kinematics_integrator == "euler":
            x = x + self.tau * x_dot
            x_dot = x_dot + self.tau * xacc
            theta = theta + self.tau * theta_dot
            theta_dot = theta_dot + self.tau * thetaacc
        else:  # semi-implicit euler
            x_dot = x_dot + self.tau * xacc
            x = x + self.tau * x_dot
            theta_dot = theta_dot + self.tau * thetaacc
            theta = theta + self.tau * theta_dot

        self.state = (x, x_dot, theta, theta_dot)

		# 事件终止标志
        terminated = bool(
            x < -self.x_threshold
            or x > self.x_threshold
            or theta < -self.theta_threshold_radians
            or theta > self.theta_threshold_radians
        )

        if not terminated:
            reward = 1.0
        elif self.steps_beyond_terminated is None:
            # Pole just fell!
            self.steps_beyond_terminated = 0
            reward = 1.0
        else:
            if self.steps_beyond_terminated == 0:
                logger.warn(
                    "You are calling 'step()' even though this "
                    "environment has already returned terminated = True. You "
                    "should always call 'reset()' once you receive 'terminated = "
                    "True' -- any further steps are undefined behavior."
                )
            self.steps_beyond_terminated += 1
            reward = 0.0

        if self.render_mode == "human":
            self.render()
        return np.array(self.state, dtype=np.float32), reward, terminated, False, {}

Tips:
①事件是episode的翻译;
②上述部分定义仅针对于官方对于CartPole环境的实现,可以自己根据需要重新定义。

Reference

[1] gym官方仓库中CartPole环境的源代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hylan_J

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值