神经网络介绍

神经网络介绍

<1>神经网络概念

神经网络:ANN

是一种模仿生物神经网络结构和功能的计算模型,由众多神经元构成,各个神经元传递复杂电信号树突接收到输入信号,通过处理转换为输出信号

神经网络构建:

如何构建人工神经网络,如下图所示:

通过不同树突中含有的权重信息,进行加权计算,输入到细胞中做加和 ,在通过激活函数输出细胞值

神经网络构造图:输入层,隐藏层,输出层构造而成

使用多个神经元来构建神经网络,相邻层之间的神经元相互连接,并给每一个连接分配一个强度.

神经网络:

​ 神经网络中的信息只向一个方向移动,即输入节点向前移动,通过隐藏节点移动.其中的基本部分是:

​ 1. 输入层: 输入x的一层

​ 2. 隐藏层:输入x与y之间都为隐藏层

​ 3. 输出层:输出y的那一层

特点是:

  • 同一层神经元之间没有连接

  • 全连接神经网络:第N层的每个神经元和第N-层的所有神经元相连接

  • N-1层的输出为N层的输入

  • 每个链接都有一个权重值(w系数和b系数)

<2>激活函数

概述:用于对每层的输出数据进行变换.为整个网络注入非线性因素,神经网络就可拟合各种曲线.

  • 1.没有引入非线性因素的网络等价于使用一个线性模型来拟合

  • 2.通过给网络输出增加激活函数,引入非线性因素,使网络模型可以逼近任意函数,提升拟合能力

<3>常见的激活函数
1.sigmoid函数

激活函数公式:
f ( x ) = 1 1 + e − x f(x) = \frac{1}{1 + e^{-x}} f(x)=1+e−x1

激活函数求导公式:
f ′ ( x ) = f ( x ) ( 1 − f ( x ) ) f′(x)=f(x)(1−f(x)) f′(x)=f(x)(1−f(x))

sigmoid的函数图像,导数图像如下:

sigmoid函数介绍

将任意输入映射到(0,1)之间,当输入的值在-6或者>6时,意味着输入任何值得到的激活值都差不多的,这样会丢失部分信息.

通过导数数据取值范围为(0,0.25),在五层以后会出现梯度消失 情况,sigmoid一般只用于二分类

一般来说,sigmoid网络在5层之内就会产生梯度消失现象,而且该函数不是以0为中心点的,在实际中该函数很少使用,sigmoid函数一般用于二分类.

  • 代码展示
python 复制代码
import torch
import matplotlib.pyplot as plt

# 创建画布和坐标轴
_, axes = plt.subplots(1, 2)
# sigmoid函数图像
x = torch.linspace(-20, 20, 1000)
# 输入值x通过sigmoid函数转换成激活值y
y = torch.sigmoid(x)
axes[0].plot(x, y)
axes[0].grid()
axes[0].set_title('Sigmoid 函数图像')

# sigmoid导数图像
x = torch.linspace(-20, 20, 1000, requires_grad=True)
torch.sigmoid(x).sum().backward()
# x.detach():输入值x的数值
# x.grad:计算梯度,求导
axes[1].plot(x.detach(), x.grad)
axes[1].grid()
axes[1].set_title('Sigmoid 导数图像')
plt.show()
2.tanh函数

Tanh函数公式如下:
tanh ⁡ ( x ) = 1 − e − 2 x 1 + e − 2 x \tanh(x) =\frac{1 - e^{-2x}}{1 + e^{-2x}} tanh(x)=1+e−2x1−e−2x

函数求导公式:
tanh ⁡ ′ ( x ) = 1 − tanh ⁡ 2 ( x ) \tanh'(x) = 1 - \tanh^2(x) tanh′(x)=1−tanh2(x)

Tanh的函数图像,导数图像如下:

tanh函数介绍

  • tanh函数将输入映射到(-1,1)之间, 当输入大概<-3或者>3时将映射到(-1,1)之间,其导数值范围(0,1),当输入值大概子<-3或者>3时,导数近似于0

  • 梯度大于sigmoid,收敛速度比其快,减少迭代次数,如图所示导数两侧为零,也会梯度消失.

  • 若使用时在隐藏层使用tanh函数,在输出层使用sigmoid函数

python 复制代码
import torch
import matplotlib.pyplot as plt

# 创建画布和坐标轴
_, axes = plt.subplots(1, 2)
# 函数图像
x = torch.linspace(-20, 20, 1000)
y = torch.tanh(x)
axes[0].plot(x, y)
axes[0].grid()
axes[0].set_title('Tanh 函数图像')

