神经网络学习日记(一)——神经网络基本概念

本文是笔者为了完成毕业设计而进行学习的一个个人学习日记
图片和链接均源自网络,侵删

感知机模型

感知机模型(Perceptron Model) 是神经元的建模,包含输入、计算和输出。通常有多个输入值 x 0 , x 1 , … , x n x_0,x_1,\dots,x_n x0,x1,,xn,对应的权重分别是 w 0 , w 1 , … , w n w_0,w_1,\dots,w_n w0,w1,,wn,激活函数为 f f f,输出输出值为 y y y

感知机模型

全连接神经网络详解:https://blog.csdn.net/ShiningLeeJ/article/details/126676581

如上图所示,对于这样一个简单的感知机,输出 y y y的计算公式为:
y = f ( ∑ i = 0 n w i x i ) y=f(\sum_{i=0}^nw_ix_i) y=f(i=0nwixi)

激活函数

激活函数(Activation Function) 是一种添加到人工神经网络中的函数,其主要作用是对所有的隐藏层和输出层添加一个非线性的操作,使得神经网络的输出更为复杂、表达能力更强。

常见的激活函数有Sigmoid函数、Tanh函数、ReLU函数、Softmax函数等,分别在不同的场合有自己的作用和优缺点。

常用的激活函数合集(详细版):https://blog.csdn.net/caip12999203000/article/details/127067360

Sigmoid函数

Sigmoid函数是一个非常常见的激活函数,其值域为[0, 1],非常适合作为模型的输出函数用于输出一个(0, 1)范围内的概率值,可用于将预测概率作为输出的模型,比如用于表示二分类的类别或者用于表示置信度
S i g m o i d 函数的公式: f ( x ) = 1 1 + e − x ,导函数: f ′ ( x ) = e − x ( 1 + e − x ) 2 = ( 1 − f ( x ) ) Sigmoid函数的公式:f(x)=\frac{1}{1+e^{-x}},导函数:f'(x)=\frac{e^{-x}}{(1+e^{-x})^2}=(1-f(x)) Sigmoid函数的公式:f(x)=1+ex1,导函数:f(x)=(1+ex)2ex=(1f(x))
sigmoid

然而,其导数的最大值只有0.25,且在 ∣ x ∣ > 5 |x|>5 x>5时导数值就几乎接近于0。这种情况会导致训练过程中神经元处于饱和状态,权重几乎得不到更新,称为梯度消失

在PyTorch中,Sigmoid函数的调用方式为:

import torch.nn.functional as F
output = F.sigmoid(input)

Tanh函数

Tanh函数的输出是S型曲线,具备打破网络层与网络层之间的线性关系,可以把网络层输出非线形地映射到 (−1, 1) 区间里。其具有很多神经网络所钟爱的特征。它完全可微分反对称,且对称中心在原点。在一般的二元分类问题中,tanh 函数用于隐藏层,而 sigmoid 函数用于输出层,但这并不是固定的,需要根据特定问题进行调整。
T a n h 函数的公式: f ( x ) = e x − e − x e x + e − x ,导函数: f ′ ( x ) = 4 ( e x + e − x ) 2 = 1 − [ f ( x ) ] 2 Tanh函数的公式:f(x)=\frac{e^x-e^{-x}}{e^x+e^{-x}},导函数:f'(x)=\frac4{(e^x+e^{-x})^2}=1-[f(x)]^2 Tanh函数的公式:f(x)=ex+exexex,导函数:f(x)=(ex+ex)24=1[f(x)]2

tanh

分类任务中,Tanh函数逐渐取代Sigmoid函数作为标准的激活函数。可是当输入较大或较小时,其输出几乎是平滑的且梯度较小,不利于权重更新。此外,Tanh函数也存在梯度消失的问题。

在PyTorch中,Tanh函数的调用方式为:

import torch.nn.functional as F
output = F.tanh(input)

ReLU函数

