YOLOv5嵌入SE、ECA、CBAM、CA注意力机制:从原理到消融实验的完整指南

发布时间:2026/8/27 19:31:17
YOLOv5嵌入SE、ECA、CBAM、CA注意力机制:从原理到消融实验的完整指南 每年到毕业季我都能看到一批同学在同一个地方卡住跑通了 YOLOv5 的官方代码也能训练自己的数据集但论文里需要一个“创新点”。于是大家不约而同地盯上了注意力机制然后迅速陷入三个困境——不知道选哪种、不知道代码加在哪、更不知道消融实验怎么做才不被答辩老师追问到哑口无言。这篇文章想把这条完整链路一次讲透。我会从 YOLOv5 的代码结构出发手把手带你嵌入 SE、ECA、CBAM、CA 四种注意力机制给出完整的模块代码、YAML 配置和消融实验表格模板。读完你能直接在自己的开源检测项目或本科毕业论文里复用这套方案而不是只停留在“看过原理”的层面。先给一个明确判断注意力机制确实是一个性价比很高的改进方向但真正决定你论文质量和工作量的不是“加了注意力”这件事本身而是你能不能说清楚它加在哪个位置、为什么加在这个位置、实验数据能不能支撑你的说法。1. 为什么说注意力机制是 YOLOv5 改进的高性价比方向很多同学第一次接触 YOLOv5 改进时习惯去 GitHub 上找别人改进好的版本然后发现代码动辄几千行里面混了好几种注意力模块有的还改写了训练逻辑。这种“全家桶式”项目有一个致命问题你很难在论文里解释清楚最终的效果提升到底是哪一种改进带来的。相比之下YOLOv5 官方仓库的结构非常适合做“单点小改进”。它的模型定义全部通过 YAML 文件描述新增一个模块只需要完成四件事写好模块类、注册进解析器、改 YAML、重新训练。整个过程对代码逻辑的理解要求并不高却能让你完整走一遍“提出改进—代码实现—实验验证—结果分析”的科研流程。注意力机制在这个框架里特别受欢迎是因为它不是一个“颠覆性”的结构改动而是一种“即插即用”的模块。你可以在不改变主干网络基本结构的前提下让网络更关注图像中真正有用的区域或通道这对目标检测任务的效果提升是直接且可解释的。另外一个现实原因是本科毕设的时间通常只有三到四个月其中还要扣除写论文、准备答辩、找工作的时间。你真的没有精力去重新实现一篇顶会论文的完整检测器。在 YOLOv5 基础上嵌入注意力机制训练时间可控实验设计清晰论文的创新点也能站得住脚这是一个性价比很高的选择。2. 四种注意力机制的核心原理与适用场景在写代码之前我强烈建议你先花一小时把四种注意力机制的核心逻辑搞清楚。原因很简单答辩的时候老师大概率不会让你现场写代码但一定会问“你的注意力机制是怎么发挥作用的”。如果你只能答出“它可以让模型更关注重要特征”这个回答是不够的。2.1 SE通道注意力机制的经典代表SESqueeze-and-Excitation是通道注意力里最经典的结构它的核心思想是先压缩再激励。具体来说网络会把每个通道的特征图压缩成一个全局描述符Squeeze然后通过两个全连接层学习每个通道的权重Excitation最后把权重乘回原来的特征图上。它的优点是结构简单、实现容易、对绝大多数 CNN 模型都有不错的提升效果。缺点是它只关注通道之间的关系完全没有利用空间信息。如果你处理的图像中目标尺度变化很大SE 的改善幅度可能会比较有限。2.2 ECA轻量化的高效通道注意力ECAEfficient Channel Attention可以理解为 SE 的轻量化改进。SE 里用两个全连接层来建模通道关系ECA 则认为全连接层是不必要的直接通过一维卷积来捕捉局部通道之间的依赖。这种设计的直接好处是参数量大幅减少。在 YOLOv5 这种本身就有大量卷积操作的模型里ECA 可以在几乎不增加计算量的前提下提升检测精度。如果你在算力有限、或者需要保证推理速度的场景下做改进ECA 是一个很务实的选择。2.3 CBAM通道加空间的联合注意力CBAMConvolutional Block Attention Module的工作方式是串行地应用两个注意力模块先做通道注意力再做空间注意力。通道注意力的部分和 SE 相似但略有区别它同时使用了平均池化和最大池化空间注意力则是在通道维度上对特征图做平均池化和最大池化再通过卷积生成空间权重。和 SE、ECA 相比CBAM 多了一个空间维度上的建模能力因此在目标定位精度上通常表现更好。代价是结构相对复杂计算量也会高一些。如果你的检测任务对目标位置的准确性要求高CBAM 值得优先考虑。2.4 CA具备位置感知能力的坐标注意力CACoordinate Attention是这里四种机制里最晚提出的一个。它把位置信息嵌入到通道注意力中通过将特征图分解为水平方向和垂直方向的两个一维特征编码让注意力模块既能感知通道信息又能感知方向和位置信息。这个特性对目标检测特别有意义。比如你想检测 PCB 板上的微小缺陷缺陷在图像中的位置和方向信息往往是判断其类型的重要依据CA 就能给模型提供这类信息。它的参数增加幅度不算大但实现复杂度比 ECA 要高一档代码里需要同时处理水平池化和垂直池化两条分支。2.5 四种机制怎么选注意力机制核心思路主要优势适用场景SE通道压缩-激励结构简单实现容易对计算量敏感希望快速出效果ECA一维卷积捕捉通道依赖参数量极小推理快算力有限追求轻量化改进CBAM通道空间串行注意力同时利用通道与空间信息对定位精度要求高的任务CA嵌入位置信息的通道注意力兼顾方向与位置感知小目标检测、细粒度缺陷检测这四种机制没有绝对的好坏关键看你的任务场景。我个人的建议是如果你的数据集比较常规先试 ECA因为它改动最小、最容易出稳定效果如果检测目标是小物体优先实验 CBAM 或 CA。3. 环境准备与 YOLOv5 代码结构梳理因为 YOLOv5 的版本迭代比较频繁不同小版本的代码细节会有差异以下环境和文件路径以主流版本为例具体版本请以你实际拉取的代码为准。本文的修改思路是通用的换到相近版本同样适用。3.1 基础环境清单# 建议使用 Python 3.8 或 3.9 # PyTorch 建议使用 1.8 及以上版本CUDA 版本根据自己的显卡驱动选择 conda create -n yolov5 python3.8 -y conda activate yolov5 pip install torch torchvision pip install -r requirements.txt这里有一个容易踩的坑YOLOv5 的requirements.txt会安装特定版本的依赖如果你原本环境里已经装过其他深度学习框架建议直接用 conda 新建一个干净的虚拟环境避免包冲突。3.2 YOLOv5 中与模型定义有关的三个文件在你正式开始改代码前先找到这三个文件后面所有操作都围绕它们展开models/common.py存放模型中的基础组件比如卷积、C3、SPPF 等。我们要新增的注意力模块也写在这里。models/yolo.py负责读取 YAML 配置将字符串形式的模块名映射为实际的类然后构建整个 DetectionModel。models/yolov5s.yaml模型结构配置文件决定网络有多少层、每层用什么模块、通道数是多少。理解这三者之间的关系你才能在出 bug 时快速定位问题。很多同学直接在 common.py 里加了类就跑去训练结果报错说找不到某个模块就是因为漏改了yolo.py中的解析字典。3.3 核心流程让 YOLOv5 认识一个新模块往 YOLOv5 里加任何新结构都遵循下面这个三步流程在models/common.py中定义新的模块类继承nn.Module。在models/yolo.py的parse_model函数中找到类似parse_model里的模块分发字典把你定义的类名加进去。在models/yolov5s.yaml或你自定义的 YAML 文件的backbone或head部分引用了这个模块名YOLOv5 启动时会自动解析并构建网络。这套流程是 YOLOv5 结构改进的核心。你可以把注意力模块看作一个“积木块”只要这个积木块的接口规范输入输出都是四维特征图它就能被安插在模型的不同位置。4. SE 注意力机制嵌入 YOLOv5 完整实现4.1 在 common.py 中新增 SE 模块代码# 文件路径models/common.py将以下代码追加到文件末尾 import torch import torch.nn as nn class SE(nn.Module): Squeeze-and-Excitation 通道注意力模块 def __init__(self, c1, c2, r16): super(SE, self).__init__() self.avg_pool nn.AdaptiveAvgPool2d(1) self.fc nn.Sequential( nn.Linear(c2, c2 // r, biasFalse), nn.ReLU(inplaceTrue), nn.Linear(c2 // r, c2, biasFalse), nn.Sigmoid() ) def forward(self, x): b, c, _, _ x.size() y self.avg_pool(x).view(b, c) y self.fc(y).view(b, c, 1, 1) return x * y这里有一个细节需要解释c2 // r在通道数很小的时候可能出现整数除法后为 0 的情况比如通道数为 16压缩率设为 16中间维度就是 1。这不会报错但会过度压缩信息。实际使用时可以根据情况把r调小或者把c2 // r改成max(8, c2 // r)。4.2 在 yolo.py 中注册 SE 模块# 文件路径models/yolo.py # 在 parse_model 函数中找到类似下面的代码块在字典里添加 SE: SE if m in { Conv, GhostConv, DWConv, GhostBottleneck, SPP, SPPF, C3, C2f, C3Ghost, SE, # 这里加上 SE Focus, Bottleneck, BottleneckCSP, # 其他模块省略 ... }这段代码的本质是告诉 YOLOv5 解析器当 YAML 中出现名为SE的模块时实例化的是我们在 common.py 中定义的 SE 类。4.3 修改 YAML 配置最简单的接入方式是把 SE 作为单独的一层插入到 Backbone 的 SPPF 之后。# 文件路径models/yolov5s.yaml # 以下为 backbone 部分的末尾示例只展示关键行 backbone: # ... 前面的层省略 - [-1, 1, Conv, [1024, 3, 1]] # P5 之前的最后一个卷积 - [-1, 1, SPPF, [1024, 5]] # SPPF 特征提取 - [-1, 1, SE, [1024, 16]] # 新增 SE 注意力层 head: # ... head 部分保持原样注意 YAML 中模块参数的写法[1024, 16]对应 SE 类的c1和r两个参数而c2会在解析时自动取上一层的输出通道数。在parse_model的实现里c2通常会从参数列表第一个值读取而c1会从上一层的输出通道自动推导所以这里的 1024 既指定了 SE 的输出通道也决定了全连接层的输入维度。4.4 验证模型是否能正常构建python models/yolo.py --cfg models/yolov5s.yaml如果输出中能看到 SE 层并且没有报错说明 SE 模块已经成功嵌入。此时可以先用一张测试图走一次前向推理再开始训练。5. ECA 注意力机制嵌入 YOLOv55.1 在 common.py 中新增 ECA 模块代码# 文件路径models/common.py继续追加 class ECA(nn.Module): Efficient Channel Attention 高效通道注意力模块 def __init__(self, c1, c2, k_size3): super(ECA, self).__init__() self.avg_pool nn.AdaptiveAvgPool2d(1) self.conv nn.Conv1d(1, 1, kernel_sizek_size, padding(k_size - 1) // 2, biasFalse) self.sigmoid nn.Sigmoid() def forward(self, x): y self.avg_pool(x) y y.squeeze(-1).transpose(-1, -2) y self.conv(y) y y.transpose(-1, -2).unsqueeze(-1) y self.sigmoid(y) return x * y.expand_as(x)ECA 和 SE 的代码差异不大但原理有本质区别SE 把通道压缩成一个向量后再通过全连接层恢复ECA 则直接对压缩后的向量做一维卷积。k_size控制了参与每个通道权重计算的相邻通道数量默认 3 在大多数任务上表现不错。5.2 在 yolo.py 中注册 ECA 模块# 文件路径models/yolo.py # 在 parse_model 的分发字典中加上 ECA: ECA5.3 修改 YAML 配置# 文件路径models/yolov5s.yaml # 在 SPPF 之后新增 ECA 层 - [-1, 1, ECA, [1024, 3]]这里[1024, 3]表示输出通道数为 1024一维卷积核大小为 3。5.4 验证方法和 SE 相同运行python models/yolo.py --cfg models/yolov5s.yaml确认模型正常构建。6. CBAM 注意力机制嵌入 YOLOv56.1 在 common.py 中新增 CBAM 模块代码CBAM 分为两部分先定义通道注意力和空间注意力两个子模块再组合成最终模块。# 文件路径models/common.py继续追加 class ChannelAttention(nn.Module): CBAM 中的通道注意力子模块 def __init__(self, in_planes, ratio16): super(ChannelAttention, self).__init__() self.avg_pool nn.AdaptiveAvgPool2d(1) self.max_pool nn.AdaptiveMaxPool2d(1) self.fc1 nn.Conv2d(in_planes, in_planes // ratio, 1, biasFalse) self.relu1 nn.ReLU() self.fc2 nn.Conv2d(in_planes // ratio, in_planes, 1, biasFalse) self.sigmoid nn.Sigmoid() def forward(self, x): avg_out self.fc2(self.relu1(self.fc1(self.avg_pool(x)))) max_out self.fc2(self.relu1(self.fc1(self.max_pool(x)))) out avg_out max_out return self.sigmoid(out) class SpatialAttention(nn.Module): CBAM 中的空间注意力子模块 def __init__(self, kernel_size7): super(SpatialAttention, self).__init__() assert kernel_size in (3, 7), kernel size must be 3 or 7 padding 3 if kernel_size 7 else 1 self.conv1 nn.Conv2d(2, 1, kernel_size, paddingpadding, biasFalse) self.sigmoid nn.Sigmoid() def forward(self, x): avg_out torch.mean(x, dim1, keepdimTrue) max_out, _ torch.max(x, dim1, keepdimTrue) x_cat torch.cat([avg_out, max_out], dim1) x_out self.conv1(x_cat) return self.sigmoid(x_out) class CBAM(nn.Module): Convolutional Block Attention Module def __init__(self, c1, c2, kernel_size7): super(CBAM, self).__init__() self.channel_attention ChannelAttention(c2) self.spatial_attention SpatialAttention(kernel_size) def forward(self, x): x self.channel_attention(x) * x x self.spatial_attention(x) * x return xCBAM 的 forward 逻辑很清晰特征图先经过通道注意力再经过空间注意力两者是串行关系。需要注意这里用了nn.Conv2d而不是nn.Linear来实现全连接功能一是因为输入本来就是四维特征图二是在代码层面更简洁不需要 reshape 操作。6.2 在 yolo.py 中注册 CBAM 模块# 文件路径models/yolo.py # 在 parse_model 的分发字典中同时添加三个类名 # ChannelAttention: ChannelAttention, SpatialAttention: SpatialAttention, CBAM: CBAM6.3 修改 YAML 配置# 文件路径models/yolov5s.yaml - [-1, 1, CBAM, [1024, 7]]6.4 验证方法因为 CBAM 定义了三个类验证时建议直接打印模型结构看 CBAM 层是否正常展开为 ChannelAttention 和 SpatialAttention 两个子模块。7. CA 注意力机制嵌入 YOLOv57.1 在 common.py 中新增 CA 模块代码CA 模块的代码量比前三个稍大因为它需要同时处理水平方向和垂直方向的两条池化分支。# 文件路径models/common.py继续追加 class h_swish(nn.Module): h-swish 激活函数 def forward(self, x): return x * torch.relu6(x 3) / 6 class CoordAtt(nn.Module): Coordinate Attention 坐标注意力模块 def __init__(self, inp, oup, reduction32): super(CoordAtt, self).__init__() self.pool_h nn.AdaptiveAvgPool2d((None, 1)) self.pool_w nn.AdaptiveAvgPool2d((1, None)) mip max(8, inp // reduction) self.conv1 nn.Conv2d(inp, mip, kernel_size1, stride1, padding0) self.bn1 nn.BatchNorm2d(mip) self.act h_swish() self.conv_h nn.Conv2d(mip, oup, kernel_size1, stride1, padding0) self.conv_w nn.Conv2d(mip, oup, kernel_size1, stride1, padding0) def forward(self, x): identity x n, c, h, w x.size() x_h self.pool_h(x) x_w self.pool_w(x).permute(0, 1, 3, 2) y torch.cat([x_h, x_w], dim2) y self.conv1(y) y self.bn1(y) y self.act(y) x_h, x_w torch.split(y, [h, w], dim2) x_w x_w.permute(0, 1, 3, 2) a_h self.conv_h(x_h).sigmoid() a_w self.conv_w(x_w).sigmoid() out identity * a_w * a_h return out使用时你可以直接定义别名CA CoordAtt这样 YAML 里的模块名可以写成CA更简洁也更好记。CA 的关键在于pool_h和pool_w这两个池化操作前者将特征图压缩成(C, H, 1)的形状后者压缩成(C, 1, W)的形状。然后两条分支被拼接起来过卷积再各自分离成方向权重最后乘回原特征图。这个设计让网络能够感知每个像素在水平和垂直方向上的位置关系。7.2 在 yolo.py 中注册 CA 模块# 文件路径models/yolo.py # 在 parse_model 的分发字典中加上 CA: CoordAtt如果你希望 YAML 里同时识别CA和CoordAtt两种写法就把两个键都加上。下面的验证命令等价于上面的 SE 验证命令输出结构里应能看到 CoordAtt 层。7.3 修改 YAML 配置# 文件路径models/yolov5s.yaml - [-1, 1, CA, [1024, 32]]这里[1024, 32]表示输出通道数 1024压缩率 reduction 为 32。压缩率越大中间通道数越少计算量越低但信息瓶颈也可能更明显。实际应用中可以从 32 开始尝试。8. 消融实验完整设计与结果表格制作消融实验是论文里证明“我的改进有效”的核心证据。很多同学在网上复制了代码训练完发现提升不大于是不知道怎么往下写。这里我给你一个可靠的实验设计方法。8.1 实验组设计标准做法是五个实验组Baseline原始的 YOLOv5不加任何注意力机制。YOLOv5 SE只在 SPPF 后加入 SE。YOLOv5 ECA只在 SPPF 后加入 ECA。YOLOv5 CBAM只在 SPPF 后加入 CBAM。YOLOv5 CA只在 SPPF 后加入 CA。这样设计的逻辑是控制变量。五个实验除了注意力模块不同其他所有训练超参数、数据集、预处理方式完全保持一致最终对比才有说服力。还有一种常见做法是“注意力模块放在不同位置”的对比实验。比如把 CBAM 分别放在 Backbone、Neck 和 SPPF 后观察哪个位置效果最好。这种实验更深入但训练次数也会成倍增加。本科毕设建议先做完整对比时间充裕再加位置对比。8.2 关键超参数必须锁定做消融实验最容易犯的错误是每个实验都习惯性微调了学习率、批量大小、训练轮数。这会让你的实验结果毫无说服力因为老师无法判断提升是来自注意力机制还是来自你调参。以下参数必须保证所有实验组完全一致# 训练时必须保持一致的超参数不要随意改动 epochs: 100 batch-size: 16 imgsz: 640 optimizer: SGD lr0: 0.01 mosaic: 1.0如果你需要在不同实验组之间切换 YAML 模型配置最简单的方式是备份四个不同的 YAML 文件比如yolov5s_se.yaml、yolov5s_eca.yaml等训练时通过--cfg参数指定而--data、--hyp等参数保持原样。8.3 结果表格模板下面是一个可以直接复制的实验结果表格模板。注意表格里的数据是示例真实数据必须以你自己的实验为准不建议照抄。论文里数据造假是严重的学术不端行为这个底线不能碰。模型mAP0.5mAP0.5:0.95参数量推理耗时(ms)YOLOv5s Baseline78.252.67.02M6.4YOLOv5s SE79.153.87.25M6.7YOLOv5s ECA79.554.27.03M6.5YOLOv5s CBAM80.355.17.31M6.9YOLOv5s CA81.055.97.38M7.1注意观察表格里的规律每个注意力模块都会带来参数量和推理耗时的增加这是正常现象。你论文里的分析不能只说“mAP 提升了”还要解释“这种提升是在什么代价下得到的”。如果某个模块提升精度 0.5 个点但推理耗时增加了 20%在实时检测场景下这个改进值不值得你心里要有数。8.4 实验结论怎么写最稳妥一个稳妥的结论结构是先指出综合效果最好的模型再解释为什么这个注意力机制适合你的任务最后补一句“虽然参数量略有增加但在可接受范围内换来了 mAP 的提升”。比如如果你的任务是 PCB 缺陷检测可以这样写“由表 x 可知在 YOLOv5s 基础上引入 CA 注意力机制后mAP0.5 提升了 2.8 个百分点验证了位置信息对微小缺陷检测的有效性。ECA 虽然参数量增加最少但精度提升幅度相对有限综合考虑精度与实时性本文最终选用 CA 作为改进模块。”这种写法有理有据答辩时也能应付追问。9. 常见问题与排查思路我根据同学实际跑代码时的高频报错整理了下面这份排查表建议收藏备用。问题现象可能原因排查方式解决方案训练时报错KeyError: SEcommon.py 中定义了类但 yolo.py 的分发字典没加检查 yolo.py 中 parse_model 是否包含对应键在分发字典中添加模块类名模型构建成功但 loss 不下降注意力模块放在了不合适的层或参数配置错误打印模型结构检查模块输入输出维度调整注意力模块位置合理设置通道数显存溢出 OOM注意力模块增加了显存占用查看 nvidia-smi 监控显存降低 batch-size 或图像尺寸训练结果 Baseline 和加注意力没区别注意力模块加在位置不对或数据集太小检查 YAML 是否真的引用了新模块将注意力模块放在 SPPF 之后或 C3 内部验证时模型权重加载失败模型结构改了但权重文件还是旧的重新训练或使用--weights 从空权重开始修改模型后不要直接加载预训练权重有一个让人头疼的问题特别值得一提YOLOv5 会自动下载 COCO 预训练权重但你在下载超时或网络受限的环境里会遇到权重文件加载失败。解决办法是提前下载好权重文件放到weights/目录训练时通过--weights weights/yolov5s.pt指定然后在 YAML 改动较小的情况下预训练权重的迁移效果通常会优于从头训练。10. 毕业论文写作与工程实践建议10.1 关于创新点的表述本科毕业论文里最常见的创新点写法是“本文在 YOLOv5 的基础上引入了 XX 注意力机制有效增强了模型对 target 特征的关注能力提升了检测精度。”这句话不够有说服力。更好的写法是结合你的任务背景去描述。比如“针对 PCB 缺陷检测中微小缺陷特征不明显的问题本文在 YOLOv5 Backbone 的 SPPF 层后引入 CA 坐标注意力机制通过将位置信息嵌入通道注意力使模型在关注缺陷通道的同时保留缺陷的空间位置特征实验结果表明 mAP0.5 提升了 2.8 个百分点。”这样既有问题导向又有技术路线还有数据支撑。10.2 训练与结果记录建议从你开始做实验的第一天起就要养成记录实验日志的习惯。每跑完一个实验至少记录以下几点实验名称和对应 YAML 配置文件的名字。训练命令完整复制不要靠记忆。训练日志文件路径。验证集上的 key 指标。训练时间、显存占用、单张图片推理速度。这些信息会直接写进你的毕业论文的“实验结果与分析”章节也会在你后期写论文时节省大量回看实验的时间。10.3 工程上的安全与规范建议如果你是在实验室服务器上训练记得使用独立的 conda 环境不要直接改系统级的 Python 环境。训练前先跑一个极小的 epoch 确认代码能跑通再提交完整训练任务。修改 YAML 或 common.py 之前建议先备份原文件避免一路改下来出了问题无法回退。我也强烈建议用 Git 管理你的实验代码。四个注意力机制的改进可以拆成四个 commit对应四个 YAML 文件这样你随时可以切换回某个版本的代码重新训练或复现结果。10.4 和导师沟通的节奏做改进实验之前先给导师看你的实验设计包括选哪几种注意力机制、加在哪个位置、做几组消融实验。导师对这个方案认可后你再投入时间去训练能避免白做几周实验。尤其是如果你们实验室算力有限先用小的数据集或少的 epoch 快速验证模块可以跑通再用完整数据训练最终模型这是很实用的做法。11. 总结与后续进阶方向这里有一个容易被忽略但很关键的建议先把四种注意力机制全部在 YOLOv5s 上跑通哪怕只用小数据集、30 个 epoch确认模型构建、训练、验证的完整流程没有问题再决定最终用哪一种做深度实验。从当前这个点往后如果你想继续深入可以关注几个方向第一把注意力机制换成更轻量的变体或者同时嵌入多种注意力机制形成混合注意力模块第二研究注意力机制在不同特征层上的分配策略而不是只加在 SPPF 后第三将改进后的模型迁移到其他数据集上做泛化能力验证。每一步都会让你的工作更有深度也更有论文可写的内容。不过当下最重要的事情只有一件打开你的 YOLOv5 代码把 SE 模块加上跑通一个最小的训练流程再逐步扩展到其他三种机制。代码和实验结果都在你手里论文的底气自然就有了。