Pytorch 中的 非线性 与 线性层

1. Non-linear activations

Non-linear activations(非线性激活函数)是神经网络中一种用于引入非线性关系的函数。在神经网络中,我们通常使用激活函数对输入数据进行非线性转换,以增加网络的表达能力和学习复杂函数的能力。

 主要作用

  1. 引入非线性关系:线性激活函数只能学习线性关系,而现实世界中的数据往往具有复杂的非线性关系。非线性激活函数通过在网络中引入非线性变换,可以使网络具备更强的表达能力,从而可以学习和表示更为复杂的数据模式和关系。

  2. 增强网络的表达能力:非线性激活函数可以通过引入非线性变换,扩大网络的拟合能力。它们可以允许网络对输入数据进行非线性映射,从而更好地适应复杂的数据分布和非线性模式。

  3. 解决梯度消失问题:在深度神经网络中,使用线性激活函数可能会导致梯度消失问题,即在反向传播中梯度趋近于0,导致网络难以更新参数。使用非线性激活函数可以打破梯度消失问题,使得梯度能够传递到较浅层的网络层,从而更好地进行参数更新和优化。

  4. 增加稳定性和收敛速度:非线性激活函数的使用可以增加网络的稳定性和收敛速度。它们能够引入非线性特性,帮助网络更好地适应训练数据,并且在训练过程中提供更多的梯度信息,加速模型的收敛过程

 2. 常见的非线性激活函数

 1. ReLU 函数

class torch.nn.ReLU(inplace=False)

inplace=False  这个参数代表:是否覆盖原输出的数据, 一般使用默认的即可!!!

eg:

inplace=True 时:

input = -3

output = ReLU(input, inplace=True)

inuput = 0

output = 0

inplace=False 时:

input = -3

output = ReLU(input, inplace=False)

inuput = -3

output = 0

公式:

                                        ReLU(x)=(x)+=max(0,x)

  图像:

 特性:

  1. 简单且易于计算:ReLU函数只需判断输入是否大于零并返回对应的值,计算量较小,求导也很简单。

  2. 收敛快速:相比于其他激活函数,ReLU函数在训练神经网络时具有较快的收敛速度,因为它不会引起梯度消失的问题

  3. 解决梯度消失问题:当输入小于等于零时,ReLU函数的导数为零,这导致了一些神经元的输出变成了零,使得网络具有稀疏性,能够减少网络的参数量,并且能够有效地解决梯度消失问题。

  4. 适用性广泛:ReLU函数通常在卷积神经网络(CNN)中使用,因为它对于图像等具有大量稀疏输入的数据集效果较好

然而,ReLU函数也存在一些缺点,例如存在神经元死亡问题,即某些神经元在训练过程中始终为零,无法恢复。针对这个问题,目前已经提出了一些改进的版本,如Leaky ReLU、Parametric ReLU和Exponential ReLU等。

import torch
from torch.nn import ReLU
from torch import nn

input = torch.tensor([[1,-3],
                      [-0.5,2]],dtype=torch.float32)

input = torch.reshape(input,(-1,1,2,2))
print(input.shape)  # torch.Size([1, 1, 2, 2])

class myModule(nn.Module):
    def __init__(self):
        super(myModule, self).__init__()
        self.relu = ReLU()

    def forward(self,input):
        return self.relu(input)


myModule = myModule()
output = myModule(input)

print(output)
"""
tensor([[[[1., 0.],
          [0., 2.]]]])
"""



2. Sigmoid 函数

class torch.nn.Sigmoid(*args, **kwargs)

公式:

                                Sigmoid(x)=\sigma (x)=\frac{1}{1+exp(-x)}

图像:

特性:

  • 值域在(0,1)之间:sigmoid函数的输出值介于0和1之间,可以将任意实数映射到一个概率值范围内。

  • 具有平滑性:sigmoid函数是一个平滑的S型曲线,这使得它可以进行连续的梯度计算,有利于优化算法的收敛。

  • 可以用于二分类问题:sigmoid函数常用于二分类问题,将线性输出(logit)转换为类别概率。

  • 可以用于神经网络隐藏层:sigmoid函数在神经网络的隐藏层中也可以使用,传递非线性的激活值,有助于提取和学习更复杂的特征。

