当前位置: 首页 > news >正文

【昇腾】NPU ID:物理ID、逻辑ID、芯片映射关系

起因:
https://www.hiascend.com/document/detail/zh/Atlas%20200I%20A2/23.0.0/re/npu/npusmi_013.html
npu-smi info -l查询所有NPU设备:

[naie@notebook-npu-bd130045-55bbffd786-lr6t8 DCNN]$ npu-smi info -lTotal Count                    : 1NPU ID                         : 6Chip Count                     : 1

运行脚本:

import torch_npu
from torch_npu.contrib import transfer_to_npu
import torchimport torch
import torch.nn as nnclass SingleConv(nn.Module):def __init__(self, in_ch, out_ch, kernel_size, stride, padding):super(SingleConv, self).__init__()self.single_conv = nn.Sequential(nn.Conv2d(in_ch, out_ch, kernel_size=kernel_size, padding=padding, stride=stride, bias=False),nn.BatchNorm2d(out_ch),nn.ReLU(inplace=True))def forward(self, x):return self.single_conv(x)class DenseFeaureAggregation(nn.Module):def __init__(self, in_ch, out_ch, base_ch):super(DenseFeaureAggregation, self).__init__()self.conv1 = nn.Sequential(nn.BatchNorm2d(num_features=1 * in_ch, eps=1e-5, affine=True),nn.ReLU(inplace=True),nn.Conv2d(in_ch, base_ch, dilation=2, kernel_size=3, padding=2, stride=1, bias=True),)self.conv2 = nn.Sequential(nn.BatchNorm2d(num_features=in_ch + base_ch, eps=1e-5, affine=True),nn.ReLU(inplace=True),nn.Conv2d(in_ch + base_ch, base_ch, dilation=3, kernel_size=3, padding=3, stride=1, bias=True),)self.conv3 = nn.Sequential(nn.BatchNorm2d(num_features=in_ch + 2 * base_ch, eps=1e-5, affine=True),nn.ReLU(inplace=True),nn.Conv2d(in_ch + 2 * base_ch, base_ch, dilation=5, kernel_size=3, padding=5, stride=1, bias=True),)self.conv4 = nn.Sequential(nn.BatchNorm2d(num_features=in_ch + 3 * base_ch, eps=1e-5, affine=True),nn.ReLU(inplace=True),nn.Conv2d(in_ch + 3 * base_ch, base_ch, dilation=7, kernel_size=3, padding=7, stride=1, bias=True),)self.conv5 = nn.Sequential(nn.BatchNorm2d(num_features=in_ch + 4 * base_ch, eps=1e-5, affine=True),nn.ReLU(inplace=True),nn.Conv2d(in_ch + 4 * base_ch, base_ch, dilation=9, kernel_size=3, padding=9, stride=1, bias=True),)self.conv_out = nn.Sequential(nn.BatchNorm2d(num_features=in_ch + 5 * base_ch, eps=1e-5, affine=True),nn.ReLU(inplace=True),nn.Conv2d(in_ch + 5 * base_ch, out_ch, dilation=1, kernel_size=1, padding=0, stride=1, bias=True),)def forward(self, x):out_ = self.conv1(x)concat_ = torch.cat((out_, x), dim=1)out_ = self.conv2(concat_)concat_ = torch.cat((concat_, out_), dim=1)out_ = self.conv3(concat_)concat_ = torch.cat((concat_, out_), dim=1)out_ = self.conv4(concat_)concat_ = torch.cat((concat_, out_), dim=1)out_ = self.conv5(concat_)concat_ = torch.cat((concat_, out_), dim=1)out_ = self.conv_out(concat_)return out_class Encoder(nn.Module):def __init__(self, in_ch, list_ch):super(Encoder, self).__init__()self.encoder_1 = nn.Sequential(SingleConv(in_ch, list_ch[1], kernel_size=3, stride=1, padding=1),SingleConv(list_ch[1], list_ch[1], kernel_size=3, stride=1, padding=1))self.encoder_2 = nn.Sequential(nn.MaxPool2d(kernel_size=2, stride=2, padding=0),SingleConv(list_ch[1], list_ch[2], kernel_size=3, stride=1, padding=1),SingleConv(list_ch[2], list_ch[2], kernel_size=3, stride=1, padding=1))self.encoder_3 = nn.Sequential(nn.MaxPool2d(kernel_size=2, stride=2, padding=0),SingleConv(list_ch[2], list_ch[3], kernel_size=3, stride=1, padding=1),SingleConv(list_ch[3], list_ch[3], kernel_size=3, stride=1, padding=1))self.encoder_4 = nn.Sequential(nn.MaxPool2d(kernel_size=2, stride=2, padding=0),SingleConv(list_ch[3], list_ch[4], kernel_size=3, stride=1, padding=1),SingleConv(list_ch[4], list_ch[4], kernel_size=3, stride=1, padding=1))self.DFA = DenseFeaureAggregation(list_ch[4], list_ch[4], list_ch[4])def forward(self, x):out_encoder_1 = self.encoder_1(x)out_encoder_2 = self.encoder_2(out_encoder_1)out_encoder_3 = self.encoder_3(out_encoder_2)out_encoder_4 = self.encoder_4(out_encoder_3)out_encoder_4 = self.DFA(out_encoder_4)return [out_encoder_1, out_encoder_2, out_encoder_3, out_encoder_4]class Decoder(nn.Module):def __init__(self, out_ch, list_ch):super(Decoder, self).__init__()self.upconv_3_1 = nn.ConvTranspose2d(list_ch[4], list_ch[3], kernel_size=2, stride=2, bias=True)self.decoder_conv_3_1 = nn.Sequential(SingleConv(2 * list_ch[3], list_ch[3], kernel_size=3, stride=1, padding=1),SingleConv(list_ch[3], list_ch[3], kernel_size=3, stride=1, padding=1))self.upconv_2_1 = nn.ConvTranspose2d(list_ch[3], list_ch[2], kernel_size=2, stride=2, bias=True)self.decoder_conv_2_1 = nn.Sequential(SingleConv(2 * list_ch[2], list_ch[2], kernel_size=3, stride=1, padding=1),SingleConv(list_ch[2], list_ch[2], kernel_size=3, stride=1, padding=1))self.upconv_1_1 = nn.ConvTranspose2d(list_ch[2], list_ch[1], kernel_size=2, stride=2, bias=True)self.decoder_conv_1_1 = nn.Sequential(SingleConv(2 * list_ch[1], list_ch[1], kernel_size=3, stride=1, padding=1),SingleConv(list_ch[1], list_ch[1], kernel_size=3, stride=1, padding=1))self.conv_out = nn.Sequential(nn.Conv2d(list_ch[1], out_ch, kernel_size=1, padding=0, bias=True))def forward(self, out_encoder):out_encoder_1, out_encoder_2, out_encoder_3, out_encoder_4 = out_encoderout_decoder_3_1 = self.decoder_conv_3_1(torch.cat((self.upconv_3_1(out_encoder_4), out_encoder_3), dim=1))out_decoder_2_1 = self.decoder_conv_2_1(torch.cat((self.upconv_2_1(out_decoder_3_1), out_encoder_2), dim=1))out_decoder_1_1 = self.decoder_conv_1_1(torch.cat((self.upconv_1_1(out_decoder_2_1), out_encoder_1), dim=1))output = self.conv_out(out_decoder_1_1)return [output]class Model(nn.Module):def __init__(self, in_ch, out_ch, list_ch):super(Model, self).__init__()self.encoder = Encoder(in_ch, list_ch)self.decoder = Decoder(out_ch, list_ch)# initself.initialize()@staticmethoddef init_conv_deconv_BN(modules):for m in modules():if isinstance(m, nn.Conv2d):nn.init.kaiming_uniform_(m.weight, mode='fan_in', nonlinearity='relu')if m.bias is not None:nn.init.constant_(m.bias, 0.)elif isinstance(m, nn.ConvTranspose2d):nn.init.kaiming_uniform_(m.weight, mode='fan_in', nonlinearity='relu')if m.bias is not None:nn.init.constant_(m.bias, 0.)elif isinstance(m, nn.BatchNorm2d):nn.init.constant_(m.weight, 1.)nn.init.constant_(m.bias, 0.)def initialize(self):print('# random init encoder weight using nn.init.kaiming_uniform !')self.init_conv_deconv_BN(self.decoder.modules)print('# random init decoder weight using nn.init.kaiming_uniform !')self.init_conv_deconv_BN(self.encoder.modules)def forward(self, x):out_encoder = self.encoder(x)out_decoder = self.decoder(out_encoder)  # is a listreturn out_decoderimport re
import subprocessdef get_npu_id():try:# 执行命令并捕获输出output = subprocess.check_output(['npu-smi', 'info', '-l'], text=True)# 使用正则表达式查找NPU IDmatch = re.search(r'NPU ID\s+:\s+(\d+)', output)if match:return match.group(1)  # 返回匹配的第一个组,即NPU IDelse:return "NPU ID not found"except subprocess.CalledProcessError as e:return f"An error occurred: {e}"network = Model(in_ch=4, out_ch=1,list_ch=[-1, 32, 64, 128, 256])npu_id = get_npu_id()
# list_GPU_ids = [npu_id]
device = torch.device('cuda:' + str(npu_id))
network.to(device)
print("device:",npu_id)

