
💡💡💡本文摘要:基于YOLO26的晶圆缺陷检测系统,阐述了整个数据制作和训练可视化过程

在半导体制造中,晶圆缺陷检测的意义主要体现在以下方面:
因此,该任务对于提升半导体制造的经济性、可靠性和技术竞争力具有关键价值。
博主简介

AI小怪兽 | 计算机视觉布道者 | 视觉检测领域创新者
深耕计算机视觉与深度学习领域,专注于目标检测前沿技术的探索与突破。长期致力于YOLO系列算法的结构性创新、性能极限优化与工业级落地实践,旨在打通从学术研究到产业应用的最后一公里。

论文:https://arxiv.org/pdf/2509.25164
摘要:本研究对Ultralytics YOLO26进行了全面分析,重点阐述了其关键架构改进及其在实时边缘目标检测中的性能基准测试。YOLO26于2025年9月发布,是YOLO系列最新、最先进的成员,专为在边缘及低功耗设备上实现高效、精确且易于部署的目标而构建。本文依次详述了YOLO26的架构创新,包括:移除了分布焦点损失(DFL);采用端到端的无NMS推理;集成了渐进损失(ProgLoss)与小目标感知标签分配(STAL);以及引入了用于稳定收敛的MuSGD优化器。除架构外,本研究将YOLO26定位为多任务框架,支持目标检测、实例分割、姿态/关键点估计、定向检测及分类。我们在NVIDIA Jetson Nano与Orin等边缘设备上呈现了YOLO26的性能基准测试,并将其结果与YOLOv8、YOLOv11、YOLOv12、YOLOv13及基于Transformer的检测器进行比较。本文进一步探讨了其实时部署路径、灵活的导出选项(ONNX、TensorRT、CoreML、TFLite)以及INT8/FP16量化技术。文章重点展示了YOLO26在机器人、制造业及物联网等领域的实际应用案例,以证明其跨行业适应性。最后,讨论了关于部署效率及更广泛影响的见解,并展望了YOLO26及YOLO系列的未来发展方向。
关键词:YOLO26;边缘人工智能;多任务目标检测;无NMS推理;小目标识别;YOLO(You Only Look Once);目标检测;MuSGD优化器

结构框图如下:


1)池化次数灵活性:YOLO11 的 3 次池化是硬编码的,要修改必须改源码;YOLO26 通过n参数可灵活调整(比如设为 2 次或 4 次),无需改核心逻辑。
2)Shortcut 设计:YOLO26 新增的残差连接能缓解深层网络的梯度消失问题,提升特征复用能力,而 YOLO11 无此设计。
3)激活函数控制:YOLO26 禁用 Conv1 的激活函数,让特征在池化前保持更 “原始” 的状态,是工程上对特征提取的优化。

源码位置:ultralytics/nn/modules/block.py
1)注意力机制的新增:YOLO26 的 C3k2 首次引入PSABlock(金字塔注意力模块),通过attn参数控制是否启用,这是两者最核心的功能差异 —— 启用后模块会先通过 Bottleneck 提取基础特征,再通过 PSABlock 增强关键区域的特征权重,提升小目标 / 复杂场景的检测效果。
2)分支逻辑的扩展:YOLO11 的分支仅受c3k控制,而 YOLO26 的分支逻辑优先级为attn > c3k,即只要attn=True,会优先启用注意力模块,忽略c3k的配置。

重复模块m (n次迭代):
┌─────────────────────────────────────────────────────────┐
│ │
│ 如果 attn=True: │
│ Sequential( │
│ Bottleneck(self.c, self.c), │ ←─ 先特征提取
│ PSABlock(self.c, attn_ratio=0.5, num_heads=...) │ ←─ 后注意力增强
│ ) │
│ │
│ 否则如果 c3k=True: │
│ C3k(self.c, self.c, 2) │ ←─ 同YOLOv11
│ │
│ 否则: │
│ Bottleneck(self.c, self.c) │ ←─ 同YOLOv11
│ │
└─────────────────────────────────────────────────────────┘YOLO26 C3k2代码:
源码位置:ultralytics/nn/modules/block.py
YOLO26引入了多项关键架构创新,使其区别于前几代YOLO模型。这些增强不仅提高了训练稳定性和推理效率,还从根本上重塑了实时边缘设备的部署流程。本节将详细描述YOLO26的四项主要贡献:(i)移除分布焦点损失(DFL),(ii)引入端到端无NMS推理,(iii)新颖的损失函数策略,包括渐进损失平衡(ProgLoss)和小目标感知标签分配(STAL),以及(iv)开发用于稳定高效收敛的MuSGD优化器。我们将详细讨论每一项架构增强,并通过对比分析突显其相对于YOLOv8、YOLOv11、YOLOv12和YOLOv13等早期YOLO版本的优势。