# 导数图像
x = torch.linspace(-20, 20, 1000, requires_grad=True)
torch.tanh(x).sum().backward()
axes[1].plot(x.detach(), x.grad)
axes[1].grid()
axes[1].set_title('Tanh 导数图像')
plt.show()
3.Relu函数

ReLu函数公式
f ( x ) = m a x ( 0 , x ) f(x) = max(0,x) f(x)=max(0,x)
激活函数求导 公式
f ′ ( x ) = 0 或 1 f'(x) = 0或1 f′(x)=0或1

Relu的函数图像如下:

Relu函数介绍:

  • Relu激活函数将小于0的值映射为0,大于0的值则保持不变,更加重视正信号,而忽略负信号,能提高模型的训练效率
  • 当x<0时,Relu导数为0,而当x>0时则存在饱和问题,所以Relu函数在x>0时保持梯度不衰减,从而缓解梯度消失问题,随着训练的推进,部分输入会落入小于0的区域,导致权重无法更新,被称为:神经元死亡.
  • Relu函数是目前最常用的激活函,与sigmoid函数相比Relu函数计算量较小Relu函数会使一部分神经元输出为0,使网络稀疏化,减少参数之间的依赖性,缓解过拟合发生

代码展示

python 复制代码
# 创建画布和坐标轴
import torch
from matplotlib import pyplot as plt

_, axes = plt.subplots(1, 2)
# 函数图像
x = torch.linspace(-20, 20, 1000)
y = torch.relu(x)
axes[0].plot(x, y)
axes[0].grid()
axes[0].set_title('ReLU 函数图像')
# 导数图像
x = torch.linspace(-20, 20, 1000, requires_grad=True)
torch.relu(x).sum().backward()
axes[1].plot(x.detach(), x.grad)
axes[1].grid()
axes[1].set_title('ReLU 导数图像')
plt.show()

Relu特点

  • 简单高效:计算简单,前向和反向传播速度快
  • 稀疏激活:可以产生零输出,有助于稀疏表示
  • 缓解梯度消失问题:对于正向输出,梯度恒为1,有助于缓解梯度消失问题
  • 死区问题:对于负输入,梯度为0,可能导致死区问题

其他常见Relu函数

1.Leaky ReLU函数:用于给 负数梯度输入提供一个非零梯度