报错:

Traceback (most recent call last):File "/home/work/user-job-dir/app/notebook/RTDosePrediction-main/RTDosePrediction/Src/DCNN/test_device_id.py", line 211, in <module>network.to(device)File "/home/naie/.local/lib/python3.9/site-packages/torch_npu/contrib/transfer_to_npu.py", line 56, in decoratedreturn fn(*args, **kwargs)File "/home/naie/.local/lib/python3.9/site-packages/torch_npu/utils/module.py", line 68, in toreturn self._apply(convert)File "/home/naie/.local/lib/python3.9/site-packages/torch/nn/modules/module.py", line 810, in _applymodule._apply(fn)File "/home/naie/.local/lib/python3.9/site-packages/torch/nn/modules/module.py", line 810, in _applymodule._apply(fn)File "/home/naie/.local/lib/python3.9/site-packages/torch/nn/modules/module.py", line 810, in _applymodule._apply(fn)[Previous line repeated 2 more times]File "/home/naie/.local/lib/python3.9/site-packages/torch/nn/modules/module.py", line 833, in _applyparam_applied = fn(param)File "/home/naie/.local/lib/python3.9/site-packages/torch_npu/utils/module.py", line 66, in convertreturn t.to(device, dtype if t.is_floating_point() or t.is_complex() else None, non_blocking)File "/home/naie/.local/lib/python3.9/site-packages/torch_npu/contrib/transfer_to_npu.py", line 56, in decoratedreturn fn(*args, **kwargs)
RuntimeError: exchangeDevice:torch_npu/csrc/aten/common/CopyKernel.cpp:37 NPU error, error code is 107001
[ERROR] 2024-12-13-10:47:03 (PID:38196, Device:0, RankID:-1) ERR00100 PTA call acl api failed
[Error]: Invalid device ID.Check whether the device ID is valid.
EE1001: 2024-12-13-10:47:03.815.272 The argument is invalid.Reason: Set device failed, invalid device, set device=6, valid device range is [0, 1)Solution: 1.Check the input parameter range of the function. 2.Check the function invocation relationship.TraceBack (most recent call last):rtSetDevice execute failed, reason=[device id error][FUNC:FuncErrorReason][FILE:error_message_manage.cc][LINE:53]open device 6 failed, runtime result = 107001.[FUNC:ReportCallError][FILE:log_inner.cpp][LINE:161]

