20250306-笔记-精读class CVRPEnv:step(self, selected)

文章目录

  • 前言
  • 一、`if self.time_step<4:`
    • 控制时间步的递增
    • 判断是否在配送中心
    • 特定时间步的操作
    • 更新
      • 更新当前节点和已选择节点列表
      • 更新需求和负载
      • 更新访问标记
      • 更新负无穷掩码
      • 更新步骤状态,将更新后的状态同步到 self.step_state
  • 二、使用步骤
  • 总结


前言

class CVRPEnv:step(self, selected)函数是强化学习代码实现中的核心。
精读该代码的目标:

  1. 熟悉每一个参数的shape。
  2. 熟悉每个参数之间的关系(剪切,扩展,等)。

一、if self.time_step<4:

控制时间步的递增

            # 控制时间步的递增self.time_step=self.time_step+1self.selectex_count = self.selected_count+1

判断是否在配送中心

            #判断是否在配送中心self.at_the_depot = (selected == 0)

特定时间步的操作

            if self.time_step==3:self.last_current_node = self.current_node.clone()self.last_load = self.load.clone()if self.time_step == 4:self.last_current_node = self.current_node.clone()self.last_load = self.load.clone()self.visited_ninf_flag[:, :, self.problem_size+1][(~self.at_the_depot)&(self.last_current_node!=0)] = 0

更新

更新当前节点和已选择节点列表

            #更新当前节点和已选择节点列表self.current_node = selectedself.selected_node_list = torch.cat((self.selected_node_list, self.current_node[:, :, None]), dim=2)
参数Shape
self.current_node(batch, pomo)
self.selected_node_list(batch, pomo,0~)

注:0~表示第三维度逐渐增加

self.selected_node_list的shape:
在这里插入图片描述
self.current_node的shape:
在这里插入图片描述
self.selected_node_list = torch.cat((self.selected_node_list, self.current_node[:, :, None]), dim=2),表示先将self.current_node扩展为三维数据,再将self.current_node沿着self.selected_node_list 的第三维度(dim=2)进行依次剪切进去。

更新需求和负载

            #更新需求和负载demand_list = self.depot_node_demand[:, None, :].expand(self.batch_size, self.pomo_size, -1)gathering_index = selected[:, :, None]selected_demand = demand_list.gather(dim=2, index=gathering_index).squeeze(dim=2)self.load -= selected_demandself.load[self.at_the_depot] = 1  # refill loaded at the depot
参数Shape含义g
self.depot_node_demand(batch, problem + 1)表示每个批次中,每个问题(包括配送中心)对应的节点需求
demand_list(batch, pomo, problem + 1)包含每个节点需求的张量
selected(batch, pomo)表示每个批次中的每个智能体所选择的节点编号(这些节点是从节点集合中选择的)
selected_demand(batch, pomo)示每个智能体所选择节点的需求。

demand_list = self.depot_node_demand[:, None, :].expand(self.batch_size, self.pomo_size, -1)

  • [:, None, :]:先在self.depot_node_demand的第二维(即问题维度)上增加一个新的维度,使其变为 (batch_size, 1, problem_size + 1)
  • .expand(self.batch_size, self.pomo_size, -1):将数据self.depot_node_demand扩展为 (batch_size, pomo_size, problem_size + 1),表示每个批次中的每个 POMO 智能体都有一份相同的需求数据。

在这里插入图片描述
gathering_index = selected[:, :, None]

  • selected 进行维度扩展
    在这里插入图片描述

selected_demand = demand_list.gather(dim=2, index=gathering_index).squeeze(dim=2)

  • demand_list 的 shape 是 (batch_size, pomo_size, problem_size + 1),包含了所有节点的需求数据。
  • gather(dim=2, index=gathering_index) 会按照 gathering_index(即 selected 中存储的节点编号)从 demand_list 中选择出对应的节点需求。dim=2 表示沿着第三维(即问题维度)进行选择。
  • gather 的结果是一个 shape 为 (batch_size, pomo_size, 1) 的张量。
  • .squeeze(dim=2) 去掉了多余的第三维,最终得到 selected_demand,其 shape 是 (batch_size, pomo_size),表示每个智能体所选择节点的需求。

在这里插入图片描述

更新访问标记

            #更新访问标记(防止重复选择已访问的节点)self.visited_ninf_flag[self.BATCH_IDX, self.POMO_IDX, selected] = float('-inf')self.visited_ninf_flag[:, :, 0][~self.at_the_depot] = 0  # depot is considered unvisited, unless you are AT the depot
