深度强化学习PG解决装箱问题

做了一个尝试,用深度强化学习policy gradient解决装箱问题。 暂时没有用Q learning。可以考虑试试AC、PPG。也可以试试VRP问题。

当然也不深,特征才用了四个,最简单的dnn,把架子先搭起来。时间的关系,还有很多待优化的,只是一个思想参考。搜了一下 强化学习解决VRP或装箱问题的代码文章不太多,嘿嘿。而且搜到的一些 运用强化学习的思想 是用来优化各种算子的,还是要配合启发式算法用。 我这个是整个流程直接使用强化学习的。好吧,悄悄给自己点个小赞。

action只有两个,拿或者不拿。 状态当前用了四个 装箱前后分别的体积重量占比。是的,状态与货物有关。训练时每次step的时候,会产生(随机选取)新的货物,也会新产生 对应货物的state。   
step的时候, 不拿:  计算不拿的奖励,旧货物还原 生成新货物和状态; 拿:  那就计算拿的奖励  episode还未done则 继续生成新货物和状态。
状态与货物有关, 状态还与动作有关。首先随机选货物(后续可以优化成概率依据体积)。动作 原本应该是根据神经网络前向传播的结果来的。 在最初训练的时候,第一个货物 如果不拿,则状态的4个属性值全为0,扔到网络里会玩不起来,所以训练时第一个货物的动作固定为拿。  而在最后的前向流程时,第一个则不合适固定拿,因为此时的货物 体积可能很小。直接从网络里前向计算得到action?计算action需要状态.. 而状态会根据action不同而不同...这就变成了先有鸡还是先有蛋的问题了....(顺便说,在古生物学家眼中 先有蛋。蛋是一种羊膜卵,最早的羊膜卵是3亿年前的林晰产下的。羊膜动物代表林晰是两栖动物中的进化者,其他古老的两栖动物繁殖仍然离不开水,林晰产下了不需要在水中孵化的羊膜卵。而最早的鸡形动物1亿年后才在地球上出现。)  怎么办? 再单独搞个神经网络 训练下初始状态时 拿什么样的货物最好? 暂时不用吧,我使用了当前货物体积 与此批货物体积均值(为避免异常值影响实际用的中位数)的比值, 如果大于均值,则使用3:1的概率选中它。 3:1数字可配。     

现有的代码没有考虑物体长宽高的影响(可能容积满足带长度并不能装下),如果要做,可以考虑把trailer中所有物品的长宽高属性、加和的结果 与拖车长宽高的比值 之类的数据扔到网络中,也就是特征多加几个, 然后 判断计算体积超标或重量超标的负反馈时, 增加对长宽高超限的负反馈。

为什么要有最后的前向流程?  训练时,episode快结束时 拿货物可能已经拿了 但已经超体积超重了。 所以前面只能是训练。最后还需要来个训练集上的测试流程。 如果用同一个训练好的网络 处理其他批次的货物,相当于是validation流程了。 

一个episode done是因为一个拖车装满了(体积占比0.95以 上)。但是本批次 还有剩余货物的话,env_done(自创的) 不会为True。一批次的货物来了,当成是一个env。 当然,如果按仿真流水线的方法,会有不同的批次陆续到达。 也可以再做另外的批次合并处理。
前向时,经常有很多次action都是不拿,不拿次数太多导致流程很长,总是得不到装满。 有两部分原因,1 是网络没训练好, 2是标签没给好,也就是训练时的奖励设置不够好。

奖励的设置 很重要,作用相当于监督学习的标签了。如果超重或超体积,当然负反馈最大。如果体积占比已经很大了但仍然取货物成功,奖励较大。如果刚开始货物不多 却拿了小体积的东西,奖励较小。 增量阈值0.1 0.3 0.5这些 也要很小心的设置。这里未来都应该做成配置项。

