非线性激活函数
1. 为什么要使用非线性激活函数
- 对于一个网络结构来说,如果不引入非线性处理方式,那么经过多层网络的堆叠后,输入数据与输出数据之间的映射始终是线性的 (公式推导略)
- 非线性激活函数通常应用于每一个神经元末尾,或者特征提取层、特征处理层之后,赋予特征非线性性,正是这种非线性性,让特征可以通过非线性变换来表示复杂的图像或者数据!
2. 非线性激活函数的使用实例
-
加载
torchvision
中的数据,并构建一个基本的DataLoader
实例data = torchvision.datasets.CIFAR10( root="./data_torchvision", train=False, transform=torchvision.transforms.ToTensor(), download=True ) dataloader = DataLoader(data, batch_size=64)
-
创建一个简单的神经网络基本框架
Model
,非线性激活函数一般应用于每层特征提取、特征处理之后,这里在卷积层、池化层后都应用一次非线性激活函数sigmoid()
函数class Model(nn.Module): def __init__(self): super(Model, self).__init__() self.conv = nn.Conv2d( in_channels=3, out_channels=3, kernel_size=3, stride=1, ) self.pool = nn.MaxPool2d(kernel_size=3, ceil_mode=True) self.sigmoid = nn.Sigmoid() def forward(self, x): conv = self.conv(x) pool = self.pool(self.sigmoid(conv)) output = self.sigmoid(pool) return conv, pool, output
-
同样使用
tensorboard
来记录每层处理后的数据with SummaryWriter("log") as writer: step = 0 model = Model() for data in dataloader: imgs, labels = data writer.add_images("input", img_tensor=imgs, global_step=step) writer.add_images("conv+pool", model(imgs)[0], global_step=step) writer.add_images("pool", model(imgs)[1], global_step=step) writer.add_images("output", img_tensor=model(imgs)[2], global_step=step) step += 1
-
展示了原始数据
input
,input
进行卷积操作后的conv
,conv
进行非线性激活以及池化操作后的pool
,pool
最后进行一次非线性激活得到output
-
原始数据
input
-
input
卷积后的数据conv
-
conv
非线性处理后进行池化操作得到pool
-
pool
最后经过一层非线性激活后输出output
-
3.常见的非线性激活函数
-
ReLU
激活函数:nn.ReLU()
R e L U ( x ) = m a x { 0 , x } ReLU(x)=max\{0, x\} ReLU(x)=max{0,x}
-
LeakyReLU
激活函数:nn.LeakyReLU()
L e a k y R e L U ( x ) = m a x { 0.01 x , x } LeakyReLU(x)=max\{0.01x, x\} LeakyReLU(x)=max{0.01x,x}
-
Sigmoid
激活函数nn.Sigmoid()
S i g m o i d ( x ) = 1 1 + e − x Sigmoid(x) = {{1}\over{1+e^{-x}}} Sigmoid(x)=1+e−x1
-
Tanh
激活函数nn.Tanh()
T a n h ( x ) = e x − e − x e x + e − x Tanh(x) = {{e^{x}-e^{-x}}\over{e^{x}+e^{-x}}} Tanh(x)=ex+e−xex−e−x