秋招面试专栏推荐 :深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转
💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡
专栏目录: 《YOLOv5入门 + 改进涨点》专栏介绍 & 专栏目录 |目前已有50+篇内容,内含各种Head检测头、损失函数Loss、Backbone、Neck、NMS等创新点改进
本文给大家介绍的是常见的十余种激活函数替换,因为每种激活函数都有一定的优势,因此我们可以在实验中尝试不同的激活函数进行实验。文章在介绍激活函数的主要原理后,将手把手教学如何进行模块的代码添加和修改,并将修改后的完整代码放在文章的最后,方便大家一键运行,小白也可轻松上手实践。以帮助您更好地学习深度学习目标检测YOLO系列的挑战。
目录
1. YOLO训练中常见激活函数介绍
激活函数是神经网络中的关键组件,它们引入非线性特性,使模型能够学习复杂的模式。以下是几个常用的激活函数的优缺点及公式,以表格形式呈现:
激活函数 | 公式 | 优点 | 缺点 |
---|---|---|---|
SiLU | 平滑非线性;在某些任务上比ReLU效果更好 | 计算复杂度稍高 | |
ReLU | 计算简单;收敛速度快 | 神经元死亡(Dead Neurons)问题 | |
LeakyReLU | 缓解神经元死亡问题 | 输出不以零为中心 | |
Hardswish | 近似Swish但计算更高效 | 相对于ReLU计算复杂度稍高 | |
Mish | 平滑非线性;在某些任务上优于ReLU和Swish | 计算复杂度高;训练时间较长 | |
ELU | 缓解神经元死亡问题;负值区域输出 | 计算复杂度稍高;α需要调优 | |
GELU | (Φ(x)是标准正态分布的累积分布函数) | 理论上优于ReLU;平滑非线性 | 计算复杂度高;训练时间较长 |
SELU | 自动标准化输出;在深层网络中效果较好 | 计算复杂度高;对参数和网络架构有一定要求 | |
RReLU | (r为在某区间内随机采样的值) | 防止过拟合;在训练期间有正则化效果 | 在推理阶段需确定r的值;计算复杂度稍高 |
PReLU | 缓解神经元死亡问题;参数可训练 | 增加了模型的参数数量 |
详细说明:
-
SiLU (Swish-1):
-
优点: 平滑非线性特性,在某些任务上优于ReLU。
-
缺点: 计算复杂度比ReLU稍高。
-
公式:
-
-
ReLU (Rectified Linear Unit):
-
优点: 计算简单,收敛速度快。
-
缺点: 可能导致神经元死亡,即在训练过程中某些神经元永远不会被激活。
-
公式:
-
-
LeakyReLU:
-
优点: 缓解了ReLU的神经元死亡问题。
-
缺点: 输出不以零为中心,可能会影响梯度的均衡。
-
公式:
-
-
Hardswish:
-
优点: 近似Swish但计算更高效。
-
缺点: 相对于ReLU,计算复杂度稍高。
-
公式:
-
-
Mish:
-
优点: 平滑非线性特性,在某些任务上优于ReLU和Swish。
-
缺点: 计算复杂度高,训练时间较长。
-
公式:
-
-
ELU (Exponential Linear Unit):
-
优点: 缓解ReLU的神经元死亡问题,负值区域有输出。
-
缺点: 计算复杂度稍高,参数α需要调优。
-
公式:
-
-
GELU (Gaussian Error Linear Unit):
-
优点: 理论上优于ReLU,平滑非线性。
-
缺点: 计算复杂度高,训练时间较长。
-
公式: ,其中Φ(x)是标准正态分布的累积分布函数。
-
-
SELU (Scaled Exponential Linear Unit):
-
优点: 自动标准化输出,在深层网络中效果较好。
-
缺点: 计算复杂度高,对参数和网络架构有一定要求。
-
公式:
-
-
RReLU (Randomized Leaky ReLU):
-
优点: 防止过拟合,在训练期间有正则化效果。
-
缺点: 在推理阶段需确定r的值,计算复杂度稍高。
-
公式: ,其中r为在某区间内随机采样的值。
-
-
PReLU (Parametric ReLU):
-
优点: 缓解ReLU的神经元死亡问题,参数可训练。
-
缺点: 增加了模型的参数数量。
-
公式: ,其中α是可训练的参数。
-
下面这些激活函数也都是大家耳熟能详的
激活函数 | 公式 | 优点 | 缺点 |
---|---|---|---|
Sigmoid | - 平滑,输出范围在 (0,1) - 适合处理概率问题 | - 梯度消失问题 - 输出不是零中心 - 计算开销大 | |
Tanh | - 输出零中心 - 梯度比Sigmoid更大 | - 梯度消失问题 - 计算开销大 | |
ReLU (Rectified Linear Unit) | - 简单且高效 - 收敛速度快 | - 梯度爆炸问题 - Dying ReLU问题(神经元死亡) | |
Leaky ReLU | - 缓解Dying ReLU问题 - 保留ReLU的优点 | - 仍然可能发生梯度爆炸 | |
Parametric ReLU (PReLU) | - 通过学习参数α来改进Leaky ReLU - 更加灵活 | - 计算开销稍高 | |
ELU (Exponential Linear Unit) | - 缓解梯度消失问题 - 更好的鲁棒性 | - 计算更复杂 - 需要调整参数α | |
Swish | - 训练效果优于ReLU - 平滑梯度 | - 计算复杂 - 需要额外的计算资源 | |
Softplus | - 平滑ReLU - 没有Dying ReLU问题 | - 梯度消失问题 - 计算开销大 | |
GELU (Gaussian Error Linear Unit) | 其中 Phi(x)是标准正态分布的累积分布函数 | - 在某些任务上表现更好 - 平滑梯度 | - 计算复杂 - 需要额外的计算资源 |
Maxout | - 更强的表示能力 - 解决Dying ReLU问题 | - 参数多,计算开销大 - 容易过拟合 |
2 .修改YOLOv5的激活函数
YOLOv5中默认是的激活函数是Silu激活函数
修改激活函数的只有一个步骤,很简单。因为YOLOv5已经给我们封装好了
详细的代码如下
class Conv(nn.Module):
"""Standard convolution with args(ch_in, ch_out, kernel, stride, padding, groups, dilation, activation)."""
default_act = nn.SiLU() # default activation
def __init__(self, c1, c2, k=1, s=1, p=None, g=1, d=1, act=True):
"""Initialize Conv layer with given arguments including activation."""
super().__init__()
self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p, d), groups=g, dilation=d, bias=False)
self.bn = nn.BatchNorm2d(c2)
self.act = self.default_act if act is True else act if isinstance(act, nn.Module) else nn.Identity()
def forward(self, x):
"""Apply convolution, batch normalization and activation to input tensor."""
return self.act(self.bn(self.conv(x)))
def forward_fuse(self, x):
"""Perform transposed convolution of 2D data."""
return self.act(self.conv(x))
阅读上面的代码可以知道,我们的只要找到default_act即可,阅读完整代码发现,在task.py中可以给default_act进行传参。
def parse_model(d, ch):
"""Parses a YOLOv5 model from a dict `d`, configuring layers based on input channels `ch` and model architecture."""
LOGGER.info(f"\n{'':>3}{'from':>18}{'n':>3}{'params':>10} {'module':<40}{'arguments':<30}")
anchors, nc, gd, gw, act, ch_mul = (
d["anchors"],
d["nc"],
d["depth_multiple"],
d["width_multiple"],
d.get("activation"),
d.get("channel_multiple"),
)
if act:
Conv.default_act = eval(act) # redefine default activation, i.e. Conv.default_act = nn.SiLU()
LOGGER.info(f"{colorstr('activation:')} {act}") # print
同时这里也写明了,在yaml文件重新定义act即可
所以我们应该在yaml文件中新增 像 activation = nn.SiLU 即可
activation = nn.SiLU()
activation = nn.ReLU()
activation = nn.LeakyReLU()
activation = nn.Hardswish()
activation = nn.Mish()
activation = nn.ELU()
activation = nn.GELU()
activation = nn.SELU()
activation = nn.RReLU()
activation = nn.PReLU()
完整的yaml文件
# Ultralytics YOLOv5 🚀, AGPL-3.0 license
# Parameters
nc: 80 # number of classes
depth_multiple: 1.0 # model depth multiple
width_multiple: 1.0 # layer channel multiple
anchors:
- [10, 13, 16, 30, 33, 23] # P3/8
- [30, 61, 62, 45, 59, 119] # P4/16
- [116, 90, 156, 198, 373, 326] # P5/32
activation: nn.SiLU() # 选择你需要的进行反注释,只留下一个激活函数即可
# activation: nn.ReLU()
# activation: nn.LeakyReLU()
# activation: nn.Hardswish()
# activation: nn.Mish()
# activation: nn.ELU()
# activation: nn.GELU()
# activation: nn.SELU()
# activation: nn.RReLU()
# activation: nn.PReLU()
# YOLOv5 v6.0 backbone
backbone:
# [from, number, module, args]
[
[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2
[-1, 1, Conv, [128, 3, 2]], # 1-P2/4
[-1, 3, C3, [128]],
[-1, 1, Conv, [256, 3, 2]], # 3-P3/8
[-1, 6, C3, [256]],
[-1, 1, Conv, [512, 3, 2]], # 5-P4/16
[-1, 9, C3, [512]],
[-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
[-1, 3, C3, [1024]],
[-1, 1, SPPF, [1024, 5]], # 9
]
# YOLOv5 v6.0 head
head: [
[-1, 1, Conv, [512, 1, 1]],
[-1, 1, nn.Upsample, [None, 2, "nearest"]],
[[-1, 6], 1, Concat, [1]], # cat backbone P4
[-1, 3, C3, [512, False]], # 13
[-1, 1, Conv, [256, 1, 1]],
[-1, 1, nn.Upsample, [None, 2, "nearest"]],
[[-1, 4], 1, Concat, [1]], # cat backbone P3
[-1, 3, C3, [256, False]], # 17 (P3/8-small)
[-1, 1, Conv, [256, 3, 2]],
[[-1, 14], 1, Concat, [1]], # cat head P4
[-1, 3, C3, [512, False]], # 20 (P4/16-medium)
[-1, 1, Conv, [512, 3, 2]],
[[-1, 10], 1, Concat, [1]], # cat head P5
[-1, 3, C3, [1024, False]], # 23 (P5/32-large)
[[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
]
🚀运行程序,如果出现下面的内容则说明添加成功🚀
from n params module arguments
activation: nn.ReLU()
0 -1 1 7040 models.common.Conv [3, 64, 6, 2, 2]
1 -1 1 73984 models.common.Conv [64, 128, 3, 2]
2 -1 3 156928 models.common.C3 [128, 128, 3]
3 -1 1 295424 models.common.Conv [128, 256, 3, 2]
4 -1 6 1118208 models.common.C3 [256, 256, 6]
5 -1 1 1180672 models.common.Conv [256, 512, 3, 2]
6 -1 9 6433792 models.common.C3 [512, 512, 9]
7 -1 1 4720640 models.common.Conv [512, 1024, 3, 2]
8 -1 3 9971712 models.common.C3 [1024, 1024, 3]
9 -1 1 2624512 models.common.SPPF [1024, 1024, 5]
10 -1 1 525312 models.common.Conv [1024, 512, 1, 1]
11 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest']
12 [-1, 6] 1 0 models.common.Concat [1]
13 -1 3 2757632 models.common.C3 [1024, 512, 3, False]
14 -1 1 131584 models.common.Conv [512, 256, 1, 1]
15 -1 1 0 torch.nn.modules.upsampling.Upsample [None, 2, 'nearest']
16 [-1, 4] 1 0 models.common.Concat [1]
17 -1 3 690688 models.common.C3 [512, 256, 3, False]
18 -1 1 590336 models.common.Conv [256, 256, 3, 2]
19 [-1, 14] 1 0 models.common.Concat [1]
20 -1 3 2495488 models.common.C3 [512, 512, 3, False]
21 -1 1 2360320 models.common.Conv [512, 512, 3, 2]
22 [-1, 10] 1 0 models.common.Concat [1]
23 -1 3 9971712 models.common.C3 [1024, 1024, 3, False]
24 [17, 20, 23] 1 457725 Detect [80, [[10, 13, 16, 30, 33, 23], [30, 61, 62, 45, 59, 119], [116, 90, 156, 198, 373, 326]], [256, 512, 1024]]
YOLOv5_act summary: 368 layers, 46563709 parameters, 46563709 gradients, 109.6 GFLOPs
3. 完整代码分享
https://pan.baidu.com/s/1Ifv9xJ-6dv6SAFQN5pH2cg?pwd=uyvh
提取码: uyvh