强化学习实战5——BaseLine3使用自定义环境训练【输入状态向量】

简介

想要学会将BL3接入自定义的环境需要做两件事:

第零,你得对自己的任务熟悉,知晓观测空间、动作空间、奖励函数如何设计,根据需求决定要用的模型,再开始写代码。

第一,明确Gym的环境配置,了解需要自己手写哪些函数?配置哪些参数?

第二,套用训练模板,根据你预先决定使用的模型抄模板就行,官方是提供了这些常用模型的示例代码

第零步,我们这次教程使用之前编写的Predator环境,动作空间是离散的,状态空间也是离散的,可以使用A2C模型(也可以用DQN等)。

我们先完成第一步,明确Gym的环境配置,写出需要自定义的函数。【这部分内容之前讲过了】

Gymnasium 环境简介

https://gymnasium.farama.org/api/env/

Gymnasium 环境(Env)的核心标准 API 非常简洁,主要由 4 个核心函数2 个核心属性 组成。这是所有强化学习任务交互的基础。

🧠 1. 核心交互函数

这些是你在训练循环(Training Loop)中必须调用的函数。

函数名 参数/说明 返回值 (Tuple)
.reset() (重置环境) 作用 :在每个回合(Episode)开始前调用,将环境恢复到初始状态。 参数seed (可选,用于复现实验结果), options (特定环境的额外参数)。 1. observation :初始环境状态(符合 observation_space 定义)。 2. info:辅助诊断信息(字典)。
.step(action) (执行动作) 作用 :这是强化学习的核心。将 Agent 的动作(Action)传入环境,环境反馈下一步的状态和奖励。 参数action (Agent 选择的动作)。 1. observation :执行动作后的新环境状态。 2. reward :该动作获得的奖励(浮点数)。 3. terminated :布尔值。True 表示回合正常结束(如到达目标/坠毁)。 4. truncated :布尔值。True 表示回合被强制截断(如超时/出界)。 5. info:辅助诊断信息。
.render() (渲染画面) 作用 :将环境的当前状态可视化。 注意 :在 gymnasium.make() 时需指定 render_mode(如 "human", "rgb_array")。 根据 render_mode 不同而不同: * "human":通常返回 None (直接在窗口显示)。 * "rgb_array":返回图像帧 np.ndarray。 * "ansi":返回文本字符串。
.close() (关闭环境) 作用 :释放环境占用的资源(如关闭 Pygame 窗口、数据库连接等)。 建议:在脚本结束或训练完成后调用。 None

📏 2. 核心属性 (Spaces)

在编写代码前,你需要通过这两个属性来了解环境的输入输出规格:

  • .action_space

    • 含义:定义了 Agent 可以采取的所有合法动作的范围。
    • 用途 :用于构建 Agent 的输出层。例如,如果是 Discrete(4),说明有 4 个离散动作(如 Lunar Lander 的 0, 1, 2, 3)。
    • 常用方法sample() (随机采样一个动作)。
  • .observation_space

    • 含义:定义了环境状态(观测值)的数据结构和范围。
    • 用途 :用于构建 Agent 的输入层。例如,Box(4,) 表示一个包含 4 个浮点数的数组。
    • 常用方法sample() (随机采样一个观测值,常用于测试)。

🛠️ 3. 辅助属性与函数

  • .metadata :包含环境的元信息,比如支持的渲染模式 (render_modes) 和帧率 (render_fps)。
  • .spec :环境的配置规格,通常在通过 gymnasium.make() 创建时生成。
  • .np_random:环境内部的随机数生成器,用于保证实验的可复现性 (Reproducibility)。

📝 总结代码模板

一个标准的 自定义环境类 模板长这样:

https://stable-baselines3.readthedocs.io/en/master/guide/custom_env.html

python 复制代码
import gymnasium as gym
import numpy as np
from gymnasium import spaces