参数Shape含义
self.visited_ninf_flag(batch, pomo, problem+ 1)记录了每 个智能体(POMO)在每个批次中已访问的节点的信息,标记某些节点是否已经被访问(用负无穷表示)。
self.BATCH_IDX(batch, pomo)批次索引的张量
self.POMO_IDX(batch, pomo)智能体(POMO)索引的张量
selected(batch, pomo)表示每个批次中的每个智能体所选择的节点编号(这些节点是从节点集合中选择的)
self.at_the_depot(batch, pomo)一个布尔型张量,表示每个智能体是否处于配送中心(即该智能体是否在节点 0,通常是配送中心)。

self.visited_ninf_flag[self.BATCH_IDX, self.POMO_IDX, selected] 表示从 visited_ninf_flag 张量中选择出对应批次和智能体的对应位置,并设置为 float('-inf'),表示这些节点已经被访问过。

举例:
假设我们有以下参数:

  • batch_size = 2,即有 2 个批次。
  • pomo_size = 3,即每个批次有 3 个智能体(POMO)。
  • problem_size = 4,即有 4 个节点(包含配送中心)。
self.visited_ninf_flag = [[[  0.,   0.,   0.,   0.,   0.],  # 第一个批次(batch 0)[  0.,   0.,   0.,   0.,   0.],  # POMO 0, POMO 1, POMO 2 各自对节点的访问标志[  0.,   0.,   0.,   0.,   0.]],[[  0.,   0.,   0.,   0.,   0.],  # 第二个批次(batch 1)[  0.,   0.,   0.,   0.,   0.],[  0.,   0.,   0.,   0.,   0.]]
]

self.BATCH_IDX(批次索引):

self.BATCH_IDX = [[0, 0, 0],  # 第一个批次[1, 1, 1]   # 第二个批次
]

self.POMO_IDX(POMO 索引):

self.POMO_IDX = [[0, 1, 2],  # 每个批次中三个智能体的索引[0, 1, 2]
]

selected(每个智能体选择的节点):

selected = [[1, 2, 0],  # 第一个批次中,智能体选择的节点:POMO 0 选择节点 1,POMO 1 选择节点 2,POMO 2 选择节点 0[3, 1, 2]   # 第二个批次中,智能体选择的节点:POMO 0 选择节点 3,POMO 1 选择节点 1,POMO 2 选择节点 2
]

执行这一行代码 self.visited_ninf_flag[self.BATCH_IDX, self.POMO_IDX, selected] = float('-inf')
对于第一个批次(BATCH_IDX[0]),我们有三个智能体(POMO_IDX[0]),选择了节点 [1, 2, 0],分别是:

  • selected[0][0] = 1 表示 POMO 0 选择了节点 1。
  • selected[0][1] = 2 表示 POMO 1 选择了节点 2。
  • selected[0][2] = 0 表示 POMO 2 选择了节点 0。
    对于第二个批次(BATCH_IDX[1]),我们同样有三个智能体(POMO_IDX[1]),选择了节点 [3, 1, 2],分别是:
  • selected[1][0] = 3 表示 POMO 0 选择了节点 3。
  • selected[1][1] = 1 表示 POMO 1 选择了节点 1。
  • selected[1][2] = 2 表示 POMO 2 选择了节点 2。

更新 visited_ninf_flag: 根据批次索引和 POMO 索引,我们更新了对应位置的值为负无穷 -inf:

  • 对于 BATCH_IDX[0] 和 POMO_IDX[0, 1, 2],我们将 selected[0][0] = 1,selected[0][1] = 2,selected[0][2] = 0 位置标记为 -inf。
  • 对于 BATCH_IDX[1] 和 POMO_IDX[0, 1, 2],我们将 selected[1][0] = 3,selected[1][1] = 1,selected[1][2] = 2 位置标记为 -inf。

self.visited_ninf_flag[:, :, 0][~self.at_the_depot] = 0,我们将所有不在配送中心的智能体的配送中心访问标志设置为 0。
-[:, :, 0] 是一个切片操作,表示我们提取张量中的第一个节点(通常是配送中心节点)。

  • ~self.at_the_depot 是对 self.at_the_depot 张量的布尔取反操作,将 True 变为 False,将 False 变为 True。

更新负无穷掩码

            #更新负无穷掩码(屏蔽需求量超过当前负载的节点)self.ninf_mask = self.visited_ninf_flag.clone()round_error_epsilon = 0.00001demand_too_large = self.load[:, :, None] + round_error_epsilon < demand_list_2=torch.full((demand_too_large.shape[0],demand_too_large.shape[1],1),False)demand_too_large = torch.cat((demand_too_large, _2), dim=2)self.ninf_mask[demand_too_large] = float('-inf')
参数Shape含义
self.visited_ninf_flag(batch, pomo, problem+ 1)记录了每 个智能体(POMO)在每个批次中已访问的节点的信息,标记某些节点是否已经被访问(用负无穷表示)。
self.ninf_mask(batch, pomo, problem+ 1)self.visited_ninf_flag.clone()

更新步骤状态,将更新后的状态同步到 self.step_state

            #更新步骤状态,将更新后的状态同步到 self.step_stateself.step_state.selected_count = self.time_stepself.step_state.load = self.loadself.step_state.current_node = self.current_nodeself.step_state.ninf_mask = self.ninf_mask
参数Shape

二、使用步骤


总结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/29445.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

nginx服务器实现上传文件功能_使用nginx-upload-module模块

目录 conf文件内容如下html文件内容如下上传文件功能展示 conf文件内容如下 #user nobody; worker_processes 1;error_log /usr/logs/error.log; #error_log /usr/logs/error.log notice; #error_log /usr/logs/error.log info;#pid /usr/logs/nginx.pid;even…

mapbox进阶,模仿百度,简单实现室内楼层切换

👨‍⚕️ 主页: gis分享者 👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.2 ☘️mapboxgl.Map style属性1.3 ☘️fill-extrusion三维填充图层样式1.4 ☘…

String / StringBuffer / StringBuilder 的区别是什么?

String、StringBuffer 和 StringBuilder 都是 Java 中用于处理字符串的类&#xff0c;但它们在多个方面存在区别&#xff0c;以下是详细介绍&#xff1a; 1. 可变性 4. 使用场景 String&#xff1a;String 类是不可变的&#xff0c;一旦创建了一个 String 对象&#xff0c;它的…

为何吹订单?因为特斯拉的销量已遥遥领先,掩耳盗铃之举!

从去年以来&#xff0c;多家新造车企业都经常拿大定、小定的数据来说事&#xff0c;而不是如之前说销量领先&#xff0c;原因就在于他们曾对标的特斯拉在销量方面已远远超越&#xff0c;在销量方面无法与特斯拉比拼&#xff0c;就只好用订单 国内媒体一片宣传特斯拉在中国的销量…

深入掌握Redis:从原理到实践的全方位指南

文章为原创&#xff0c;转载请注明出处——Gavana - 半分之月&#x1f319;。 文章在我的博客中同步更新&#xff0c;也可访问本文链接——深入掌握Redis&#xff1a;从原理到实践的全方位指南 | Gavana 关注AI开发工程师Gavana&#xff0c;带你了解更多实用有趣的AI宝藏✨ 个人…

结构型模式---享元模式

概念 享元模式是一种结构型设计模式&#xff0c;他摒弃了在每个对象中保存所有数据的方式&#xff0c;通过共享多个对象所共有的相同状态&#xff0c;让你能在有限的内存容量中载入更多对象。享元模式将原始类中的数据分为内在状态数据和外在状态数据。 内在状态&#xff1a;就…

【Altium】22.11版本后如何导出Gerber镜像层

1、 文档目标 解决 22.11 版本后如何导出 Gerber 镜像层的问题 2、 问题场景 Gerber 导出旧版本&#xff0c;在 AD 22.11 之前的 Gerber 导出中是存在镜像层的选择。 图 1 软件更新至 AD22.11 及之后版本&#xff0c;在 Gerber 导出设置中无法选择层镜像进行导出。 图 2 3、…

Ubuntu 合上屏幕 不待机 设置

有时候需要Ubuntu的机器合上屏幕的时候也能正常工作&#xff0c;而不是处于待机状态。 需要进行配置文件的设置&#xff0c;并重启即可。 1. 修改配置文件 /etc/systemd/logind.conf sudo vi /etc/systemd/logind.conf 然后输入i&#xff0c;进入插入状态&#xff0c;修改如…

Dockerfile 深入浅出:从基础到进阶全解析

Dockerfile 深入浅出&#xff1a;从基础到进阶全解析 各位同学&#xff0c;大家好&#xff01;欢迎来到今天的 Dockerfile 课程。Docker 技术在当今的软件开发和部署领域可以说是非常热门&#xff0c;而 Dockerfile 作为构建 Docker 镜像的关键文件&#xff0c;掌握它对于我们…

视频录像机视频通道是指什么

视频录像机的视频通道是指摄像机在监控矩阵或硬盘录像机设备上的视频输入的物理位置。 与摄像头数量关系&#xff1a;在视频监控系统中&#xff0c;有多少个摄像头就需要多少路视频通道&#xff0c;通道数量决定了视频录像机可接入摄像头的数量&#xff0c;一般硬盘录像机有4路…

2025-03-06 学习记录--C/C++-PTA 习题6-6 使用函数输出一个整数的逆序数

合抱之木&#xff0c;生于毫末&#xff1b;九层之台&#xff0c;起于累土&#xff1b;千里之行&#xff0c;始于足下。&#x1f4aa;&#x1f3fb; 一、题目描述 ⭐️ 二、代码&#xff08;C语言&#xff09;⭐️ #include <stdio.h>int reverse( int number );int main…

游戏引擎学习第138天

仓库:https://gitee.com/mrxiao_com/2d_game_3 资产&#xff1a;game_hero_test_assets_003.zip 发布 我们的目标是展示游戏运行时的完整过程&#xff0c;从像素渲染到不使用GPU的方式&#xff0c;我们自己编写了渲染器并完成了所有的工作。今天我们开始了一些新的内容&#…

LeetCode hot 100—二叉树的最大深度

题目 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;3示例 2&#xff1a; 输入&#xff1a;root [1,n…

力扣刷题DAY6(滑动窗口/中等+栈/简单、中等)

一、滑动窗口 找到字符串中所有字母异位词 方法一&#xff1a;哈希表 class Solution { public:vector<int> findAnagrams(string s, string p) {vector<int> ans;unordered_map<char, int> target;for (int i 0; i < p.size(); i) {target[p[i]];}in…

DeepSeek V3 源码:从入门到放弃!

从入门到放弃 花了几天时间&#xff0c;看懂了DeepSeek V3 源码的逻辑。源码的逻辑是不难的&#xff0c;但为什么模型结构需要这样设计&#xff0c;为什么参数需要这样设置呢&#xff1f;知其然&#xff0c;但不知其所以然。除了模型结构以外&#xff0c;模型的训练数据、训练…

thinkphp5.1 在fetch模版就超时

场景 当被渲染模版不存在&#xff0c;请求不响应任何内容&#xff0c;过一会就timeout 排查过程 使用xdebug,追踪代码&#xff0c;发现走到D:\temporary_files\m40285_mini\40285_mini\thinkphp\library\think\exception\Handle.php&#xff0c;进入死循环&#xff0c;一直…

【Vue CLI脚手架开发】——6.scoped样式

文章目录 一、scoped是什么二、应用案例1.使用代码2.原理3父组件App未添加scoped影响 一、scoped是什么 我们知道vue为了防止css样式污染&#xff0c;在每个组件中提供了 scoped属性进行限定css作用域&#xff1b;当<style>标签有 scoped 属性时&#xff0c;它的 CSS 只…

微服务,服务治理nacos,负载均衡LOadBalancer,OpenFeign

1.微服务 简单来说&#xff0c;微服务架构风格[1]是一种将一个单一应用程序开发为一组小型服务的方法&#xff0c;每个服务运行在 自己的进程中&#xff0c;服务间通信采用轻量级通信机制(通常用HTTP资源API)。这些服务围绕业务能力构建并 且可通过全自动部署机制独立部署。这…

STM32-USART串口数据包

一&#xff1a;HEX数据包发送 1.为了收发数据包&#xff0c;先定义两个缓存区的数组 &#xff0c;这4个数据只存储发送或者接收的载荷数据&#xff0c;包头和包尾不存 uint8_t Serial_TxPacket[4]; uint8_t Serial_RxPacket[4]; uint8_t Serial_RxFlag;//接收一个数据包就置F…

[项目]基于FreeRTOS的STM32四轴飞行器: 四.LED控制

基于FreeRTOS的STM32四轴飞行器: 四.LED控制 一.配置Com层二.编写驱动 一.配置Com层 先在Com_Config.h中定义灯位置的枚举类型&#xff1a; 之后定义Led的结构体&#xff1a; 定义飞行器状态&#xff1a; 在Com_Config.c中初始化四个灯&#xff1a; 在Com_Config.h外部声明…