You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Stable-Baselines3的RL求解2D装箱问题训练失效求助

基于Stable-Baselines3的2D装箱RL模型训练异常排查

问题概述

用Stable-Baselines3框架开发强化学习2D装箱求解项目,训练过程中模型性能毫无提升,输出的布局频繁出现箱子重叠或无效放置情况。已经尝试调整奖励函数、扩大网络规模,问题依然存在。

核心训练代码

# 实际核心训练代码
from stable_baselines3 import PPO
from custom_env import BinPacking2DEnv

# 初始化环境
env = BinPacking2DEnv(bin_width=10, bin_height=10)

# 定义PPO模型
model = PPO(
    "MlpPolicy",
    env,
    verbose=1,
    tensorboard_log="./bin_packing_tensorboard/",
    policy_kwargs={"net_arch": [256, 256]}  # 已尝试调整网络层数/神经元数
)

# 启动训练
model.learn(total_timesteps=1000000)
model.save("bin_packing_ppo")

自定义环境关键函数代码

import gym
from gym import spaces
import numpy as np

class BinPacking2DEnv(gym.Env):
    metadata = {"render.modes": ["human"]}

    def __init__(self, bin_width=10, bin_height=10):
        super().__init__()
        self.bin_width = bin_width
        self.bin_height = bin_height
        # 动作空间:示例为[放置位置x, 放置位置y, 是否旋转]的离散编码
        self.action_space = spaces.Discrete(10*10*2)
        # 状态空间:示例为已放置箱子的位置+剩余箱子尺寸+当前利用率
        self.observation_space = spaces.Box(
            low=0, high=np.max([bin_width, bin_height]),
            shape=(10*4 + 2 + 1,), dtype=np.float32
        )
        self.placed_boxes = []
        self.remaining_boxes = self._generate_boxes()

    def step(self, action):
        reward = 0
        done = False
        info = {}

        # 解析动作,执行放置逻辑
        x, y, rotate = self._decode_action(action)
        current_box = self.remaining_boxes[0]
        box_w, box_h = (current_box[1], current_box[0]) if rotate else current_box

        # 检查放置是否有效(不超出边界、不重叠)
        if x + box_w > self.bin_width or y + box_h > self.bin_height:
            reward = -5
        elif self._check_overlap(x, y, box_w, box_h):
            reward = -10
        else:
            self.placed_boxes.append((x, y, box_w, box_h))
            self.remaining_boxes.pop(0)
            # 计算利用率奖励
            utilization = self._calculate_utilization()
            reward = utilization * 20

        # 判断是否完成所有箱子放置
        if len(self.remaining_boxes) == 0:
            done = True
            reward += 100  # 完成额外奖励

        return self._get_observation(), reward, done, info

    def _get_observation(self):
        # 构造观测向量:已放置箱子的坐标尺寸 + 剩余第一个箱子尺寸 + 当前利用率
        placed_vec = np.array([item for box in self.placed_boxes for item in box]).flatten()
        # 补全固定长度(最多10个箱子)
        placed_vec = np.pad(placed_vec, (0, 40 - len(placed_vec)), mode='constant')
        remaining_vec = self.remaining_boxes[0] if self.remaining_boxes else [0,0]
        utilization = np.array([self._calculate_utilization()])
        return np.concatenate([placed_vec, remaining_vec, utilization])

    def _check_overlap(self, x, y, w, h):
        for (px, py, pw, ph) in self.placed_boxes:
            if not (x + w <= px or x >= px + pw or y + h <= py or y >= py + ph):
                return True
        return False

    def _calculate_utilization(self):
        total_area = sum(w*h for (x,y,w,h) in self.placed_boxes)
        return total_area / (self.bin_width * self.bin_height)

    def _generate_boxes(self):
        # 生成随机箱子列表
        return [(np.random.randint(1,5), np.random.randint(1,5)) for _ in range(10)]

    def reset(self):
        self.placed_boxes = []
        self.remaining_boxes = self._generate_boxes()
        return self._get_observation()

TensorBoard日志截图

TensorBoard奖励曲线
截图说明:奖励值长期在-10到20之间波动,无明显上升趋势,平均奖励维持在0左右

排查方向建议

1. 动作与状态空间设计

  • 动作空间是否存在局限性:比如当前动作编码是否覆盖了所有合理放置位置?是否遗漏了箱子旋转的灵活度?若动作离散度过高,模型难以探索到有效放置方式。
  • 状态空间是否缺失关键信息:观测是否包含了剩余空间的分布?仅靠已放置箱子坐标和利用率,模型无法感知哪些区域还能放置箱子,建议加入可用空间的特征(比如最大空白矩形的尺寸、位置)。

2. 奖励函数优化

  • 惩罚机制是否精准:当前对边界溢出和重叠的惩罚是否有区分?是否应该对完全无效的动作(比如重复放置同一位置)设置更严厉的惩罚?
  • 奖励稀疏性问题:仅在完成所有放置时给大额奖励,模型前期难以获得有效反馈。建议增加每步正向奖励:比如成功放置一个箱子就给予与该箱子面积挂钩的奖励,同时叠加利用率奖励,引导模型逐步优化。
  • 奖励冲突检查:是否存在为了短期利用率而牺牲后续放置空间的情况?可以加入"未来可用空间"的奖励项,鼓励模型预留合适空间给后续大箱子。

3. 环境逻辑验证

  • 重叠检测函数_check_overlap()是否正确:比如边界判断是否存在误差(比如是否应该用<=还是<),建议手动模拟几个放置场景,验证检测结果是否符合预期。
  • 观测向量是否准确:_get_observation()返回的向量是否完整反映了当前环境状态?比如剩余箱子的信息是否只取了第一个,是否需要加入所有剩余箱子的尺寸统计(如最大/最小尺寸)?

4. 算法与参数调整

  • 尝试更换算法:PPO适合连续/离散空间,但2D装箱属于组合优化问题,可尝试DQN(若动作空间规模适中)或DQN的变种(如Dueling DQN),对比训练效果。
  • 调整PPO核心参数:比如调小learning_rate(从3e-4降到1e-4),增大gamma(从0.99到0.995)强化长期奖励权重,调整clip_range平衡探索与利用。
  • 加入环境向量归一化:用VecNormalize对观测进行归一化处理,避免不同维度数值范围差异过大导致模型学习困难。

5. 数据与训练策略

  • 增加训练步数:当前1e6步可能不足以让模型学到有效策略,可尝试提升到3e6或5e6步,同时观察TensorBoard中奖励曲线的变化。
  • 加入演示数据:若有已知的合理布局,可采用行为克隆预训练模型,再进行强化学习微调,帮助模型快速找到有效动作空间。

内容的提问来源于stack exchange,提问作者Philipp Gradl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 09:15:32