class CustomEnv(gym.Env):
    """Custom Environment that follows gym interface."""

    metadata = {"render_modes": ["human"], "render_fps": 30}

    def __init__(self, arg1, arg2, ...):
        super().__init__()
        # Define action and observation space
        # They must be gym.spaces objects
        # Example when using discrete actions:
        self.action_space = spaces.Discrete(N_DISCRETE_ACTIONS)
        # Example for using image as input (channel-first; channel-last also works):
        self.observation_space = spaces.Box(low=0, high=255,
                                            shape=(N_CHANNELS, HEIGHT, WIDTH), dtype=np.uint8)

    def step(self, action):
        ...
        return observation, reward, terminated, truncated, info

    def reset(self, seed=None, options=None):
        ...
        return observation, info

    def render(self):
        ...

    def close(self):
        ...

我们要按要求修改我们的envCube类。

首先,可以看出,自定义环境要继承gym.Env。

其次需要指定action_space和observation_space。

python 复制代码
self.action_space = gym.spaces.Discrete(ACTION_SPACE_VALUES)
self.observation_space = gym.spaces.Box(low=-SIZE+1, high=SIZE-1,
                                            shape=(4,), dtype=int)

注意,动作空间是9个,是离散的,因此使用Discrete。而观察空间其实也是离散的,但是这里还是使用了连续的Box,Box有四个参数,分别是连续区间的最小最大值,状态向量的维度,以及单个数据类型。我们设定的是SIZE*SIZE的棋盘,状态用(x1,y1,x2,y2)这个(4,)tuple表示。

(注意一下,更新后spaces.Discrete、spaces_Box都无法直接用,要加前缀gym)

写出来应该如下:

python 复制代码
    def __init__(self,SIZE=10,
                 ACTION_SPACE_VALUES = 9,
                 RETURN_IMAGE = True,
                 MAX_STEP=200,
                 FOOD_REWARD = 25,
                 ENEMY_PENALITY = -300,
                 MOVE_PENALITY = -1):
        super(envCube,self).__init__()
        
        self.SIZE=SIZE
        #self.OBSERVATION_SPACE_VALUES=(SIZE,SIZE,3)
        self.OBSERVATION_SPACE_VALUES=(4,)
        #self.ACTION_SPACE_VALUES=ACTION_SPACE_VALUES
        self.RETURN_IMAGE = RETURN_IMAGE  # 考虑返回值是否图像
        self.MAX_STEP=MAX_STEP
    
        self.FOOD_REWARD = FOOD_REWARD  # agent获得食物的奖励
        self.ENEMY_PENALITY = ENEMY_PENALITY  # 遇上对手的惩罚
        self.MOVE_PENALITY = MOVE_PENALITY  # 每移动一步的惩罚

        self.action_space = gym.spaces.Discrete(ACTION_SPACE_VALUES)
        self.observation_space = gym.spaces.Box(low=-SIZE+1, high=SIZE-1,
                                            shape=(4,), dtype=int)

然后我们验证一下

为了检测我们的环境是否符合gym的要求,可以使用这个函数验证

肯定会遇到不少报错,但都很好解决,基本就是把observation改为np.array的形式,而不是tuple。以及返回需要添加info的问题。

下面这个是能跑通的:

python 复制代码
class envCube(gym.Env):
    # 设定三个部分的颜色分别是蓝、绿、红
    d = {1: (255, 0, 0),  # blue
        2: (0, 255, 0),  # green
        3: (0, 0, 255)}  # red
    PLAYER_N = 1
    FOOD_N = 2
    ENEMY_N = 3
    
    metadata = {"render_modes": ["human"], "render_fps": 30}
    
    def __init__(self,SIZE=10,
                 ACTION_SPACE_VALUES = 9,
                 RETURN_IMAGE = False,
                 MAX_STEP=200,
                 FOOD_REWARD = 25,
                 ENEMY_PENALITY = -300,
                 MOVE_PENALITY = -1):
        super(envCube,self).__init__()
        
        self.SIZE=SIZE
        #self.OBSERVATION_SPACE_VALUES=(SIZE,SIZE,3)
        self.OBSERVATION_SPACE_VALUES=(4,)
        #self.ACTION_SPACE_VALUES=ACTION_SPACE_VALUES
        self.RETURN_IMAGE = RETURN_IMAGE  # 考虑返回值是否图像
        self.MAX_STEP=MAX_STEP
    
        self.FOOD_REWARD = FOOD_REWARD  # agent获得食物的奖励
        self.ENEMY_PENALITY = ENEMY_PENALITY  # 遇上对手的惩罚
        self.MOVE_PENALITY = MOVE_PENALITY  # 每移动一步的惩罚

        self.action_space = gym.spaces.Discrete(ACTION_SPACE_VALUES)
        self.observation_space = gym.spaces.Box(low=-SIZE+1, high=SIZE-1,
                                            shape=(4,), dtype=int)

    # 环境重置
    def reset(self,seed=None, options=None):
        self.player = Cube(self.SIZE)
        self.food = Cube(self.SIZE)
        self.enemy = Cube(self.SIZE)
        # 如果玩家和食物初始位置相同,重置食物的位置,直到位置不同
        while self.player == self.food:
            self.food = Cube(self.SIZE)
        # 如果敌人和玩家或食物的初始位置相同,重置敌人的位置,直到位置不同
        while self.player == self.enemy or self.food == self.enemy:
            self.enemy = Cube(self.SIZE)
        # 判断观测是图像和数字
        if self.RETURN_IMAGE:
            observation = np.array(self.get_image())
        else:
            observation = (self.player - self.food)+(self.player - self.enemy)
            observation=np.array(observation)

        self.episode_step = 0
        info={}

        return observation,info

    def step(self,action):
        self.episode_step+=1
        self.player.action(action)
        self.food.move()
        self.enemy.move()

        # 分类讨论输出new_obs
        if self.RETURN_IMAGE:
            new_observation = np.array(self.get_image())
        else:
            new_observation = (self.player - self.food)+(self.player - self.enemy)
            new_observation=np.array(new_observation)
            
        #获取reward值
        if self.player == self.food:
            reward=self.FOOD_REWARD
        elif self.player==self.enemy:
            reward=self.ENEMY_PENALITY
        else:
            reward=self.MOVE_PENALITY

        #检测截止情况
        terminated = False
        truncated = False

        # 4. 判断结束条件
        if self.player == self.food or self.player == self.enemy:
            terminated = True
        
        if self.episode_step >= self.MAX_STEP:
            truncated = True

        info={}
        return new_observation,reward,terminated,truncated,info

    def render(self,mode='human'):
        img=self.get_image()
        img = img.resize((800,800))
        cv2.imshow('Predator',np.array(img))
        cv2.waitKey(1)

    def get_image(self):
        # 图像显示
        env = np.zeros(self.OBSERVATION_SPACE_VALUES,dtype= np.uint8)
        env[self.food.x][self.food.y] = self.d[self.FOOD_N]
        env[self.player.x][self.player.y] = self.d[self.PLAYER_N]
        env[self.enemy.x][self.enemy.y] = self.d[self.ENEMY_N]
        img = Image.fromarray(env,'RGB')
        return img

第二步,套用官方提供的代码

接下来,我们套用之前写的A2C模型的训练代码,来自这一讲【A2C 再战登月器降落】

这一讲中,官方提供了示例代码:

https://stable-baselines3.readthedocs.io/en/master/modules/a2c.html

python 复制代码
from stable_baselines3 import A2C
from stable_baselines3.common.env_util import make_vec_env

# Parallel environments
vec_env = make_vec_env("CartPole-v1", n_envs=4)

model = A2C("MlpPolicy", vec_env, verbose=1)
model.learn(total_timesteps=25000)
model.save("a2c_cartpole")

del model # remove to demonstrate saving and loading

model = A2C.load("a2c_cartpole")

obs = vec_env.reset()
while True:
    action, _states = model.predict(obs)
    obs, rewards, dones, info = vec_env.step(action)
    vec_env.render("human")