然而,sigmoid函数也存在一些缺点,例如:

  • 容易发生梯度消失:当输入值非常大或非常小时,sigmoid函数的导数接近于零,这导致了梯度消失的问题,使得深层神经网络的反向传播算法难以有效地更新权重。

  • 输出不是零中心化:sigmoid函数的输出非零中心化,这意味着它的平均值不为零,这会在某些情况下不利于神经网络的训练。

  • 计算量较大:相比于其他激活函数,sigmoid函数的计算量较大,因为它需要进行指数运算。

因此,在一些情况下,为了解决梯度消失和计算量较大的问题,人们更倾向于使用其他激活函数,如ReLU、Leaky ReLU和ELU等。

3. LeakyReLU 函数

class torch.nn.LeakyReLU(negative_slope=0.01, inplace=False)

 negative_slope 是指ReLU(Rectified Linear Unit)函数中的负斜率。ReLU函数在负数范围内保持不为零的激活值。负斜率表示了ReLU函数在负数范围内的线性部分的斜率。

一些常见的取值如:negative_slope = 0.01(Leaky ReLU),negative_slope = 0.2(Parametric ReLU)等。通过调整 negative_slope 的值可以控制ReLU函数在负数范围内的输出激活值大小。

公式:

图像:

特性:

  1. 解决了ReLU中的神经元“死亡”问题,增加了负数范围内的激活值,使得所有神经元都能够参与到训练中。
  2. 具有线性关系,在负数范围内保留了一部分输入值信息,有助于提高模型的表达能力。
  3. 可以通过调整负斜率的值来控制负数范围内的输出激活值大小,一般取较小的正数。

4. Tanh 函数

class torch.nn.Tanh(*args, **kwargs)

公式:

                                        Tanh(x)=tanh(x)=\frac{exp(x)-exp(-x)}{exp(x)+exp(-x)}

图像:

特性:

  1.  范围在[-1, 1]之间:Tanh函数的输出范围是[-1, 1],当输入趋近于正无穷大时,输出趋近于1;当输入趋近于负无穷大时,输出趋近于-1;当输入为0时,输出为0。这使得Tanh函数可以将输入值映射到一个有限的范围内,适用于对称的激活函数要求。
  2. 中心对称性:Tanh函数以(0, 0)为中心点对称,即f(x) = -f(-x)。这意味着当输入接近0时,输出值也接近0。这性质与许多优化算法和神经网络中的权重初始化方法是相容的。
  3. 渐进性:当输入值趋近于正负无穷大时,Tanh函数的输出趋近于1和-1,它们是函数的渐进值。这个特性可以使神经网络对输入值的变化具有更大的敏感性。

注意:

        Tanh函数在输入值远离零时会饱和,导致梯度消失的问题。当输入值非常大或非常小时,Tanh函数的导数接近于0,这可能会对梯度下降算法的有效性产生不利影响

5. ELU 函数

class torch.nn.ELU(alpha=1.0, inplace=False)

公式:

图像:

特性:

  1. 支持负数输入:ELU函数在输入小于等于零时,对于负值的处理方式与ReLU不同。它通过引入一个参数alpha,使得负值经过指数变换后仍保持负值,并且接近于0。这可以避免ReLU函数在负值时出现的死亡神经元问题。

  2. 有助于缓解梯度消失问题:ELU函数在输入小于等于零时,具有非常大的负导数。这可以使得具有负输入的神经元在反向传播时得到较大的梯度,从而有助于缓解梯度消失问题,使得网络更易于训练。

注意:

        ELU函数的参数alpha是一个超参数,通常取一个较小的正数值,如0.1或0.2。这个参数可以控制负输入的曲线斜率,从而影响神经元的激活程度。