猜想也许是进行了从物理ID到逻辑ID的映射。
查了一下华为的官方文档:
https://www.hiascend.com/document/detail/zh/Atlas%20200I%20A2/23.0.0/re/npu/npusmi_013.html
还真的存在这么一个映射。
在这里插入图片描述

遂用这个命令查看了当前环境下的芯片映射关系:

[naie@notebook-npu-bd130045-55bbffd786-lr6t8 DCNN]$ npu-smi info -mNPU ID                         Chip ID                        Chip Logic ID                  Chip Name                     6                              0                              0                              Ascend 910B36                              1                              -                              Mcu 

确实物理ID为6的NPU被映射成了0。这是因为当前环境下(notebook)中只存在一个NPU。

但是还有一个问题:什么时候使用物理ID什么时候使用逻辑ID呢?

物理ID

npu-smi info -t power -i id类似于这种命令里使用的id都是物理ID:
在这里插入图片描述
因为npu-smi info -l查出来的是物理ID。

逻辑ID

device = torch.device('cuda:' + str(npu_id))这种就用的是逻辑ID

相关文章:

【昇腾】NPU ID:物理ID、逻辑ID、芯片映射关系

起因&#xff1a; https://www.hiascend.com/document/detail/zh/Atlas%20200I%20A2/23.0.0/re/npu/npusmi_013.html npu-smi info -l查询所有NPU设备&#xff1a; [naienotebook-npu-bd130045-55bbffd786-lr6t8 DCNN]$ npu-smi info -lTotal Count : 1NPU…...