我们参照着这个代码写出了:

python 复制代码
#A2C版本代码
# Instantiate the agent
model = A2C("MlpPolicy",
            env, 
            verbose=1,
            tensorboard_log='./logs',
            learning_rate=5e-4,
            policy_kwargs={'net_arch':[256, 256]}
           )
# Train the agent and display a progress bar
model.learn(total_timesteps=int(2.5e6), progress_bar=True,tb_log_name='A2C_Net256_2M_50')
# Save the agent
model.save("A2C_Net256_2M_50_lunar")
del model  # delete trained model to demonstrate loading
python 复制代码
model = DQN.load("dqn_Net256_lunar", env=env)
model.set_env(env)
mean_reward, std_reward = evaluate_policy(model, model.get_env(),deterministic=True,render=False, n_eval_episodes=10)

我们不需要改架构,只需要改参数即可。

这次我们打算训练50万次,那么total_timesteps就要设定为5e6,然后我们把训练的日志记录名称改为"S10_A2C_Net256_50W"。

python 复制代码
#A2C版本代码
# Instantiate the agent
model = A2C("MlpPolicy",
            env, 
            verbose=1,
            tensorboard_log='./logs',
            learning_rate=5e-4,
            policy_kwargs={'net_arch':[256, 256]}
           )
# Train the agent and display a progress bar
model.learn(total_timesteps=int(2.5e6), progress_bar=True,tb_log_name='S10_A2C_Net256_50W')

然后保存模型的名称也改一下"A2C_Net256_50_lunar"

python 复制代码
# Save the agent
model.save("S10_A2C_Net256_50W_lunar")
del model  # delete trained model to demonstrate loading

打开tensorboard,可以看到,训练出来的效果还是不错的,奖励基本都收敛到0附近了!

而且步数也稳定在10步左右就能吃到食物。

效果不好,考虑修改模型架构

现在我们想扩大一点棋盘,改为SIZE=20,在20*20的情况下,50万次的训练很明显是无法达到预期效果的,仅有-200。

很多时候,训练步数给到50W也无法达到很好的效果,这种情况下,就需要我们修改模型架构了。

python 复制代码
model = A2C("MlpPolicy",
            env, 
            verbose=1,
            tensorboard_log='./logs',
            learning_rate=5e-4,
            policy_kwargs={'net_arch':[256, 256]}
           )

核心就是这个policy_kwargs。

如何修改呢?我们可以参考:

https://stable-baselines3.readthedocs.io/en/master/guide/custom_policy.html

架构的修改

policy_kwargs核心参数详解

1. features_extractor_classfeatures_extractor_kwargs

用于指定如何从原始观测(Observation)中提取特征。

用途 :如果你的输入是图像,通常用 CnnPolicy;如果是向量(Vector),通常用 MlpPolicy

2. net_arch (最常用的参数)

这是设定神经网络层数和每层神经元数量的核心参数。它决定了 Actor(策略网络)和 Critic(价值网络)的隐藏层结构。

设定规则:
net_arch 接受一个列表(List)。列表中的每一个数字代表一个隐藏层的神经元数量。如果需要将策略网络和价值网络的结构分开定义,可以使用字典(Dict)格式。

两种主要设定格式:

格式 A:统一架构

当 Actor 和 Critic 使用相同的网络结构时使用。

  • 写法

    python 复制代码
    policy_kwargs = dict(net_arch=[128, 128])
  • 含义:创建两个隐藏层,每层都有 64 个神经元。这个结构将同时用于策略(Policy)和价值函数(Value)。

格式 B:分离架构

当需要为 Actor 和 Critic 分别设定不同结构时使用。这是文档中重点展示的高级用法。

  • 写法

    python 复制代码
    policy_kwargs = dict(net_arch=dict(pi=[32, 32], vf=[64, 64]))
  • 含义:策略网络使用两层 64 个神经元的结构,而价值网络使用两层 32 个神经元的结构。

激活函数的修改