公式定义:
f ( x ) = { x if x > = 0 α x if x < 0 \text{f}(x) = \begin{cases} x & \text{if } x >= 0 \\ αx & \text{if x < 0} \end{cases} f(x)={xαxif x>=0if x < 0

其中α是一个小的正数,通常取0.01

  • 特点:

    • 缓解死区问题:对于负输入的,梯度不为零,可以缓解ReLU死区问题
    • **保持简单:**计算任然简单,前向,反向传播速度快
  • 调用方式

python 复制代码
torch.nn.LeakyRelu(negative_slope = 0.01)

2.PReLU函数: 与Leaky Relu类似,但α参数 可以学习

公式定义
f ( x ) = { x if x > = 0 α x if x < 0 \text{f}(x) = \begin{cases} x & \text{if } x >= 0 \\ αx & \text{if x < 0} \end{cases} f(x)={xαxif x>=0if x < 0

其中,α是一个可学习的参数

  • 特点

    • 自适应:α是一个可学习的参数,可以自动调节 负半轴斜率
    • 灵活性:比Leaky ReLU更灵活,可以更好的适应于不同的数据分布
  • 调用方式:

python 复制代码
torch.nn.PReLU(num_parameters=1, init=0.25)

3.ELU函数:

数学定义:
f ( x ) = { x if x > = 0 α ( e x − 1 ) if x < 0 \text{f}(x) = \begin{cases} x & \text{if } x >= 0 \\ α(e^x - 1) & \text{if x < 0} \end{cases} f(x)={xα(ex−1)if x>=0if x < 0

其中,α为正数通常取1.0

  • 特点
    • 平滑过渡:负半轴上有平滑的过渡,有助于减少梯度消失问题
    • 均值接近于零:激活函数的输出均值接近零,有助于加速训练
  • 调用方式
python 复制代码
torch.nn.ELU(alpha=1.0)

总结

  • ReLU:简单高效,广泛使用,但存在死区问题。
  • Leaky ReLU:缓解死区问题,保持简单。
  • PReLU:自适应调整负半轴斜率,灵活性更高。
  • ELU:平滑过渡,均值接近零,有助于加速训练。
4.Softmax激活函数

适用于多分类,目的是将多分类的结果以概率的形式展示出来

函数公式:
s o f t m a x ( z i ) = e z i ∑ j e z j softmax(z_i)=\frac{e^{z_i}}{\sum_j{e{z_j}}} softmax(zi)=∑jezjezi

softmax函数介绍

就是将网络输出通过softmax函数,映射到(0,1)的值,这些值的累计和为1(满足概率的性质),可以将其理解为概率,选取概率最大的节点作为我们预测目标类别。

  • 代码展示
python 复制代码
import torch

scores = torch.tensor([0.2, 0.02, 0.15, 0.15, 1.3, 0.5, 0.06, 1.1, 0.05, 3.75])
# dim = 0,按行计算
probabilities = torch.softmax(scores, dim=0)
print(probabilties)
激活函数选择方法
对于隐藏层:
  • 1.优先选择ReLU激活函数

  • 2.如果ReLU效果不好,可以尝试其他激活函数 ,如Leaky ReLU

  • 3 .如果使用ReLU函数,注意神经元死区问题,可更换Relu其他变体激活函数

  • 4.少使用sigmoid激活函数,可以尝试使用tanh激活函数

对于输出层
  • 二分类问题选择sigmoid函数

  • 多分类问题使用softmax函数

  • 回归问题选择identity 激活函数

<4>.参数初始化方法

均匀分布初始化:uniform_

权重参数初始化从区间均匀 随机取值即在(-1/√d,1/√d)均匀分布中生成当前神经元的权重,其中d为每个神经元的输入数量

python 复制代码
# 1.导入数据包
import torch
import torch.nn as nn

# 2.均匀分布初始化
def test01():
    # 全连接线性层
    linear = nn.Linear(5, 3)
    # 从0-1均匀分布 产生参数
    nn.init.uniform_(linear.weight)
    print(linear.weight.data)

正态分布初始化:normal_

随机初始化均值为0,标准差为1,使用一些很小的值对参数w进行初始化

python 复制代码
# 3.正态分布初始化
def test02():
    # 全连接线性层
    linear = nn.Linear(5, 3)
    # 正态分布
    nn.init.normal_(linear.weight, mean=0, std=1)
    print(linear.weight.data)

固定值初始化:constant_

将神经元 所有权重参数初始化固定为某个值

python 复制代码
# 4.固定值初始化
def test03():
    # 全连接线性层
    linear = nn.Linear(5, 3)
    # 固定值初始化
    nn.init.constant_(linear.weight, 0.1)
    print(linear.weight.data)

全零初始化:zreos_

将神经网络中的所有权重参数初始化为 0

python 复制代码
# 5.全零初始化
def test04():
    # 全连接线性层
    linear = nn.Linear(5, 3)
    # 全零初始化
    nn.init.zeros_(linear.weight)
    print(linear.weight.data)

全1初始化:ones_

将神经网络中的所有权重参数初始化为 1.

python 复制代码
# 6.全1初始化
def test05():
    # 全连接线性层
    linear = nn.Linear(5, 3)
    # 全1初始化
    nn.init.ones_(linear.weight)
    print(linear.weight.data)

Kaiming初始化,也叫HE初始化 适用于Relu激活函数以及变体

均匀分布初始化:unifrom_

python 复制代码
# 它从 [-limit,limit] 中的均匀分布中抽取样本, limit是 sqrt(6 / fan_in)
#  fan_in为输入神经元个数

# kaiming均匀分布
def test07():
    linear = nn.Linear(5, 3)
    nn.init.kaiming_uniform_(linear.weight)
    print(linear.weight.data)

正态化初始化:normal_

python 复制代码
# stddev = sqrt(2 / fan_in)
# sqrt:根号

# kaiming正态分布
def test06():
    linear = nn.Linear(5, 3)
    nn.init.kaiming_normal_(linear.weight)
    print(linear.weight.data)

Xavier初始化,也叫Glorot初始化 适用于sigmoid,tanh激活函数

正态化初始化:uniform_

python 复制代码
# stddev = sqrt(2 / (fan_in + fan_out))

# xavier正态分布
def test08():
    linear = nn.Linear(5, 3)
    nn.init.xavier_normal_(linear.weight)
    print(linear.weight.data

均匀分布初始化:normal_

python 复制代码
# [-limit,limit] 中的均匀分布中抽取样本, limit 是 sqrt(6 / (fan_in + fan_out))
# fan_in 是输入神经元的个数, fan_out 是输出的神经元个数

# xavier均匀分布
def test09():
    linear = nn.Linear(5, 3)
    nn.init.xavier_uniform_(linear.weight)
    print(linear.weight.data)
<5>.神经网络搭建及参数计算

在pytorch中定义深度神经网络 就是堆叠的过程,继承自nn.Model,实现两个方法:

  • __init__定义网络中的层结构,主要进行全连接层,并进行参数初始化:初始化权重系数和偏置值

  • forword方法,在实例化模型时,底层会自动调用该函数,该函数可定义学习率,为初始化定义的layer传入数据.

来构建如下图神经网络模型

编程设计如下

第1个隐藏层:权重初始化采用标准化的xavier初始化 激活函数使用sigmoid

第2个隐藏层:权重初始化采用标准化的He初始化 激活函数采用relu

out输出层线性层 假若二分类,采用softmax做数据归一化

python 复制代码
import torch
import torch.nn as nn
from torchsummary import summary  # 计算模型参数,查看模型结构, pip install torchsummary

# 创建神经网络模型类
class Model(nn.Module):
    # 初始化属性值
    def __init__(self):
        super(Model, self).__init__() # 调用父类的初始化属性值
        self.linear1 = nn.Linear(3, 3) # 创建第一个隐藏层模型, 3个输入特征,3个输出特征
        nn.init.xavier_normal_(self.linear1.weight) # 初始化权
        # 创建第二个隐藏层模型, 3个输入特征(上一层的输出特征),2个输出特征
        self.linear2 = nn.Linear(3, 2)
        # 初始化权重
        nn.init.kaiming_normal_(self.linear2.weight)
        # 创建输出层模型
        self.out = nn.Linear(2, 2)

    # 创建前向传播方法,自动执行forward()方法
    def forward(self, x):
        # 数据经过第一个线性层
        x = self.linear1(x)
        # 使用sigmoid激活函数
        x = torch.sigmoid(x)
        # 数据经过第二个线性层
        x = self.linear2(x)
        # 使用relu激活函数
        x = torch.relu(x)
        # 数据经过输出层
        x = self.out(x)
        # 使用softmax激活函数
        # dim=-1:每一维度行数据相加为1
        x = torch.softmax(x, dim=-1)
        return x


if __name__ == "__main__":
    # 实例化model对象
    my_model = Model()
    # 随机产生数据
    my_data = torch.randn(5, 3)
    print("mydata shape", my_data.shape)
    # 数据经过神经网络模型训练
    output = my_model(my_data)
    print("output shape-->", output.shape)
    # 计算模型参数
    # 计算每层每个神经元的w和b个数总和
    summary(my_model, input_size=(3,), batch_size=5) 
    # 查看模型参数
    print("======查看模型参数w和b======")
    for name, parameter in my_model.named_parameters():
        print(name, parameter)

总结

神经网络搭建方法

1.定义继承nn.Model的模型类

2.在__init__ 方法中定义网络的结构:定义各个层的网络并初始化权重系数和偏置

3.在forward方法中定义数据传输方式:使用激活函数增加非线性因素提高拟合能力

激活函数使用

介绍几种常用的激活函数,具体使用还要结合遇到的问题

相关推荐
卧式纯绿1 分钟前
自动驾驶3D目标检测综述(三)
人工智能·python·深度学习·目标检测·3d·cnn·自动驾驶
ZOMI酱1 小时前
【AI系统】GPU 架构回顾(从2018年-2024年)
人工智能·架构
土豆炒马铃薯。1 小时前
【深度学习】Pytorch 1.x 安装命令
linux·人工智能·pytorch·深度学习·ubuntu·centos
阿_旭1 小时前
【超全】目标检测模型分类对比与综述:单阶段、双阶段、有无锚点、DETR、旋转框
人工智能·深度学习·目标检测·分类
研一计算机小白一枚1 小时前
Which Tasks Should Be Learned Together in Multi-task Learning? 译文
人工智能·python·学习·机器学习
xianghan收藏册2 小时前
基于lora的llama2二次预训练
人工智能·深度学习·机器学习·chatgpt·transformer
2zcode2 小时前
基于YOLOv8深度学习的智慧农业果园果树柑橘类果实目标检测系统(PyQt5界面+数据集+训练代码)
深度学习·yolo·目标检测
Eric.Lee20212 小时前
数据集-目标检测系列- 蘑菇 检测数据集 mushroom >> DataBall
人工智能·python·yolo·目标检测·计算机视觉·蘑菇检测
像污秽一样2 小时前
根据气候变化自动制定鲜花存储策略(BabyAGI)
人工智能·chatgpt·langchain
Struart_R2 小时前
Epipolar-Free 3D Gaussian Splatting for Generalizable Novel View Synthesis 论文解读
人工智能·深度学习·计算机视觉·3d·transformer·三维重建·新视角生成