Three.js曲线篇 8.管道漫游

目录 创建样条曲线 创建管道 透视相机漫游 完整代码 大家不要被这个“管道漫游”这几个字所蒙骗了&#xff0c;学完后大家就知道这个知识点有多脏了。我也是误入歧途&#xff0c;好奇了一下“管道漫游”。好了&#xff0c;现在就给大家展示一下为啥这个只是点脏了。 我也废话…...

scala基础_数据类型概览

Scala 数据类型 下表列出了 Scala 支持的数据类型&#xff1a; 类型类别数据类型描述Scala标准库中的实际类基本类型Byte8位有符号整数&#xff0c;数值范围为 -128 到 127scala.Byte基本类型Short16位有符号整数&#xff0c;数值范围为 -32768 到 32767scala.Short基本类型I…...

【LeetCode刷题之路】622.设计循环队列

LeetCode刷题记录 &#x1f310; 我的博客主页&#xff1a;iiiiiankor&#x1f3af; 如果你觉得我的内容对你有帮助&#xff0c;不妨点个赞&#x1f44d;、留个评论✍&#xff0c;或者收藏⭐&#xff0c;让我们一起进步&#xff01;&#x1f4dd; 专栏系列&#xff1a;LeetCode…...

暂停一下,给Next.js项目配置一下ESLint(Next+tailwind项目)

前提 之前开自己的GitHub项目&#xff0c;想着不是团队项目&#xff0c;偷懒没有配置eslint&#xff0c;后面发现还是不行。eslint的存在可以帮助我们规范代码格式&#xff0c;同时 ctrl s保存立即调整代码格式是真的很爽。 除此之外&#xff0c;团队使用eslint也是好处颇多…...

Windows系统磁盘与分区之详解(Detailed Explanation of Windows System Disks and Partitions)

Windows系统磁盘与分区知识详解 在日常使用Windows操作系统的过程中,我们常常会接触到磁盘管理,磁盘分区等操作.然而,许多人可能并不完全理解磁盘和分区的运作原理以及如何高效管理它们. 本篇文章将探讨Windows系统中关于磁盘和分区的各种知识,帮助大家更好地理解磁盘以及分区…...

顺序表的使用,对数据的增删改查

主函数&#xff1a; 3.c #include "3.h"//头文件调用 SqlListptr sql_cerate()//创建顺序表函数 {SqlListptr ptr(SqlListptr)malloc(sizeof(SqlList));//在堆区申请连续的空间if(NULLptr){printf("创建失败\n");return NULL;//如果没有申请成功&#xff…...

XDMA与FPGA:高效数据传输的艺术

XDMA与FPGA&#xff1a;高效数据传输的艺术 引言 在现代计算系统中&#xff0c;数据传输的效率直接影响系统的整体性能。特别是在涉及到高速数据处理的领域&#xff0c;如高性能计算&#xff08;HPC&#xff09;、实时视频处理和大数据分析等&#xff0c;如何高效地在主机与F…...

#思科模拟器通过服务配置保障无线网络安全Radius

演示拓扑图&#xff1a; 搭建拓扑时要注意&#xff1a; 只能连接它的Ethernet接口&#xff0c;不然会不通 MAC地址绑定 要求 &#xff1a;通过配置MAC地址过滤禁止非内部员工连接WiFi 打开无线路由器GUI界面&#xff0c;点开下图页面&#xff0c;配置路由器无线网络MAC地址过…...

浅谈Python库之pillow

一、pillow的介绍 Pillow是Python Imaging Library (PIL) 的一个分支&#xff0c;它是一个强大的图像处理库&#xff0c;用于打开、操作和保存许多不同图像文件格式。Pillow提供了广泛的文件格式支持、强大的图像处理能力和广泛的文件格式兼容性。它是PIL的一个友好的分支&…...

Android通过okhttp下载文件(本文案例 下载mp4到本地,并更新到相册)