在官方的示例中,如果我们想修改激活函数(默认tanh),可以导入th库,然后在这里设定activation_fn=th.nn.ReLU

我们也参考,先共享一层,再分开

python 复制代码
model = A2C("MlpPolicy",
            env, 
            verbose=1,
            tensorboard_log='./logs',
            learning_rate=5e-4,
            policy_kwargs={
                'net_arch': dict(vf=[32, 32], pi=[32, 16]), # 修正了这里
                'activation_fn': th.nn.ReLU
            }
           )

model.policy

在这个架构下,policynet第一层是32,第二层变成了16;而valuenet第一层是32,第二层也是32;对应了 dict(vf=[32, 32], pi=[32, 16])

然后我们开始训练。

训练结束,发现红色线形势一片大好,很快就收敛了,只需要15步就能吃到食物,而且奖励也达到了正数!

这样我们的模型架构修改是成功的!

总结

这一节,综合了前几节的内容。

包括【强化学习实战4------编写符合Gym的环境】以及【强化学习实战2------A2C 再战登月器降落

要学会将BL3接入自定义的环境需要做两件事:

第零,你得对自己的任务熟悉,知晓观测空间、动作空间、奖励函数如何设计,根据需求决定要用的模型,再开始写代码。

第一,明确Gym的环境配置,了解需要自己手写哪些函数?配置哪些参数?

第二,套用训练模板,根据你预先决定使用的模型抄模板就行,官方是提供了这些常用模型的示例代码

第三,当增加训练步数也无法达到预期效果时,就要考虑修改模型架构了。

修改有三个地方,

一个是"是否使用分离的AC模型?"

一个是"是否修改不同层级的神经元数量?"

一个是"是否修改激活函数"

实际上,这样的修改往往还不足够,在下一节,我们会讲如何自定义特征提取器。这一节我们仅仅是触及了net_arch的修改,并没有涉及前面的特征提取器的修改。

我们最终的目的是要能够自己定义Observation,自定义特征提取器,自定义模型架构。从而实现这张图。

都可以做尝试。

本节代码:

下载依赖库

python 复制代码
!pip install opencv-python
!pip install pillow
!pip install gymnasium
!pip install matplotlib
!pip install stable-baselines3[extra]
!pip install tensorboard

导入依赖库

python 复制代码
#将学习环境所需要的依赖库导入
import gymnasium as gym
import numpy as np
from gymnasium import spaces

import cv2
from PIL import Image
import time
import torch as th
import pickle #对象到文件的处理
import matplotlib.pyplot as plt
from matplotlib import style
from stable_baselines3.common.env_checker import check_env

style.use('ggplot')

设置环境参数

python 复制代码
#环境参数设定
#SIZE=10 #3个对象在10*10的范围内
EPISODES=30000 #智能体玩的游戏轮数
SHOW_EVERY=3000 #每3000局展示一次游玩过程

#奖励与惩罚
#FOOD_REWARD=25#吃食物的奖励
#ENEMY_PENALITY=300 #被敌人抓住的惩罚
#MOVE_PENALITY=1 #移动惩罚

#环境计算参数
epsilon=0.6 #在强化学习时抽取随机动作的概率 40%使用最大价值期望动作
EPS_DECAY=0.9998 #每玩一局游戏就让随机动作概率乘以这个数,到最后基本就定性了
DISCOUNT=0.95 #折扣回报 未来奖励的折扣
LEARNING_RATE=0.1 #学习率 步长

#q_table_file = "q_table_save.pkl" 
#q_table = None
q_table = "qtable_1775227149.pickle"
#d = {1:(255,0,0), #蓝色------玩家
#     2:(0,255,0), #绿色------食物
#     3:(0,0,255)} #红色------敌人
#PLAYER_N=1
#FOOD_N=2
#ENEMY_N=3

编写Cube对象类