YOLO26最重要的架构简化之一是移除了分布焦点损失(DFL)模块(图3a),该模块曾存在于YOLOv8和YOLOv11等早期YOLO版本中。DFL最初旨在通过预测边界框坐标的概率分布来改进边界框回归,从而实现更精确的目标定位。虽然该策略在早期模型中展示了精度提升,但也带来了不小的计算开销和导出困难。在实践中,DFL在推理和模型导出期间需要专门处理,这使针对ONNX、CoreML、TensorRT或TFLite等硬件加速器的部署流程变得复杂。
源码位置:ultralytics/utils/loss.py
通过reg_max 设置为1,移除了分布焦点损失(DFL)
class BboxLoss(nn.Module):
"""Criterion class for computing training losses for bounding boxes."""
def __init__(self, reg_max: int = 16):
"""Initialize the BboxLoss module with regularization maximum and DFL settings."""
super().__init__()
self.dfl_loss = DFLoss(reg_max) if reg_max > 1 else NoneYOLO26从根本上重新设计了预测头,以直接产生非冗余的边界框预测,无需NMS。这种端到端设计不仅降低了推理复杂度,还消除了对手动调优阈值的依赖,从而简化了集成到生产系统的过程。对比基准测试表明,YOLO26实现了比YOLOv11和YOLOv12更快的推理速度,其中nano模型在CPU上的推理时间减少了高达43%。这使得YOLO26对于移动设备、无人机和嵌入式机器人平台特别有利,在这些平台上,毫秒级的延迟可能产生重大的操作影响。
源码位置:ultralytics/utils/nms.py
训练稳定性和小目标识别仍然是目标检测中持续存在的挑战。YOLO26通过整合两种新颖策略来解决这些问题:渐进损失平衡(ProgLoss)和小目标感知标签分配(STAL),如图(图3c)所示。
ProgLoss在训练期间动态调整不同损失分量的权重,确保模型不会过拟合于主导物体类别,同时防止在稀有或小类别上表现不佳。这种渐进式再平衡改善了泛化能力,并防止了训练后期的不稳定。另一方面,STAL明确优先为小目标分配标签,由于像素表示有限且易被遮挡,小目标尤其难以检测。ProgLoss和STAL共同为YOLO26在包含小目标或被遮挡目标的数据集(如COCO和无人机图像基准)上带来了显著的精度提升。
YOLO26的最后一项创新是引入了MuSGD优化器(图3d),它结合了随机梯度下降(SGD)的优势与最近提出的Muon优化器(一种受大型语言模型训练中使用的优化策略启发而发展的技术)。MuSGD利用SGD的鲁棒性和泛化能力,同时融入了来自Muon的自适应特性,能够在不同数据集上实现更快的收敛和更稳定的优化。
源码位置:ultralytics/optim/muon.py
"""
基于YOLO26的晶圆缺陷检测系统
Python源码 + 数据集 + PySide6界面
YOLO26关键特性:
- 端到端无NMS设计,直接输出最终检测结果[reference:0]
- 移除DFL(分布焦点损失),推理更简洁[reference:1]
- MuSGD优化器,训练更稳定[reference:2]
- ProgLoss + STAL(小目标感知标签分配),提升小目标检测能力[reference:3]
"""
import os
import sys
import cv2
import numpy as np
from pathlib import Path
from PySide6.QtWidgets import *
from PySide6.QtCore import *
from PySide6.QtGui import *
from ultralytics import YOLO
# ==================== 一、配置模块 ====================
class Config:
"""系统配置类"""
# 模型配置
MODEL_NAME = "yolo26n.pt" # 模型权重文件[reference:4]
MODEL_SIZE = "nano" # nano/s/m/l/x
IMG_SIZE = 640 # 输入图像尺寸
CONF_THRESHOLD = 0.25 # 置信度阈值[reference:5]
# 数据集配置[reference:6]
DATA_YAML = "data/wafers.yaml" # 数据集配置文件
# 典型缺陷类别: Center, Donut, Edge-Loc, Edge-Ring, Loc, Near-full, None, Random, Scratch
# 训练配置
EPOCHS = 100
BATCH_SIZE = 16
DEVICE = "cuda" # cuda / cpu
# 路径配置
WEIGHTS_DIR = "weights/"
RESULTS_DIR = "results/"
DETECTIONS_DIR = "detections/"
# ==================== 二、数据加载模块 ====================
class DatasetManager:
"""晶圆缺陷数据集管理器"""
def __init__(self, data_yaml):
self.data_yaml = data_yaml
self.class_names = []
self._load_classes()
def _load_classes(self):
"""从data.yaml加载类别名称"""
# 读取YAML文件,提取names字段
# 典型晶圆缺陷类别:Center, Donut, Edge-Loc, Edge-Ring, Loc, Near-full, None, Random, Scratch[reference:7]
pass
def get_dataset_info(self):
"""返回数据集信息:类别数、训练集/验证集路径"""
return {
"num_classes": 9,
"train_path": "data/train/images",
"val_path": "data/val/images",
"class_names": self.class_names
}
def visualize_sample(self, image_path, annotation):
"""可视化单个样本的标注框"""
# 读取图像,绘制边界框和标签
pass
# ==================== 三、YOLO26模型模块 ====================
class YOLO26Model:
"""
YOLO26晶圆缺陷检测模型
特点:端到端无NMS推理,CPU推理速度提升最高43%[reference:8][reference:9]
"""
def __init__(self, model_path=None):
self.model = None
self.model_path = model_path
self.class_names = []
def load_model(self, model_path):
"""加载预训练或自定义模型权重"""
# YOLO26支持五种尺寸:nano(s), small(s), medium(m), large(l), extra large(x)[reference:10]
self.model = YOLO(model_path)
self.class_names = self.model.names
return self.model
def train(self, data_yaml, epochs, batch_size, imgsz, device):
"""
训练YOLO26模型
YOLO26采用MuSGD优化器确保稳定收敛[reference:11][reference:12]
"""
if self.model is None:
# 从预训练权重开始训练
self.model = YOLO(Config.MODEL_NAME)
# 训练参数
results = self.model.train(
data=data_yaml, # 数据集配置
epochs=epochs, # 训练轮数
batch=batch_size, # 批次大小
imgsz=imgsz, # 输入图像尺寸
device=device, # 计算设备
project=Config.RESULTS_DIR, # 结果保存目录
name="wafer_detection", # 实验名称
patience=50, # 早停耐心值
save=True, # 保存检查点
exist_ok=True, # 覆盖已有结果
# YOLO26特有:端到端训练默认启用[reference:13]
# 双头架构:一对一(端到端推理)+ 一对多(传统输出)[reference:14]
)
return results
def validate(self, data_yaml):
"""在验证集上评估模型性能"""
if self.model is None:
raise ValueError("请先加载或训练模型")
metrics = self.model.val(
data=data_yaml,
imgsz=Config.IMG_SIZE,
batch=Config.BATCH_SIZE,
device=Config.DEVICE
)
# 返回mAP50, mAP50-95等指标
return metrics
def predict(self, image, conf_threshold=0.25):
"""
推理预测 - 端到端无NMS[reference:15]
YOLO26直接输出最终检测结果,无需额外NMS后处理
输出格式: (N, 300, 6) 即 xyxy 格式[reference:16]
"""
if self.model is None:
raise ValueError("请先加载模型")
# 执行推理
results = self.model(
image, # 输入图像
imgsz=Config.IMG_SIZE, # 推理尺寸
conf=conf_threshold, # 置信度阈值[reference:17]
device=Config.DEVICE,
verbose=False
)
# 解析检测结果
detections = []
for result in results:
boxes = result.boxes
if boxes is not None:
for box in boxes:
detection = {
"bbox": box.xyxy[0].tolist(), # [x1, y1, x2, y2]
"confidence": float(box.conf[0]),
"class_id": int(box.cls[0]),
"class_name": self.class_names[int(box.cls[0])]
}
detections.append(detection)
return {
"detections": detections,
"image_shape": image.shape[:2] if isinstance(image, np.ndarray) else None
}
def export_model(self, format="onnx"):
"""
导出模型到不同格式
支持: ONNX, TensorRT, CoreML, TFLite[reference:18]
"""
if self.model is None:
raise ValueError("请先加载模型")
export_path = self.model.export(
format=format,
imgsz=Config.IMG_SIZE,
device=Config.DEVICE
)
return export_path
# ==================== 四、图像处理模块 ====================
class ImageProcessor:
"""图像预处理和后处理"""
@staticmethod
def preprocess(image, target_size=640):
"""图像预处理:缩放、归一化等"""
if isinstance(image, str):
image = cv2.imread(image)
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# 保持宽高比的缩放
h, w = image.shape[:2]
scale = target_size / max(h, w)
new_w, new_h = int(w * scale), int(h * scale)
resized = cv2.resize(image, (new_w, new_h))
# 填充到目标尺寸
padded = np.full((target_size, target_size, 3), 114, dtype=np.uint8)
pad_x = (target_size - new_w) // 2
pad_y = (target_size - new_h) // 2
padded[pad_y:pad_y+new_h, pad_x:pad_x+new_w] = resized
return padded, (pad_x, pad_y, scale)
@staticmethod
def draw_detections(image, detections, class_names, color_map=None):
"""在图像上绘制检测框和标签"""
img_copy = image.copy()
for det in detections:
x1, y1, x2, y2 = map(int, det["bbox"])
conf = det["confidence"]
cls_name = det["class_name"]
# 绘制边界框
color = color_map.get(cls_name, (0, 255, 0)) if color_map else (0, 255, 0)
cv2.rectangle(img_copy, (x1, y1), (x2, y2), color, 2)
# 绘制标签
label = f"{cls_name} {conf:.2f}"
cv2.putText(img_copy, label, (x1, y1-10),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)
return img_copy
# ==================== 五、PySide6界面模块 ====================
class WaferDetectionUI(QMainWindow):
"""晶圆缺陷检测系统主界面"""
def __init__(self):
super().__init__()
self.model = None
self.current_image = None
self.detection_results = None
self.init_ui()
def init_ui(self):
"""初始化用户界面"""
self.setWindowTitle("基于YOLO26的晶圆缺陷检测系统")
self.setMinimumSize(1200, 800)
# 主布局
central_widget = QWidget()
self.setCentralWidget(central_widget)
main_layout = QHBoxLayout(central_widget)
# === 左侧控制面板 ===
left_panel = QWidget()
left_panel.setFixedWidth(280)
left_layout = QVBoxLayout(left_panel)
# 模型加载区域
model_group = QGroupBox("模型管理")
model_layout = QVBoxLayout(model_group)
self.model_path_edit = QLineEdit()
self.model_path_edit.setPlaceholderText("选择模型权重文件...")
model_btn_layout = QHBoxLayout()
self.load_model_btn = QPushButton("加载模型")
self.load_model_btn.clicked.connect(self.load_model)
model_btn_layout.addWidget(self.load_model_btn)
self.train_btn = QPushButton("训练模型")
self.train_btn.clicked.connect(self.train_model)
model_btn_layout.addWidget(self.train_btn)
model_layout.addWidget(self.model_path_edit)
model_layout.addLayout(model_btn_layout)
left_layout.addWidget(model_group)
# 图像输入区域
input_group = QGroupBox("图像输入")
input_layout = QVBoxLayout(input_group)
self.load_image_btn = QPushButton("加载图片")
self.load_image_btn.clicked.connect(self.load_image)
self.load_video_btn = QPushButton("加载视频")
self.load_video_btn.clicked.connect(self.load_video)
self.camera_btn = QPushButton("摄像头检测")
self.camera_btn.clicked.connect(self.start_camera)
input_layout.addWidget(self.load_image_btn)
input_layout.addWidget(self.load_video_btn)
input_layout.addWidget(self.camera_btn)
left_layout.addWidget(input_group)
# 检测控制区域
detect_group = QGroupBox("缺陷检测")
detect_layout = QVBoxLayout(detect_group)
self.detect_btn = QPushButton("开始检测")
self.detect_btn.clicked.connect(self.run_detection)
self.detect_btn.setStyleSheet("background-color: #4CAF50; color: white;")
self.conf_threshold_spin = QDoubleSpinBox()
self.conf_threshold_spin.setRange(0.0, 1.0)
self.conf_threshold_spin.setValue(0.25)
self.conf_threshold_spin.setSingleStep(0.05)
detect_layout.addWidget(QLabel("置信度阈值:"))
detect_layout.addWidget(self.conf_threshold_spin)
detect_layout.addWidget(self.detect_btn)
left_layout.addWidget(detect_group)
# 结果显示区域
result_group = QGroupBox("检测结果")
result_layout = QVBoxLayout(result_group)
self.result_text = QTextEdit()
self.result_text.setReadOnly(True)
result_layout.addWidget(self.result_text)
left_layout.addWidget(result_group)
left_layout.addStretch()
main_layout.addWidget(left_panel)
# === 右侧图像显示区域 ===
right_panel = QWidget()
right_layout = QVBoxLayout(right_panel)
self.image_label = QLabel()
self.image_label.setAlignment(Qt.AlignCenter)
self.image_label.setStyleSheet("background-color: #2b2b2b;")
self.image_label.setMinimumSize(800, 600)
right_layout.addWidget(self.image_label)
# 状态栏
self.status_label = QLabel("就绪 - 请加载模型和图像")
right_layout.addWidget(self.status_label)
main_layout.addWidget(right_panel)
# 设置布局比例
main_layout.setStretchFactor(left_panel, 1)
main_layout.setStretchFactor(right_panel, 3)
def load_model(self):
"""加载YOLO26模型"""
file_path, _ = QFileDialog.getOpenFileName(
self, "选择模型权重", "", "PyTorch模型 (*.pt);;ONNX模型 (*.onnx)"
)
if file_path:
self.model_path_edit.setText(file_path)
try:
self.model = YOLO26Model()
self.model.load_model(file_path)
self.status_label.setText(f"模型加载成功: {os.path.basename(file_path)}")
self.result_text.append(f"[INFO] 模型加载成功: {file_path}")
except Exception as e:
QMessageBox.critical(self, "错误", f"模型加载失败: {str(e)}")
def train_model(self):
"""启动模型训练"""
# 显示训练配置对话框
# 调用 YOLO26Model.train()
# 显示训练进度
pass
def load_image(self):
"""加载单张图片"""
file_path, _ = QFileDialog.getOpenFileName(
self, "选择晶圆图像", "", "图像文件 (*.png *.jpg *.jpeg *.bmp)"
)
if file_path:
self.current_image = cv2.imread(file_path)
self.current_image = cv2.cvtColor(self.current_image, cv2.COLOR_BGR2RGB)
self.display_image(self.current_image)
self.status_label.setText(f"已加载图像: {os.path.basename(file_path)}")
def load_video(self):
"""加载视频文件"""
file_path, _ = QFileDialog.getOpenFileName(
self, "选择视频文件", "", "视频文件 (*.mp4 *.avi *.mov)"
)
if file_path:
self.status_label.setText(f"已加载视频: {os.path.basename(file_path)}")
# 启动视频检测线程
pass
def start_camera(self):
"""启动摄像头实时检测"""
self.status_label.setText("摄像头已启动 - 按ESC退出")
# 启动摄像头检测线程
pass
def run_detection(self):
"""执行缺陷检测"""
if self.model is None or self.model.model is None:
QMessageBox.warning(self, "警告", "请先加载模型!")
return
if self.current_image is None:
QMessageBox.warning(self, "警告", "请先加载图像!")
return
try:
conf_threshold = self.conf_threshold_spin.value()
# 执行推理
result = self.model.predict(self.current_image, conf_threshold)
self.detection_results = result
# 绘制检测结果
annotated = ImageProcessor.draw_detections(
self.current_image,
result["detections"],
self.model.class_names
)
self.display_image(annotated)
# 显示检测统计
num_defects = len(result["detections"])
self.result_text.clear()
self.result_text.append(f"检测到 {num_defects} 个缺陷")
self.result_text.append("-" * 40)
for i, det in enumerate(result["detections"], 1):
self.result_text.append(
f"{i}. {det['class_name']} "
f"置信度: {det['confidence']:.3f}"
)
self.status_label.setText(f"检测完成: 发现 {num_defects} 个缺陷")
except Exception as e:
QMessageBox.critical(self, "错误", f"检测失败: {str(e)}")
def display_image(self, image):
"""在界面上显示图像"""
if image is None:
return
# 缩放以适应显示区域
h, w = image.shape[:2]
label_size = self.image_label.size()
scale = min(label_size.width() / w, label_size.height() / h) * 0.95
new_w, new_h = int(w * scale), int(h * scale)
resized = cv2.resize(image, (new_w, new_h))
# 转换为QPixmap
if len(image.shape) == 3:
h, w, ch = resized.shape
bytes_per_line = ch * w
qt_image = QImage(resized.data, w, h, bytes_per_line, QImage.Format_RGB888)
else:
h, w = resized.shape
qt_image = QImage(resized.data, w, h, w, QImage.Format_Grayscale8)
pixmap = QPixmap.fromImage(qt_image)
self.image_label.setPixmap(pixmap)
def closeEvent(self, event):
"""窗口关闭事件"""
# 释放资源
event.accept()
# ==================== 六、主程序入口 ====================
def main():
"""系统主入口"""
app = QApplication(sys.argv)
# 设置应用样式
app.setStyle("Fusion")
# 创建并显示主窗口
window = WaferDetectionUI()
window.show()
sys.exit(app.exec())
if __name__ == "__main__":
main()概述 本项目聚焦于半导体制造图像中的晶圆缺陷检测。
该模型能够检测并分割多种类型的晶圆表面缺陷,例如划痕、颗粒、涂层问题、污染和烧焦区域。
数据集 该数据集包含用于实例分割的晶圆缺陷图像。
训练集3172,测试集907张,验证集452张
names:
- Center
- Donut
- Edge-Loc
- Edge-Ring
- Loc
- Scratch
nc: 6
标签可视化分析