使用步骤分为两步 第一步导入 okhttp3 依赖 第二步调用本文提供的 utils 第一步这里不做说明了&#xff0c;直接提供第二步复制即用 DownloadUtil 中 download 为下载文件 参数说明 这里主要看你把 destFileName 下载文件名称定义为什么后缀&#xff0c;比如我定义为 .mp4 下…...

计算机网络从诞生之初到至今的发展历程

前言 "上网"&#xff0c;相信大家对这个动词已经不再陌生&#xff0c;网 通常指的是网络&#xff1b;在 2024 年的今天&#xff0c;网络已经渗透到了每个人的生活中&#xff0c;成为其不可或缺的一部分&#xff1b;你此时此刻在看到我的博客&#xff0c;就是通过网络…...

Kudu 源码编译-aarch架构 1.17.1版本

跟着官方文档编译 第一个问题&#xff1a;在make阶段时会报的问题&#xff1a; kudu/src/kudu/util/block_bloom_filter.cc:210:3: error: ‘vst1q_u32_x2’ was not declared in this scope kudu/src/kudu/util/block_bloom_filter.cc:436:5: error: ‘vst1q_u8_x2’ was no…...

SEC_ASA 第二天作业

拓扑 按照拓扑图配置 NTP&#xff0c;Server端为 Outside路由器&#xff0c;Client端为 ASA&#xff0c;两个设备的 NTP传输使用MD5做校验。&#xff08;安全 V4 LAB考点&#xff09; 提示&#xff1a;Outside路由器作为 Server端要配置好正确的时间和时区&#xff0c;ASA防…...

操作系统(5)进程

一、定义与特点 定义&#xff1a;进程是计算机中的程序关于某数据集合上的一次运行活动&#xff0c;是系统进行资源分配和调度的基本单位&#xff0c;是操作系统结构的基础。 特点&#xff1a; 动态性&#xff1a;进程是动态创建的&#xff0c;有它自身的生命周期&#xff0c;…...

6_Sass 选择器函数 --[CSS预处理]

Sass 提供了一系列的选择器函数&#xff0c;用于操作和组合CSS选择器。这些函数可以帮助你更灵活地创建样式规则&#xff0c;并且可以减少重复代码。以下是几个常用的选择器函数及其用法&#xff1a; 1. selector-append($selector1, $selector2...) selector-append($select…...

考研数学【线性代数基础box(数二)】

本文是对数学二线性代数基础进行总结&#xff0c;一些及极其简单的被省略了&#xff0c;代数的概念稀碎&#xff0c;不如高数关联性高&#xff0c;所以本文仅供参考&#xff0c;做题请从中筛选&#xff01; 本文为初稿&#xff0c;后面会根据刷题和自己的理解继续更新 第一章…...

ModbusTcp获取数据

ModbusTcp获取数据 记录一个用 pymodbus 库来获取数据的代码。 注意&#xff1a; 1.读取寄存器地址是16进制的。2.大小端转换通过代码知道原理。读取数据时&#xff0c;切记频率别太高&#xff0c;否则会出现连接被关闭问题。 from pymodbus.client.sync import ModbusTcpCli…...

java 知识点:注解及使用

注解 大多数时候&#xff0c;我们会使用注解&#xff0c;而不是自定义注解。注解给谁用&#xff1f;编译器 、给解析程序用注解不是程序的一部分&#xff0c;可以理解为注解就是一个标签 主要的作用有以下四方面&#xff1a; 生成文档&#xff0c;通过代码里标识的元数据生成…...

AI预测体彩排3采取888=3策略+和值012路+胆码+通杀1码测试12月13日升级新模型预测第156弹

经过100多期的测试&#xff0c;当然有很多彩友也一直在观察我每天发的预测结果&#xff0c;得到了一个非常有价值的信息&#xff0c;那就是9码定位的命中率非常高&#xff0c;已到达90%的命中率&#xff0c;这给喜欢打私菜的朋友提供了极高价值的预测结果~当然了&#xff0c;大…...

Windows 11三指拖拽功能完全配置指南:从驱动安装到手势优化

Windows 11三指拖拽功能完全配置指南&#xff1a;从驱动安装到手势优化 【免费下载链接】ThreeFingersDragOnWindows Enables macOS-style three-finger dragging functionality on Windows Precision touchpads. 项目地址: https://gitcode.com/gh_mirrors/th/ThreeFingersD…...