python 复制代码
#为三个对象创建类
class Cube:
    def __init__(self,size):#初始位置
        self.size=size
        self.x=np.random.randint(0,self.size-1)
        self.y=np.random.randint(0,self.size-1)

    def __str__(self): #打印当前位置
        return f'{self.x},{self.y}'

    def __sub__(self,other):#这个类的另一个实体
        return (self.x-other.x,self.y-other.y)

    def __eq__(self,other):
        return self.x == other.x and self.y == other.y

    def action(self,choise):
        if choise == 0:
            self.move(x=1,y=1)
        elif choise == 1:
            self.move(x=-1,y=1)
        elif choise == 2:
            self.move(x=1,y=-1)
        elif choise == 3:
            self.move(x=-1,y=-1)
        elif choise == 4:
            self.move(x=0,y=1)
        elif choise == 5:
            self.move(x=0,y=-1)
        elif choise == 6:
            self.move(x=1,y=0)
        elif choise == 7:
            self.move(x=-1,y=0)
        elif choise == 8:
            self.move(x=0,y=0)

    def move(self,x=False,y=False):
        if not x:#如果x没有给值
            self.x += np.random.randint(-1,2)
        else:
            self.x += x

        if not y:#如果y没有给值
            self.y += np.random.randint(-1,2)
        else:
            self.y += y

        #考虑边界
        if self.x<0:
            self.x=0
        elif self.x>=self.size:
            self.x=self.size-1
        if self.y<0:
            self.y=0
        elif self.y>=self.size:
            self.y=self.size-1

编写envCube环境类

python 复制代码
class envCube(gym.Env):
    # 设定三个部分的颜色分别是蓝、绿、红
    d = {1: (255, 0, 0),  # blue
        2: (0, 255, 0),  # green
        3: (0, 0, 255)}  # red
    PLAYER_N = 1
    FOOD_N = 2
    ENEMY_N = 3
    
    metadata = {"render_modes": ["human"], "render_fps": 30}
    
    def __init__(self,SIZE=20,
                 ACTION_SPACE_VALUES = 9,
                 RETURN_IMAGE = False,
                 MAX_STEP=200,
                 FOOD_REWARD = 25,
                 ENEMY_PENALITY = -300,
                 MOVE_PENALITY = -1):
        super(envCube,self).__init__()
        
        self.SIZE=SIZE
        #self.OBSERVATION_SPACE_VALUES=(SIZE,SIZE,3)
        self.OBSERVATION_SPACE_VALUES=(4,)
        #self.ACTION_SPACE_VALUES=ACTION_SPACE_VALUES
        self.RETURN_IMAGE = RETURN_IMAGE  # 考虑返回值是否图像
        self.MAX_STEP=MAX_STEP
    
        self.FOOD_REWARD = FOOD_REWARD  # agent获得食物的奖励
        self.ENEMY_PENALITY = ENEMY_PENALITY  # 遇上对手的惩罚
        self.MOVE_PENALITY = MOVE_PENALITY  # 每移动一步的惩罚

        self.action_space = gym.spaces.Discrete(ACTION_SPACE_VALUES)
        self.observation_space = gym.spaces.Box(low=-SIZE+1, high=SIZE-1,
                                            shape=(4,), dtype=int)

    # 环境重置
    def reset(self,seed=None, options=None):
        self.player = Cube(self.SIZE)
        self.food = Cube(self.SIZE)
        self.enemy = Cube(self.SIZE)
        # 如果玩家和食物初始位置相同,重置食物的位置,直到位置不同
        while self.player == self.food:
            self.food = Cube(self.SIZE)
        # 如果敌人和玩家或食物的初始位置相同,重置敌人的位置,直到位置不同
        while self.player == self.enemy or self.food == self.enemy:
            self.enemy = Cube(self.SIZE)
        # 判断观测是图像和数字
        if self.RETURN_IMAGE:
            observation = np.array(self.get_image())
        else:
            observation = (self.player - self.food)+(self.player - self.enemy)
            observation=np.array(observation)

        self.episode_step = 0
        info={}

        return observation,info

    def step(self,action):
        self.episode_step+=1
        self.player.action(action)
        self.food.move()
        self.enemy.move()

        # 分类讨论输出new_obs
        if self.RETURN_IMAGE:
            new_observation = np.array(self.get_image())
        else:
            new_observation = (self.player - self.food)+(self.player - self.enemy)
            new_observation=np.array(new_observation)
            
        #获取reward值
        if self.player == self.food:
            reward=self.FOOD_REWARD
        elif self.player==self.enemy:
            reward=self.ENEMY_PENALITY
        else:
            reward=self.MOVE_PENALITY

        #检测截止情况
        terminated = False
        truncated = False

        # 4. 判断结束条件
        if self.player == self.food or self.player == self.enemy:
            terminated = True
        
        if self.episode_step >= self.MAX_STEP:
            truncated = True

        info={}
        return new_observation,reward,terminated,truncated,info

    def render(self,mode='human'):
        img=self.get_image()
        img = img.resize((200,200))
        cv2.imshow('Predator',np.array(img))
        if self.player == self.food or self.player == self.enemy or self.episode_step >= self.MAX_STEP:
            cv2.waitKey(1500)
        else:
            cv2.waitKey(1)

    def get_image(self):
        # 图像显示
        env = np.zeros(self.OBSERVATION_SPACE_VALUES,dtype= np.uint8)
        env[self.food.x][self.food.y] = self.d[self.FOOD_N]
        env[self.player.x][self.player.y] = self.d[self.PLAYER_N]
        env[self.enemy.x][self.enemy.y] = self.d[self.ENEMY_N]
        img = Image.fromarray(env,'RGB')
        return img