ps:建议填写绝对路径
names:
- Center
- Donut
- Edge-Loc
- Edge-Ring
- Loc
- Scratch
nc: 6
path: D:/YOLO26//data/WaferDefects/
test: images/test
train: images/train
val: images/valid
import warnings
warnings.filterwarnings('ignore')
from ultralytics import YOLO
if __name__ == '__main__':
model = YOLO('ultralytics/cfg/models/26/yolo26.yaml')
model.train(data='data/WaferDefects.yaml',
cache=False,
imgsz=640,
epochs=200,
batch=8,
close_mosaic=10,
device='0',
optimizer='SGD', # using SGD
project='runs/train',
name='exp',
)
YOLO26 summary (fused): 122 layers, 2,376,006 parameters, 0 gradients, 5.2 GFLOPs
Class Images Instances Box(P R mAP50 mAP50-95): 100% ━━━━━━━━━━━━ 28/28 3.5it/s 8.0s
all 888 889 0.735 0.741 0.747 0.52
Center 181 181 0.702 0.74 0.773 0.591
Donut 69 69 0.653 0.551 0.499 0.338
Edge-Loc 119 119 0.759 0.874 0.845 0.549
Edge-Ring 86 86 0.778 0.779 0.787 0.48
Loc 110 111 0.651 0.672 0.676 0.496
Scratch 322 323 0.864 0.829 0.899 0.663

预测结果:

受益于人工智能的崛起,Python语言几乎以压倒性优势在众多编程语言中异军突起,成为AI时代的首选语言。在很多情况下,我们想要以图形化方式将我们的人工智能算法打包提供给用户使用,这时候选择以python为主的GUI框架就非常合适了。
PySide是Qt公司的产品,PyQt是第三方公司的产品,二者用法基本相同,不过在使用协议上却有很大差别。PySide可以在LGPL协议下使用,PyQt则在GPL协议下使用。
PySide目前常见的有两个版本:PySide2和PySide6。PySide2由C++版的Qt5开发而来.,而PySide6对应的则是C++版的Qt6。从PySide6开始,PySide的命名也会与Qt的大版本号保持一致,不会再出现类似PySide2对应Qt5这种容易混淆的情况。
pip install --upgrade pip
pip install pyside6 -i https://mirror.baidu.com/pypi/simple
基于PySide6开发GUI程序包含下面三个基本步骤:

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。