深入解析PyTorch中.pth文件的保存与加载机制

1. 揭开.pth文件的神秘面纱 第一次接触PyTorch时&#xff0c;看到那些以.pth结尾的文件&#xff0c;你是不是也和我当初一样充满疑惑&#xff1f;这些看似普通的文件&#xff0c;实际上是PyTorch模型持久化的关键。简单来说&#xff0c;.pth文件就像是给AI模型拍的一张"照…...

低代码拖拽逻辑执行慢10倍?:用3个内存布局优化+1个opcode精简表,让RuleEngine吞吐量突破23,000 TPS

第一章&#xff1a;低代码拖拽逻辑执行慢10倍&#xff1f;&#xff1a;用3个内存布局优化1个opcode精简表&#xff0c;让RuleEngine吞吐量突破23,000 TPS低代码规则引擎在拖拽式策略编排场景下&#xff0c;常因对象频繁分配、字段间接寻址与冗余指令解析导致执行路径膨胀。我们…...

Zotero文献管理效率革命:Ethereal Style插件深度应用指南

Zotero文献管理效率革命&#xff1a;Ethereal Style插件深度应用指南 【免费下载链接】zotero-style zotero-style - 一个 Zotero 插件&#xff0c;提供了一系列功能来增强 Zotero 的用户体验&#xff0c;如阅读进度可视化和标签管理&#xff0c;适合研究人员和学者。 项目地…...

AI辅助开发新思路:让快马AI为你的下拉词功能注入智能排序与语义联想

AI辅助开发新思路&#xff1a;让快马AI为你的下拉词功能注入智能排序与语义联想 最近在开发一个需要智能下拉词功能的项目时&#xff0c;我发现传统的前缀匹配方式已经不能满足用户需求了。于是我开始探索如何用AI来增强下拉词功能&#xff0c;让它变得更智能、更人性化。经过…...

SeqGPT-560M金融信贷申请:申请人/收入证明/抵押物/授信额度结构化

SeqGPT-560M金融信贷申请&#xff1a;申请人/收入证明/抵押物/授信额度结构化 1. 项目概述 SeqGPT-560M是一个专门针对金融信贷场景深度优化的智能信息抽取系统。与通用聊天模型不同&#xff0c;这个系统专注于从复杂的非结构化文本中精准提取关键金融信息&#xff0c;特别适…...

【STM32HAL库实战】DAC精准输出0-3.3V可调电压与ADC自检闭环

1. DAC与ADC的基础原理 在嵌入式系统中&#xff0c;数字信号和模拟信号的相互转换是常见需求。STM32微控制器内置了DAC&#xff08;数字模拟转换器&#xff09;和ADC&#xff08;模拟数字转换器&#xff09;模块&#xff0c;让我们能够轻松实现这种转换。 DAC的作用是将数字量转…...

OpenClaw技能扩展:基于nanobot开发自定义自动化模块

OpenClaw技能扩展&#xff1a;基于nanobot开发自定义自动化模块 1. 为什么选择nanobot作为技能开发基础 当我第一次尝试为OpenClaw开发自定义技能时&#xff0c;面对庞大的框架和复杂的依赖关系感到无从下手。直到发现nanobot这个轻量级解决方案&#xff0c;才真正找到了适合…...

【AI工具篇】10款免费AI聊天与绘画神器:从GPT到Stable Diffusion的全方位体验

1. GPT机器人&#xff1a;全能型AI助手 这款工具可以说是AI领域的瑞士军刀&#xff0c;既能陪你聊天又能帮你画画。我实测下来最惊艳的是它直接集成了GPT-4模型&#xff0c;要知道很多收费工具都还在用3.5版本。打开应用就像有个学霸朋友随时待命——上周我写项目方案卡壳时&am…...

RViz实战:如何用C++在ROS中动态切换不同形状的物体(含避坑指南)

RViz实战&#xff1a;如何用C在ROS中动态切换不同形状的物体&#xff08;含避坑指南&#xff09; 在机器人开发过程中&#xff0c;RViz作为ROS生态中的三维可视化利器&#xff0c;其核心价值在于让抽象的数据变得直观可见。而Marker消息系统则是实现这种可视化的关键桥梁——它…...