ReLU函数在正输入时是线性的,收敛和计算速度快,并且由于正输入时导数为1,能够完整传递梯度,不存在梯度消失的问题,是使用最频繁的激活函数。
R e L U 函数的公式: f ( x ) = { x , x ≥ 0 0 , x < 0 ,导函数: f ′ ( x ) = { 1 , x ≥ 0 0 , x < 0 ReLU函数的公式:f(x)=\begin{cases} x,& x\ge0 \\ 0,& x<0 \end{cases} ,导函数:f'(x)=\begin{cases} 1,& x\ge0 \\ 0,& x<0 \end{cases} ReLU函数的公式:f(x)={x,0,x0x<0,导函数:f(x)={1,0,x0x<0

relu

ReLU的输入值为负的时候,输出始终为0,其一阶导数也始终为0,会导致神经元不能更新参数,这种现象叫做“Dead Neuron”。

在PyTorch中,ReLU函数的调用方式为:

import torch.nn.functional as F
output = F.relu(input)

Softmax函数

由于使用梯度无法求导,因此导函数图像是一个 y = 0 y=0 y=0的直线。Softmax函数在零点不可微,在负输入的梯度为0,因此在该区域权重不会再反向传播期间更新,会产生永不激活的神经元。
S o f t m a x 函数的公式: f ( x ) = e x i ∑ i = 0 n e x i Softmax函数的公式:f(x)=\frac{e^{x_i}}{\sum_{i=0}^ne^{x_i}} Softmax函数的公式:f(x)=i=0nexiexi

softmax

由于预测结果总是转化为非负数,并且结果概率之和等于1,故很适合配合交叉熵损失函数做多分类模型。

在PyTorch中,Softmax函数的调用方式为:

import torch.nn.functional as F
output = F.softmax(input)

损失函数

损失函数(Loss Function)是用于计算结果与答案之间的差异的函数,深度学习是一种有监督的学习,在计算结果后,需要与标签(label)进行对比得到计算结果与答案之间的差异,称为损失(loss)。常见的损失函数如均方差损失函数、平均绝对误差损失函数、交叉熵损失函数等。

常用的损失函数合集:https://blog.csdn.net/caip12999203000/article/details/127307395

【深度学习】损失函数详解:https://blog.csdn.net/LogosTR_/article/details/126366482

均方差损失函数(MSE Loss)

均方差损失函数属于是一个万金油的损失函数,既可以处理分类问题,也可以处理回归问题。求的是预测值与真实值差的平均平方。
M S E = 1 n ∑ i = 0 n ( y i − y ^ i ) 2 MSE=\frac1n\sum_{i=0}^n(y_i-\hat{y}_i)^2 MSE=n1i=0n(yiy^i)2
在PyTorch中均方差损失函数的调用方式为:

import torch
loss_function = torch.nn.MSELoss(reduction='mean')

平均绝对误差损失函数(L1 Loss)

指预测值和真实值之间距离平均值。
M A E = 1 n ∑ i = 0 n ∣ y i − y ^ i ∣ MAE=\frac1n\sum_{i=0}^n|y_i-\hat{y}_i| MAE=n1i=0nyiy^i

在PyTorch中平均绝对误差损失函数的调用方式为:

import torch
loss_function = torch.nn.L1Loss(reduction='mean')

交叉熵损失函数(Cross Entropy Loss)

主要运用在多分类问题中。
C r o s s E n t r o p y = − y × log ⁡ ( y ^ ) CrossEntropy=-y\times\log(\hat y) CrossEntropy=y×log(y^)
在PyTorch中平交叉熵损失函数的调用方式为:

import torch
loss_function = torch.nn.CrossEntropyLoss()

前向传播

神经网络中数据的传播方式与感知机相同,被称为前向传播(Forward Propagation),但是会在累加时默认加上一个偏置值 b b b,即一个输入值为 b b b,权重值为1的输入节点。我们使用 b j l b^l_j bjl表示在第 l l l层的第 j j j个神经元的偏置值。

对于每条链接上的权重,我们使⽤ w j k l w^l_{jk} wjkl表示从第 ( l − 1 ) (l-1) (l1)层的第 k k k个神经元,到第 l l l层的第 j j j个神经元的链接上的权重。例如,下面的 w 24 3 w^3_{24} w243表示第2层第4个神经元到第3层第二个神经元连接上的权重:

forward

同理,我们可以用 a j l a^l_j ajl表示第 l l l层的第 j j j个神经元的激活值,那么,我们就可以用上一层的激活值 a j l − 1 a^{l-1}_j ajl1和权重、偏置值等参数来表示 a j l a^l_j ajl f f f为激活函数):
a j l = f ( ∑ k w j k l a j l − 1 + b j l ) a^l_j=f(\sum_kw^l_{jk}a^{l-1}_j+b^l_j) ajl=f(kwjklajl1+bjl)

反向传播与优化器

在前向传播算出预测值之后,我们要使用损失函数得到的损失值反过来更新参数,即反向传播(Back Propagation)。一般情况下,使用的方法是梯度下降法,即权值和偏置矢量的修正值正比于当前位置上损失值的梯度,得到 Δ w j k = ∂ E ∂ w j k \Delta w_{jk}=\frac{\partial E}{\partial w_{jk}} Δwjk=wjkE Δ b j = ∂ E ∂ b j \Delta b_{j}=\frac{\partial E}{\partial b_{j}} Δbj=bjE。对于一个简单的单隐藏层FCNN,根据链式求导法则,可以得到权重的更新公式。在PyTorch中,我们通过选择不同的**优化器(Optimizer)**来实现,不同的优化器会通过loss值,用不同的方式调整模型参数的值。下面介绍不同的优化器及其优缺点。

传统梯度下降法

  • BGD(批量梯度下降法)

    BGD在训练的时候选用所有的训练集进行计算,将全部的数据样本输入后进行一次更新,更新公式如下:
    w k + 1 = w k − η ∗ ▽ f ( w k ) w^{k+1}=w^k-\eta*\bigtriangledown f(w^k) wk+1=wkηf(wk)
    其中, η \eta η为学习率, ▽ f ( w k ) \bigtriangledown f(w^k) f(wk)为模型参数更新梯度。

    这个方法的最大问题就是容易落入局部最优点(local minimum)或者鞍点(saddle point)。落入后,会导致梯度为0,无法继续更新梯度。

  • SGD(随机梯度下降法)

    为了解决BGD落入鞍点或局部最优点的问题,SGD引入了随机性,即将每个数据样本输入网络计算梯度后就进行一次更新,更新公式如下:
    w k + 1 = w k − η ∗ ▽ f ( w k ; x i ; y i ) w^{k+1}=w^k-\eta*\bigtriangledown f(w^k;x^i;y^i) wk+1=wkηf(wk;xi;yi)
    由于要对每个样本都单独计算梯度,那么相当于引入了许多噪声,梯度下降时就会跳出鞍点和局部最优点。但要对每个样本都计算一次梯度就导致了时间复杂度较高,模型收敛较慢,而且loss和梯度会有大幅度的震荡

  • MBGD(小批量梯度下降法)

    MBGD在训练的时候只选择小部分数据进行训练,相当于缝合了SGD和BGD,将多个数据样本输入网络计算梯度后就进行一次更新,更新公式如下:
    w k + 1 = w k − η ∗ ▽ f ( w k ; x i : i + b ; y i : i + b ) w^{k+1}=w^k-\eta*\bigtriangledown f(w^k;x^{i:i+b};y^{i:i+b}) wk+1=wkηf(wk;xi:i+b;yi:i+b)
    MBGD同时解决了两者的缺点,使得参数更新更稳定更快速,这也是我们最常用的方法,在PyTorch中SGD类也是指的MBGD(当然可以自己设置特殊的batch size,就会退化为SGD或BGD)。但同时,它也继承了BGD和SGD的缺点:第一,随机噪声的引入使得权值更新方向不一定正确;第二,无法解决局部最优的问题。

以上三种传统梯度下降法的PyTorch代码调用如下:

'''
params(iterable)- 参数组
lr(float)- 初始学习率,可按需随着训练过程不断调整学习率
momentum(float)- 动量,通常设置为0.9,0.8
dampening(float)- dampening for momentum,暂时不了解其功能
weight_decay(float)- 权值衰减系数,也就是L2正则项的系数
nesterov(bool)- bool 选项,是否使用NAG(Nesterov accelerated gradient)
'''
torch.optim.SGD(params, lr=lr, momentum=0, dampening=0, weight_decay=0, nesterov=False)

自适应学习率方法

  • AdaGrad算法

    AdaGrad算法是梯度下降法的改进算法,其优点是可以自适应学习率。该优化算法在较为平缓处学习速率大,有比较高的学习效率,在陡峭处学习率小,在一定程度上可以避免越过极小值点。公式较为复杂,PyTorch代码调用如下:

    '''
    lr_decay(float)– 学习率衰减系数
    '''
    torch.optim.Adagrad(params, lr=0.01, lr_decay=0, weight_decay=0, initial_accumulator_value=0)
    
  • RMSProp算法

    RMSProp简单修改了Adagrad方法,结合梯度平方的指数移动平均数来调节学习率的变化。与AdaGrad不同,其更新不会让学习率单调变小。

    '''
    alpha(float)- 平滑常数
    eps(float)- 加到分母中防止为0
    centered(bool)- 如果为真,计算中心RMSProp,梯度通过其方差的估计进行归一化
    '''
    torch.optim.RMSprop(params, lr=0.01, alpha=0.99, eps=1e-08, weight_decay=0, momentum=0, centered=False)
    
  • Adam算法

    Adam本质上是带有动量项的RMSProp,它利用梯度的一阶矩估计和二阶矩估计动态调整每个参数的学习率。Adam的优点主要在于经过偏置校正后,每一次迭代学习率都有个确定范围,使参数比较稳定。

    '''
    betas(tuple[float, float])- 用于计算梯度及其平方的运行平均值的系数
    amsgrad(bool)- 是否使用论文 On the Convergence of Adam and Beyond 中该算法的AMSGrad变体
    '''
    torch.optim.Adam(params, lr=0.001, betas=(0.9, 0.999), eps=1e-08, weight_decay=0, amsgrad=False)
    

    Adam实现简单,计算高效,对内存需求少,很适合应用于大规模的数据及参数的场景。

个人神经网络学习日记:
神经网络学习日记(一)——神经网络基本概念
神经网络学习日记(二)——全连接神经网络及Pytorch代码实现
神经网络学习日记(三)——CNN卷积神经网络
神经网络学习日记(四)——RNN、LSTM、BiLSTM、GRU
神经网络学习日记(五)——数据加载器(DataLoader)的调用

由于是第一次写博客,不知道是否有侵犯其他人文章版权的问题,如果有请务必联系我,谢谢!

  • 28
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值