def action_1_reward(self, cur_vol_ratio, cur_weight_ratio, max_vol, before_vol):
    if cur_vol_ratio > 1 or cur_weight_ratio > 1:
        return -10

    before_vol_ratio = before_vol * 1.0 / max_vol

    if before_vol_ratio < 0.5 and (cur_vol_ratio - before_vol_ratio) < 0.1:
        return 1
    if before_vol_ratio < 0.5 and (cur_vol_ratio - before_vol_ratio) < 0.3:
        return 2
    if before_vol_ratio < 0.5 and (cur_vol_ratio - before_vol_ratio) < 0.5:
        return 3

    if before_vol_ratio > 0.9:
        return 5
    if before_vol_ratio > 0.8:
        return 3

    return 1

def action_0_reward(self):
    return 0

tensorflow版本 用的1.14     如果用tensorflow2.x版本跑代码要少量修改一下

分文件写的,这里是一些主要逻辑参考:

关键文件:  网络相关的  pg.py        binning环境相关的  binning.py

生成货物:gen_trailer_cargo.py

from collections import namedtuple
import random
import pandas as pd


cargo_weight_range = tuple(range(20, 501, 10))
depth_range = tuple(range(10, 151, 10))
width_range = tuple(range(10, 151, 10))
height_range = tuple(range(20, 81, 10))
# vol_unit = "cm"
trailer_load_bearing = (20000, 40000, 60000)
trailer_vol = (0.001, 0.003, 0.006)
# trailer_vol = (0.05, 0.08, 0.12)


Cargo = namedtuple("Cargo", ("volume", "weight"))


def gen_cargo_df(quantity=50):
    weights = random.choices(cargo_weight_range, k=quantity)
    depths = random.choices(depth_range, k=quantity)
    widths = random.choices(width_range, k=quantity)
    heights = random.choices(height_range, k=quantity)
    # cm -> cube cm  * 1e-9
    vols = [d * w * h * 1e-9 for d, w, h in zip(depths, widths, heights)]

    df = pd.DataFrame({"id": list(range(1, quantity + 1)),
                       "weight": weights,
                       "volume": vols,
                       "depths": depths,
                       "widths": widths,
                       "heights": heights},
                      index=list(range(1, quantity + 1)))

    return df.to_dict(orient="index")


def gen_trailer_df():
    # trailer 没有数量限制
    df = pd.DataFrame({"id": list(range(1, len(trailer_vol) + 1)),
                       "load_bearing": trailer_load_bearing,
                       "trailer_vol": trailer_vol},
                      index=list(range(1, len(trailer_vol) + 1)))
    return df.to_dict(orient="index")

网络相关的  pg.py

import random
import tensorflow as tf
# from keras.models import Sequential
# from keras.layers import Dense
from keras.losses import sparse_categorical_crossentropy
import numpy as np
from service.sol.reinforce.env.binnging import BinningEnv


max_epoch = 60


class PolicyGradient:
    def __init__(self, n_features, n_actions, learning_rate=0.01, reward_decay=0.95, action_0_max_times=2000):
        self.n_actions = n_actions
        self.n_features = n_features
        self.lr = learning_rate
        self.gamma = reward_decay
        self.action_0_max_times = action_0_max_times
        self.ep_obs, self.ep_as, self.ep_rs = [], [], []
        self.clear_action_0_times()
        self.make_network()


    def make_network(self):
        with tf.name_scope("inputs"):
            self.input_ph = tf.placeholder(tf.float32, [None, self.n_features], name="input_")
            self.actions_ph = tf.placeholder(tf.int32, [None, self.n_actions], name="actions")
          
