第4章:Python强化学习环境搭建

环境搭建,说白了就是给智能体搭个舞台。

我刚开始学强化学习时,最头疼的就是环境这块。理论看了不少,但一上手就发现——连个能跑的环境都没有。后来踩了无数坑,才把 Gymnasium 这套东西摸透。今天我把这些经验整理出来,希望能帮你少走弯路。

4.1 Gymnasium 库安装

Gymnasium 是 OpenAI Gym 的继承者。我个人习惯用这个库,因为它维护更积极,接口也更干净。

安装很简单,一行命令搞定:

pip install gymnasium

如果你想跑一些经典的控制问题,比如倒立摆、小车爬坡,可以安装完整版:

pip install gymnasium[all]
注意: 我曾经在 Windows 上装 mujoco 时卡了半天,后来发现是 Visual C++ 运行时没装。如果你遇到类似问题,先检查下系统环境。

安装完成后,验证一下:

import gymnasium as gym
env = gym.make("CartPole-v1")
print(env.observation_space)
print(env.action_space)

能正常输出,说明环境装好了。

4.2 自定义环境接口

实际项目中,我们很少直接用现成的环境。比如我做过一个期货高频策略,交易所的撮合逻辑跟 Gymnasium 的接口完全不搭。这时候就得自己写环境。

Gymnasium 要求自定义环境继承 gym.Env,并实现几个核心方法:

方法 作用 返回值
__init__ 初始化环境,定义动作空间和观测空间
reset 重置环境到初始状态 观测值, 额外信息
step 执行动作,推进环境 观测值, 奖励, 终止标志, 截断标志, 额外信息
render 可视化环境(可选)

来看一个简单的自定义环境示例——一个股票交易环境:

import gymnasium as gym
from gymnasium import spaces
import numpy as np

class StockTradingEnv(gym.Env):
    def __init__(self, price_data):
        super().__init__()
        self.price_data = price_data
        self.current_step = 0
        
        # 动作空间:0=卖出, 1=持有, 2=买入
        self.action_space = spaces.Discrete(3)
        
        # 观测空间:价格、持仓量、现金
        self.observation_space = spaces.Box(
            low=-np.inf, high=np.inf, shape=(3,), dtype=np.float32
        )
    
    def reset(self, seed=None, options=None):
        self.current_step = 0
        self.position = 0  # 持仓量
        self.cash = 10000  # 初始现金
        return self._get_obs(), {}
    
    def step(self, action):
        price = self.price_data[self.current_step]
        
        # 执行动作
        if action == 0:  # 卖出
            self.cash += self.position * price
            self.position = 0
        elif action == 2:  # 买入
            shares = self.cash // price
            self.cash -= shares * price
            self.position += shares
        
        self.current_step += 1
        done = self.current_step >= len(self.price_data) - 1
        
        # 计算奖励(简单用资产变化)
        total_asset = self.cash + self.position * price
        reward = total_asset - self.last_asset
        self.last_asset = total_asset
        
        return self._get_obs(), reward, done, False, {}
    
    def _get_obs(self):
        price = self.price_data[self.current_step]
        return np.array([price, self.position, self.cash], dtype=np.float32)
经验之谈: 我刚开始写环境时,总把奖励函数搞得很复杂。后来发现,简单直接的奖励往往效果更好。比如上面这个例子,直接用资产变化做奖励,反而比各种加权组合更稳定。

4.3 动作空间与观测空间定义

动作空间和观测空间,是环境与智能体之间的「通信协议」。定义错了,整个训练都会出问题。

4.3.1 动作空间

动作空间告诉智能体:你能做什么。

  • 离散动作空间spaces.Discrete(n),表示 n 个互斥的动作。比如上面股票交易里的 0、1、2。
  • 连续动作空间spaces.Box(low, high, shape),表示一个连续区间。比如控制机器人的关节角度。
  • 复合动作空间spaces.Dictspaces.Tuple,组合多种动作类型。

举个例子,如果你要控制一个交易机器人,既要决定买卖方向(离散),又要决定交易量(连续),就可以用 Dict:

from gymnasium import spaces

action_space = spaces.Dict({
    "direction": spaces.Discrete(3),  # 0=卖, 1=持, 2=买
    "volume": spaces.Box(low=0, high=1, shape=(1,))  # 交易比例
})

4.3.2 观测空间

观测空间告诉智能体:你能看到什么。

常见的观测空间类型:

类型 适用场景 示例
Box 连续数值观测 价格序列、技术指标
Discrete 离散状态 市场状态(牛/熊/震荡)
MultiBinary 多选一状态 持仓品种的涨跌标志
Dict 混合观测 价格+新闻情感+持仓
核心原则: 观测空间要包含智能体做决策所需的全部信息,但不要冗余。我见过有人把 100 个技术指标全塞进去,结果模型根本学不动。少即是多。

4.4 知识体系总览

下面这张图,是我对本章内容的总结。你可以把它当作搭建环境的「导航图」:

强化学习环境搭建知识体系 Gymnasium安装 自定义环境接口 动作/观测空间 pip install gymnasium 验证安装 继承 gym.Env 实现 reset/step 定义奖励函数 Discrete / Box Dict / Tuple MultiBinary 核心流程:安装 → 继承Env → 定义空间 → 实现逻辑 环境是智能体与真实世界的桥梁,定义好坏决定训练成败

4.5 避坑指南

最后,分享几个我踩过的坑:

  • 观测空间范围不匹配:我曾经定义 Box 时用了 low=-1, high=1,但实际数据范围是 [-100, 100],结果模型直接崩了。记得检查数据范围。
  • 奖励函数设计不当:奖励太稀疏,智能体学不动;奖励太密集,智能体学会钻空子。我一般先用简单奖励跑通,再逐步优化。
  • 忘记处理截断标志:Gymnasium 的 step 返回 5 个值,其中第 4 个是截断标志。我刚开始老漏掉,导致训练逻辑出错。
一个小技巧: 写完环境后,先用随机策略跑 1000 步,看看观测值、奖励值是否在合理范围内。这一步能帮你发现 80% 的 bug。

环境搭建是强化学习量化策略的基础。打好这个基础,后面的训练才能顺利推进。嗯,今天就先聊到这里。


专注资料整理