3. 线性层

主要作用

线性层是深度学习中常用的一种基本层类型,也被称为全连接层或仿射层。它的主要作用是对输入的特征进行线性变换并输出。

在深度学习模型中,线性层通常用于实现从输入特征到输出特征的映射。它可以将输入特征空间的每个维度与一个权重相关联,并通过加权和的方式将所有维度的信息进行整合。同时,线性层还可以选择性地添加一个偏置项,用于进一步调整输出的偏移量。

线性层可以引入非线性变换的能力,使模型能够学习到更复杂的特征表示。通过堆叠多个线性层和非线性激活函数,可以组成深度神经网络,实现对输入数据的高级特征抽取和复杂模式识别。

 nn.Linear

class torch.nn.Linear(in_features, out_features, bias=True, device=None, dtype=None)

  • in_features:输入特征的数量,即输入张量的大小。输入张量的形状应为 (batch_size, in_features)。
  • out_features:输出特征的数量,即输出张量的大小。输出张量的形状为 (batch_size, out_features)。
  • bias:是否使用偏置项。默认为True,表示使用偏置项,设置为False时将不使用偏置项。
  • device:指定线性层运行的设备。默认为None,表示使用当前设备。可以通过torch.device("cuda:0")将线性层放在名为"cuda:0"的CUDA设备上。
  • dtype:指定线性层的数据类型。默认为None,表示使用默认的数据类型。可以通过torch.float32或torch.float64等指定数据类型。
import torch
import torch.nn
from torch import nn
from torch.nn import MaxPool2d, Linear
from torch.utils.tensorboard import SummaryWriter
import torchvision.datasets
from torch.utils.data import DataLoader


input = torchvision.datasets.CIFAR10("../TorchVersion/dataset",train=True,
                                     transform=torchvision.transforms.ToTensor(),download=True)
dataloader = DataLoader(input,batch_size=64)

class myModule(nn.Module):
    def __init__(self):
        super(myModule, self).__init__()
        self.linear1 = Linear(196608,10)

    def forward(self,input):
        output = self.linear1(input)
        return output

my_module = myModule()

"""
    将 torch.Size([64, 3, 32, 32])  改变格式为 torch.Size([1, 1, 1, 196608])
        方式一:
            # output = torch.reshape(img,(1,1,1,-1))
            # print(img.shape)    # torch.Size([1, 1, 1, 196608])
        方式二:
            output = torch.flatten(img)
            print(output.shape)  # torch.Size([196608])
"""

for data in dataloader:
    img, target = data
    print(img.shape)  # torch.Size([64, 3, 32, 32])

    output = torch.flatten(img)      # 将多维度的 Tensor, 展平为 一行 Tensor
    output = my_module(output)
    print(output.shape)        # torch.Size([10])



m = nn.Linear(20, 30)
input = torch.randn(128, 20)
output = m(input)
print(output.size())

5. 总结

线性层和非线性层在深度学习模型中通常是交替使用的,它们的组合极大地增强了模型的表达能力。

线性层通过线性变换将输入特征映射到输出特征空间,但它本身只能学习到输入特征之间的线性关系。线性模型的表达能力有限,无法很好地处理复杂的非线性模式。

为了解决这个问题,通常在线性层之后会添加一个非线性激活函数,例如ReLU、Tanh、Sigmoid等。非线性激活函数能够引入非线性变换,使得模型能够学习到更复杂的特征表示和模式。

通过交替使用线性层和非线性层,深度神经网络可以逐渐将输入数据转化为复杂的非线性表示。每一层的线性变换将输入特征进行了扩展和转换,而非线性激活函数引入了非线性变换,使网络能够逐渐学习到更丰富、更复杂的特征表示,从而提高了模型的表达能力和性能。

总结起来,线性层和非线性层是深度学习模型中的重要组成部分。线性层进行输入特征的线性变换,而非线性层引入非线性变换,交替使用可以提高模型的表达能力,使其能够处理更复杂的特征和模式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值