【资源说明】 1、该资源包括项目的全部源码,下载可以直接使用! 2、本项目适合作为计算机、数学、电子信息等专业的课程设计、期末大作业和毕设项目,作为参考资料学习借鉴。 3、本资源作为“参考资料”如果需要实现其他功能,需要能看懂代码,并且热爱钻研,自行调试。 DQN深度强化学习解决三维在线装箱问题python源码+项目说明.zip ## 问题描述 物流公司在流通过程中,需要将打包完毕的箱子装入到一个货车的车厢中,为了提高物流效率,需要将车厢尽量填满,显然,车厢如果能被100%填满是最优的,但通常认为,车厢能够填满85%,可认为装箱是比较优化的。 设车厢为长方形,其长宽高分别为L,W,H;共有n个箱子,箱子也为长方形,第i个箱子的长宽高为li,wi,hi(n个箱子的体积总和是要远远大于车厢的体积),做以下假设和要求: 1. 长方形的车厢共有8个角,并设靠近驾驶室并位于下端的一个角的坐标为(0,0,0),车厢共6个面,其中长的4个面,以及靠近驾驶室的面是封闭的,只有一个面是开着的,用于工人搬运箱子; 2. 需要计算出每个箱子在车厢中的坐标,即每个箱子摆放后,其和车厢坐标为(0,0,0)的角相对应的角在车厢中的坐标,并计算车厢的填充率。 ## 运行环境 主机 |内存 | 显卡 | IDE | Python | torch -----|------|------|-----|--------|----- CPU:12th Gen Intel(R) Core (TM) i7-12700H 2.30 GHz | 6GB RAM | NVIDIA GEFORCE RTX 3050 | Pycharm2022.2.1 | python3.8 | 1.13.0 ## 思路 (1)箱子到来后,根据车厢的实际空间情况,按照策略选择放置点; (2)当摆放箱子时,以6种姿态摆放,并对其进行评估,使用评估值最高的姿态将箱子摆放在选中的角点上; (3)重复以上步骤,直到摆放完毕。 ## 建立模型 在车厢内部设置坐标系,靠近驾驶室并位于下端的一个角的坐标为(0,0,0),相交于原点的车厢长边、宽边和高边分别为x轴,y轴和z轴方向,L、W、H分别为车厢的长、宽、高。箱子具有六种摆放姿态,分别以箱子的长宽、长高、宽高平面为底,旋转90°可以得到另外三种摆放姿态。 ## 核心 ### 箱子放置策略 本算法将角点作为车厢内部空间中箱子的摆放位置,每次放入新箱子后搜索新生成的角点,当向车厢中放入第一个箱子时,假设车厢中只有原点一个角点,当一个箱子放入后,会产生新的角点,再放置箱子后,又会产生新的角点。 建立箱子可放置点列表,表示箱子i到来时,车厢内部所有可选的摆放位置,在放置新箱子后更新可放置点列表,并记录已放置箱子到车厢顶部距离,用于后续的奖励函数。 ### DQN (1)设置一些超参数,包括ε-greedy使用的ε,折扣因子γ,目标网络更新频率,经验池容量等。 (2)由于给定的箱子数据较少,为了增加模型训练数据数量,将给定的箱子数据打乱,以随机的形式生成并保存,作为训练数据,训练网络模型。 (3)奖励函数 使用x-y平面中两个最大剩余矩形面积(如下图)之和与箱子到车厢顶部的距离作为奖励值R,奖励函数表示如下: (4)动作-价值函数网络和目标动作-价值函数网络设置为包含6层卷积层的CNN。对当前状态和动作建模,使其能够输入到价值网络Q和Q’中。以车厢的底面为基准,建模L*W的矩阵,每个元素代表该点放置的箱子最大高度。 (5)动作选择 根据当前的状态(当前车厢的属性,包括尺寸、放置的所有箱子、H矩阵、可放置点列表等),使用ε-greedy方法选择具有最大Q值的动作或随机选择动作(动作是箱子的放置点和摆放姿态)。 (6)经验重放 ## 说明 将所有文件夹放置在同一目录下,train.py用于模型训练,cnn.pth是已经训练好的模型,在eval.py中导入后直接运行eval.py即可。 ## 不足 1、填充率 一般认为车厢填充率高于85%,认为装箱算法是较优的,本实验设计的装箱方案填充率较低,在60%-80%间,分析原因可能在于强化学习网络的参数不够合适,算法有待优化。 改进的方向:调整强化学习网络的参数,选择更加合适的参数。
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值