创建环境对象

python 复制代码
env=envCube()

检测环境是否符合Gym标准

python 复制代码
check_env(env)

导入主函数依赖库

python 复制代码
import gymnasium as gym

from stable_baselines3 import DQN,A2C
from stable_baselines3.common.evaluation import evaluate_policy
import os
import stable_baselines3 as sb3
print(sb3.__version__)
os.environ['KMP_DUPLICATE_LIB_OK']='True'

构建模型

python 复制代码
model = A2C("MlpPolicy",
            env, 
            verbose=1,
            tensorboard_log='./logs',
            learning_rate=5e-4,
            policy_kwargs={
                'net_arch': dict(vf=[32, 32], pi=[32, 16]), # 修正了这里
                'activation_fn': th.nn.ReLU
            }
           )

model.policy

训练模型

python 复制代码
# Train the agent and display a progress bar
model.learn(total_timesteps=int(500000), progress_bar=True,tb_log_name='S20_A2C_Net32X32X16_50W')

保存模型

python 复制代码
# Save the agent
model.save("S20_A2C_Net32X32X16_50W_lunar")
del model  # delete trained model to demonstrate loading

加载与评估模型

python 复制代码
model = DQN.load("S20_A2C_Net32X32X16_50W_lunar", env=env)
model.set_env(env)
mean_reward, std_reward = evaluate_policy(model, model.get_env(),deterministic=True,render=False, n_eval_episodes=10)
相关推荐
ZhiqianXia2 小时前
PyTorch 笔记学习(15) : aot_autograd.py 解析
pytorch·笔记·学习
阿捞22 小时前
JVM排查工具单
java·jvm·python
weixin_423533992 小时前
【ubuntu20.04安装nvidia显卡驱动及pytorch】
python
I疯子2 小时前
2026-04-08 打卡第 5 天
开发语言·windows·python
ZhiqianXia3 小时前
PyTorch 学习笔记(14):PyTorch/LLVM 编译栈
pytorch·笔记·学习
C+++Python3 小时前
Python MCP Server 最简实现
开发语言·python
zhuhezhang3 小时前
一个用python开发的文本对比工具
python·文本对比工具
智算菩萨3 小时前
【Python图像处理】5 Pillow图像处理与格式转换
图像处理·python·pillow
人工干智能3 小时前
科普:%%matplotlib inline:魔法命令 (Cell Magic)
python·matplotlib