神经网络——非线性激活
目录
非线性激活
非线性激活代码举例(ReLU)
综合代码案例
非线性激活
在神经网络中,非线性激活函数是核心组件之一,它赋予了神经网络拟合复杂非线性关系的能力。如果没有非线性激活函数,无论神经网络有多少层,最终都只能实现线性映射,无法处理图像识别、自然语言处理等复杂任务。
在神经网络中,“激活函数” 的名称源于神经科学的类比,它模拟了生物神经元的 “激活” 机制。
激活函数的核心功能是:
- 引入非线性:让神经网络能拟合复杂函数(如 异或问题)
- 控制信号传递:决定哪些信息被增强(高激活)、哪些被抑制(低激活)
- 归一化输出:将输入映射到特定范围(如 Sigmoid 的 (0,1)、Tanh 的 (-1,1))
为什么需要非线性激活?
神经网络的本质是通过 “线性变换 + 激活” 的堆叠来学习数据规律:
- 线性变换(如
y = Wx + b
)只能表示直线(或高维空间中的超平面),无法拟合曲线、分类边界不规则的数据(比如 “异或问题”)。 - 激活函数通过非线性变换,让神经网络可以组合多个线性变换结果,最终形成任意复杂的非线性函数。
简单说:没有非线性激活,神经网络就退化为 “多层线性回归”,失去深度的意义。
常见的非线性激活函数
不同激活函数有不同的特性,适用场景也不同。以下是最常用的几种:
1. ReLU(Rectified Linear Unit,修正线性单元)
-
公式:
f(x) = max(0, x)
-
特性:
-
计算简单(仅判断是否为正),训练速度快;
-
解决了早期 “Sigmoid 梯度消失” 问题(正区间梯度为 1,不衰减);
-
-
缺点:
-
“死亡 ReLU 问题”:当输入长期为负时,神经元会永久 “失效”(梯度为 0,无法更新);
-
-
适用场景:几乎所有深度学习模型的默认选择(尤其是卷积神经网络 CNN)。
2. Sigmoid
-
公式:
f(x) = 1 / (1 + e^(-x))
-
特性:
-
输出范围在 (0,1) 之间,可表示 “概率”(如二分类的预测概率);
-
非线性平滑,适合早期浅层网络;
-
-
缺点:
-
梯度消失:当 x 很大或很小时,导数接近 0,深层网络中参数难以更新;
-
输出非零均值(偏向 0.5),可能影响训练稳定性;
-
-
适用场景:仅用于二分类任务的输出层(如判断 “是 / 否”)。
3. Tanh(双曲正切)
-
公式:
f(x) = (e^x - e^(-x)) / (e^x + e^(-x))
(输出范围 (-1,1)) -
特性:
-
解决了 Sigmoid 的 “非零均值” 问题(输出以 0 为中心);
-
非线性更强,适合浅层网络的隐藏层;
-
-
缺点:
-
仍存在梯度消失问题(x 绝对值大时,导数接近 0);
-
-
适用场景:循环神经网络(RNN)的早期版本,或对输出对称性有要求的场景。
4. Leaky ReLU(带泄漏的 ReLU)
-
公式:
f(x) = max(αx, x)
(α 通常取 0.01,即 x<0 时输出 0.01x) -
特性:
-
解决了 ReLU 的 “死亡神经元” 问题(负区间保留微小梯度);
-
计算简单,性能通常优于 ReLU;
-
-
缺点:α 是超参数,需要手动调整;
-
适用场景:替代 ReLU 的常用选择(尤其当训练中出现大量死亡神经元时)。
5. Swish
-
公式:
f(x) = x * sigmoid(βx)
(β 是可训练参数或固定值) -
特性:
-
平滑的非线性函数,负区间有微小输出(类似 Leaky ReLU,但更平滑);
-
在深层网络(如 ResNet)中表现常优于 ReLU;
-
-
适用场景:需要更高精度的深层模型。
6. Softmax
-
公式:
f(x_i) = e^x_i / Σ(e^x_j)
(对所有输入归一化,输出和为 1) -
特性:
-
将多分类的 “得分” 转换为概率分布(如判断图像是 “猫 / 狗 / 鸟” 的概率);
-
-
适用场景:多分类任务的输出层。
激活函数的选择原则
-
隐藏层:优先用 ReLU 或其变种(Leaky ReLU、Swish),计算快且不易梯度消失;
-
输出层:
-
二分类:Sigmoid(输出单个概率值);
-
多分类:Softmax(输出概率分布);
-
回归任务:可不用激活(直接输出连续值)或用 ReLU(确保输出非负);
-
-
特殊场景:
-
循环神经网络(RNN):避免用 ReLU(可能导致梯度爆炸),可用 Tanh 或 Sigmoid;
-
深层模型:优先用 Swish 等更平滑的函数,减少训练波动。
-
非线性激活代码举例(ReLU)
参数inplace的作用:是否直接在原内存地址上修改输入数据,还是创建新的内存空间存储输出。
inplace默认是False
import torch
from torch import nn
from torch.nn import ReLUinput = torch.tensor([[1, -0.5],[-1, 3]])
intput = torch.reshape(input, (-1, 1, 2, 2))
print(intput.shape)class MyModule(nn.Module):def __init__(self):super().__init__()self.relu = ReLU()def forward(self, input):output = self.relu(input)return outputmodule = MyModule()
output = module(input)
print("input", input)
print("output", output)
运行结果:
综合代码案例
import torchvision
from torch import nn
from torch.nn import Sigmoid
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriterdataset = torchvision.datasets.CIFAR10("../torchvision_dataset", train=False,transform=torchvision.transforms.ToTensor(),download=True)dataloader = DataLoader(dataset, batch_size=64)class MyModule(nn.Module):def __init__(self):super().__init__()self.sigmoid = Sigmoid()def forward(self, input):output = self.sigmoid(input)return outputwriter = SummaryWriter("logs_test7")
module = MyModule()
step = 1
for data in dataloader:imgs, targets = datawriter.add_images("激活前", imgs, step)output = module(imgs)writer.add_images("激活后", output, step)step += 1writer.close()