【神经网络基础】

目录

一、神经网络的构成

1.1什么是神经网络?

[1.2 激活函数](#1.2 激活函数)

[1.2.1 Sigmoid](#1.2.1 Sigmoid)

[1.2.2 Tanh](#1.2.2 Tanh)

[1.2.3 ReLU](#1.2.3 ReLU)

[1.2.4 softmax](#1.2.4 softmax)

[1.2.5 其他激活函数](#1.2.5 其他激活函数)

[1.2.6 选择激活函数](#1.2.6 选择激活函数)

[1.3 参数初始化](#1.3 参数初始化)

[1.4 模型构建](#1.4 模型构建)

二、损失函数

[2.1 分类问题](#2.1 分类问题)

2.1.1多分类(多分类交叉熵/softmax损失)

[2.1.2 二分类(二分类交叉熵/sigmoid损失)](#2.1.2 二分类(二分类交叉熵/sigmoid损失))

[2.2 回归问题](#2.2 回归问题)

[2.2.1 MSE(L2 loss)](#2.2.1 MSE(L2 loss))

[2.2.2 MAE(L1 loss)](#2.2.2 MAE(L1 loss))

[2.2.3 Smooth L1](#2.2.3 Smooth L1)

三、优化方法

[3.1 反向传播](#3.1 反向传播)

[3.2 梯度下降的优化方法](#3.2 梯度下降的优化方法)

[3.2.1 指数加权平均](#3.2.1 指数加权平均)

[3.2.2 动量算法Momentum](#3.2.2 动量算法Momentum)

[3.2.3 AdaGrad](#3.2.3 AdaGrad)

[3.2.4 RMSProp](#3.2.4 RMSProp)

[3.2.5 Adam](#3.2.5 Adam)

[3.3 学习率衰减](#3.3 学习率衰减)

[3.3.1 等间隔衰减](#3.3.1 等间隔衰减)

[3.3.2 指定间隔衰减](#3.3.2 指定间隔衰减)

[3.3.3 指数衰减](#3.3.3 指数衰减)

四、正则化

[4.1 Dropout正则化](#4.1 Dropout正则化)

[4.2 批量归一化](#4.2 批量归一化)


一、神经网络的构成

1.1什么是神经网络?

人工神经网络( Artificial Neural Network, 简写为ANN )也简称为神经网络(NN),是一种模仿生物神经网络结构和功能的计算模型。由神经元(加权和 + 激活函数)构成

神经网络中信息只向一个方向移动,即从输入节点向前移动,通过隐藏节点,再向输出节点移动。
其中的基本部分是 :
1. 输入层 : 即输入 x 的那一层
2. 输出层 : 即输出 y 的那一层
3. 隐藏层 : 输入层和输出层之间都是隐藏层
特点是:
• 同一层的神经元之间没有连接。
• 第 N 层的每个神经元和第 N-1 层 的所有神经元相连(这就是 full connected 的含义 ) ,这就是全连接神经网络。
• 第 N-1 层神经元的输出就是第 N 层神经元的输入。
• 每个连接都有一个权重值( w 系数和 b 系数)。

1.2 激活函数

**解释:**激活函数由于对每层的输出数据进行变换,进而为整个网络注入了非线性因素。此时,神经网路就可以拟合各种曲线。

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

  2. 通过给网络输出增加激活函数, 实现引入非线性因素, 使得网络模型可以逼近任意函数, 提升网络对复杂问题的拟合能力.

1.2.1 Sigmoid

常见的激活函数**-sigmoid****激活函数**:(适用于二分类的输出层)

① sigmoid 函数可以将任意的输入映射到 **(0, 1)**之间,当输入的值大致在 <-6或者>6时,意味着输入任何值得到的激 活值都是差不多的,这样会丢失部分的信息。比如:输入 100 和输出 10000 经过 sigmoid 的激活值几乎都是等于 1 的,但是输入的数据之间相差 100 倍的信息就丢失了。

② 对于 sigmoid 函数而言,输入值在 [-6, 6]之间输出值才会有明显差异,输入值在 [-3, 3]之间才会有比较好的效果

③ 通过上述导数图像,我们发现导数数值范围是****(0, 0.25),当输入 <-6 或者 >6 时,sigmoid 激活函数图像的导数接近0,此时网络参数将更新极其缓慢,或者无法更新。

④ 一般来说, sigmoid 网络在 5****层之内就会产生梯度消失现象。而且,该激活函数并不是以 0 为中心的,所以在实践 中这种激活函数使用的很少。sigmoid****函数一般只用于二分类的输出层

python 复制代码
import torch
import matplotlib.pyplot as plt
import os
os.environ['KMP_DUPLICATE_LIB_OK'] = 'TRUE'

plt.rcParams['font.sans-serif'] = ['SimHei']  # 选择中文字体
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题

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


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

1.2.2 Tanh

常见的激活函数**-tanh****激活函数:**

  • 隐藏层中要使用指数型激活函数时,就选择tanh,不要使用sigmoid

  • [-1,1],关于0对称

  • 导数相对于sigmoid大,更新速度快,迭代次数少

  • x远离0点时,梯度为0,梯度消失/弥散

① Tanh 函数将输入映射到 (-1, 1) 之间,图像以 0 为中心,在 0 点对称,当输入 大概<-3 或者>3 时将被映射为 -1 或者 1。其导数值范围 (0, 1),当输入的值大概 <-3 或者 > 3 时,其导数近似 0。

② 与 Sigmoid 相比,它是以 0 为中心的,且梯度相对于sigmoid大,使得其收敛速度要比Sigmoid 快,减少迭代次数。然而,从图中可以看出,Tanh 两侧的导数也为 0,同样会造成梯度消失。

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

python 复制代码
import torch
import matplotlib.pyplot as plt
import os
os.environ['KMP_DUPLICATE_LIB_OK'] = 'TRUE'

plt.rcParams['font.sans-serif'] = ['SimHei']  # 选择中文字体
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题

# 创建画布和坐标轴
_, 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()

1.2.3 ReLU

常用的激活函数 -ReLU 激活函数:

  • 隐藏层使用,最多
  • 小于0 ,取值为0 ;大于0 ,本身
  • 导数:小于0 ,取值为0 ;大于0 ,为1
  • 大于0 :不会梯度消失
  • 小于0:
  • 当某一部分神经元输出为0,神经元死亡,缓解过拟合
  • 当大部分神经元输出为0,从头开始或换激活函数leakyrelu
  • 相对于sigmoid: 计算简单,计算量小(函数和求导)

① ReLU 激活函数将小于 0 的值映射为 0,而大于 0 的值则保持不变,它更加重视正信号,而忽略负信号,这种激活函数运算更为简单,能够提高模型的训练效率。

② 当x<0时,ReLU导数为0,而当x>0时,则不存在饱和问题。所以,ReLU 能够在x>0时保持梯度不衰减,从而缓解梯度消失问题。然而,随着训练的推进,部分输入会落入小于0区域,导致对应权重无法更新。这种现象被称为"神经元死亡" 。

③ReLU是目前最常用的激活函数。与sigmoid相比,RELU的优势是:采用sigmoid函数,计算量大(指数运算),反向传播求误差梯度时,计算量相对大,而采用Relu激活函数,整个过程的计算量节省很多。 sigmoid函数反向传播时,很容易就会出现梯度消失的情况,从而无法完成深层网络的训练。 Relu会使一部分神经元的输出为0,这样就造成了网络的稀疏性,并且减少了参数的相互依存关系,缓解了过拟合问题的发生。

python 复制代码
import torch
import matplotlib.pyplot as plt
import os
os.environ['KMP_DUPLICATE_LIB_OK'] = 'TRUE'

plt.rcParams['font.sans-serif'] = ['SimHei']  # 选择中文字体
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题

# 创建画布和坐标轴
_, 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()

1.2.4 softmax

常用的激活函数**-SoftMax****激活函数:**

  • 多分类输出层

  • 将输出层的加权和(scores/logits)转换概率值,概率值之和是1

  • 选择概率最大的作为结果

  • 多分类的目标值:类别标注的热编码结果

softmax用于多分类 过程中,它是二分类函数sigmoid在多分类上的推广,目的是将多分类的结果以概率的形式展现出来。计算方法如下图所示:

Softmax 就是将网络输出的 logits 通过 softmax 函数,就映射成为(0,1)的值,而这些值的累和****为1(满足概率的性质),那么我们将它理解成概率,选取概率最大(也就是值对应最大的)节****点,作为我们的预测目标类别

1.2.5 其他激活函数

1.2.6 选择激活函数

对于隐藏层:

  1. 优先选择ReLU激活函数

  2. 如果ReLu效果不好,那么尝试其他激活,如Leaky ReLu等。

  3. 如果你使用了ReLU, 需要注意一下Dead ReLU问题, 避免出现大的梯度从而导致过多的神经元死亡。

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

对于输出层:

  1. 二分类问题选择sigmoid激活函数

  2. 多分类问题选择softmax激活函数

  3. 回归问题选择identity激活函数

1.3 参数初始化

①均匀分布初始化(对weight)

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

python 复制代码
    linear = nn.Linear(5, 3)#(in_features,out_features)
    # 从0-1均匀分布产生参数
    nn.init.uniform_(linear.weight)
    print(linear.weight.data)

②正态分布初始化(对weight)

随机初始化从均值为0,标准差是1的高斯分布中取样,使用一些很小的值对参数W进行初始化

python 复制代码
    linear = nn.Linear(5, 3)
    nn.init.normal_(linear.weight, mean=0, std=1)
    print(linear.weight.data)

0初始化(对bias)

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

python 复制代码
    linear = nn.Linear(5, 3)
    nn.init.zeros_(linear.weight)
    print(linear.weight.data)

1初始化(对bias)

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

python 复制代码
    linear = nn.Linear(5, 3)
    nn.init.ones_(linear.weight)
    print(linear.weight.data)

固定值初始化(对bais)

将神经网络中的所有权重参数初始化为某个固定值

python 复制代码
    linear = nn.Linear(5, 3)
    nn.init.constant_(linear.weight, 5)
    print(linear.weight.data)

⑥kaiming 初始化,也叫做 HE 初始化

HE 初始化分为正态分布的 HE 初始化、均匀分布的 HE 初始化.

--正态化的he初始化

stddev = sqrt(2 / fan_in)

python 复制代码
    linear = nn.Linear(5, 3)
    nn.init.kaiming_normal_(linear.weight)
    print('kaiming正态分布:',linear.weight.data)

--均匀分布的he初始化

它从 [-limit,limit] 中的均匀分布中抽取样本, limit是 sqrt(6 / fan_in)

python 复制代码
    linear = nn.Linear(5, 3)
    nn.init.kaiming_uniform_(linear.weight)
    print('kaiming均匀分布:',linear.weight.data)

--fan_in 输入神经元的个数

⑦xavier 初始化,也叫做 Glorot初始化

该方法也有两种,一种是正态分布的 xavier 初始化、一种是均匀分布的 xavier 初始化.

--正态化的Xavier初始化

stddev = sqrt(2 / (fan_in + fan_out))

python 复制代码
    linear = nn.Linear(5, 3)
    nn.init.xavier_normal_(linear.weight)
    print('xavier正态分布:',linear.weight.data)

--均匀分布的Xavier初始化

[-limit,limit] 中的均匀分布中抽取样本, limit 是 sqrt(6 / (fan_in + fan_out))

python 复制代码
    linear = nn.Linear(5, 3)
    nn.init.xavier_uniform_(linear.weight)
    print('xavier均匀分布:',linear.weight.data)

--fan_in 是输入神经元的个数, fan_out 是输出的神经元个数

总结:

1.4 模型构建

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

① __init__方法中定义网络中的层结构,主要是全连接层,并进行初始化

② forward方法,在实例化模型的时候,底层会自动调用该函数。该函数中可以定义学习率,

为初始化定义的layer传入数据等。

编码设计:

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

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

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

'''
神经网络搭建流程
一个继承--继承自nn.moudle
两个方法 --__init__方法 网络层
        --forward方法  串联网络层
'''



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)

二、损失函数

2.1 分类问题

2.1.1多分类(多分类交叉熵/softmax损失)

python 复制代码
# 分类损失函数:交叉熵损失使用nn.CrossEntropyLoss()实现。nn.CrossEntropyLoss()=softmax + 损失计算
def test():
# 设置真实值: 可以是热编码后的结果也可以不进行热编码
# y_true = torch.tensor([[0, 1, 0], [0, 0, 1]], dtype=torch.float32)
# 注意的类型必须是64位整型数据
y_true = torch.tensor([1, 2], dtype=torch.int64)
y_pred = torch.tensor([[0.2, 0.6, 0.2], [0.1, 0.8, 0.1]], dtype=torch.float32)
# 实例化交叉熵损失
loss = nn.CrossEntropyLoss()
# 计算损失结果
my_loss = loss(y_pred, y_true).numpy()
print('loss:', my_loss)

2.1.2 二分类(二分类交叉熵/sigmoid损失)

python 复制代码
def test2():
    # 1 设置真实值和预测值
    # 预测值    是sigmoid输出的结果
    y_pred = torch.tensor([0.6901, 0.5459, 0.2469], requires_grad=True)
    y_true = torch.tensor([0, 1, 0], dtype=torch.float32)
    # 2 实例化二分类交叉熵损失
    criterion = nn.BCELoss()
    # 3 计算损失
    my_loss = criterion(y_pred, y_true).detach().numpy()
    print('loss:', my_loss)

2.2 回归问题

2.2.1 MSE(L2 loss)

采用均方误差方式:

python 复制代码
def test4():
    # 1 设置真实值和预测值
    y_pred = torch.tensor([1.0, 1.0, 1.9], requires_grad=True)
    y_true = torch.tensor([2.0, 2.0, 2.0], dtype=torch.float32)
    # 2 实例MSE损失对象
    loss = nn.MSELoss()
    # 3 计算损失
    my_loss = loss(y_pred, y_true).detach().numpy()
    print('myloss:', my_loss)

2.2.2 MAE(L1 loss)

平均绝对值误差:

python 复制代码
# 计算算inputs与target之差的绝对值
    def test3():
    # 1 设置真实值和预测值
    y_pred = torch.tensor([1.0, 1.0, 1.9], requires_grad=True)
    y_true = torch.tensor([2.0, 2.0, 2.0], dtype=torch.float32)
    # 2 实例MAE损失对象
    loss = nn.L1Loss()
    # 3 计算损失
    my_loss = loss(y_pred, y_true).detach().numpy()
    print('loss:', my_loss)

2.2.3 Smooth L1

python 复制代码
def test5():
    # 1 设置真实值和预测值
    y_true = torch.tensor([0, 3])
    y_pred = torch.tensor ([0.6, 0.4], requires_grad=True)
    # 2 示例损失对象
    loss = nn.SmoothL1Loss()
    # 3 计算损失
    my_loss = loss(y_pred, y_true).detach().numpy()
    print('loss:', my_loss)

三、优化方法

3.1 反向传播(BP算法)

什么是反向传播?

利用损失函数ERROR,从后往前,结合梯度下降法,依次求各个参数的偏导,并进行参数更新

什么是前向传播?

指的是数据输入的神经网络中,逐层向前传输,一直运算到输出层为止

反向传播(BP算法):

3.2 梯度下降的优化方法

梯度下降优化算法中,可能会碰到以下情况:

1. 碰到平缓区域,梯度值较小,参数优化变慢

2. 碰到 "鞍点" ,梯度为 0,参数无法优化

3. 碰到局部最小值,参数不是最优

3.2.1 指数加权平均

指数移动加权平均则是参考各数值,并且各数值的权重都不同,距离越远的数字对平均数计算的贡献就越小(权重较小),距离越近则对平均数的计算贡献就越大(权重越大)。比如:明天气温怎么样,和昨天气温有很大关系,而和一个月前的气温关系就小一些。

计算公式可以用下面的式子来表示:

3.2.2 动量算法Momentum

梯度计算公式:Dt = β * St-1 + (1- β) * Wt

  1. St-1 表示历史梯度移动加权平均值

  2. Wt 表示当前时刻的梯度值

  3. Dt 为当前时刻的指数加权平均梯度值

  4. β 为权重系数

假设:权重 β 为 0.9,例如:

第一次梯度值:s1 = d1 = w1

第二次梯度值:d2=s2 = 0.9 * s1 + w2 * 0.1

第三次梯度值:d3=s3 = 0.9 * s2 + w3 * 0.1

第四次梯度值:d4=s4 = 0.9 * s3 + w4 * 0.1

梯度下降公式中梯度的计算,就不再是当前时刻 t 的梯度值,而是历史梯度值的指数移动加权平

均值。公式修改为:

W_t+1 = W_t - a * Dt

3.2.3 AdaGrad

AdaGrad 通过对不同的参数分量使用不同的学习率,AdaGrad****的学习率总体会逐渐减小

其计算步骤如下:

  1. 初始化学习率 α、初始化参数 θ、小常数 σ = 1e-6

  2. 初始化梯度累积变量 s = 0

  3. 从训练集中采样 m 个样本的小批量,计算梯度 g

4.****累积平方梯度s = s + g ⊙ g,⊙ 表示各个分量相乘

3.2.4 RMSProp

RMSProp优化算法是对AdaGrad****的优化. 最主要的不同是,其使用指数移动加权平均梯度替换历史梯度的平方和。其计算过程如下:

  1. 初始化学习率 α、初始化参数 θ、小常数 σ = 1e-6

  2. 初始化参数 θ

  3. 初始化梯度累计变量 s

  4. 从训练集中采样 m 个样本的小批量,计算梯度 g

  5. 使用指数移动平均累积历史梯度,公式如下:

3.2.5 Adam

3.3 学习率衰减

3.3.1 等间隔衰减

3.3.2 指定间隔衰减

3.3.3 指数衰减

四、正则化

4.1 Dropout正则化

4.2 批量归一化

相关推荐
深图智能12 分钟前
PyTorch使用教程(9)-使用profiler进行模型性能分析
人工智能·pytorch·python·深度学习
天天代码码天天13 分钟前
C# OpenCvSharp 部署3D人脸重建3DDFA-V3
人工智能·神经网络·计算机视觉·c#·dnn·3d人脸重建
Zda天天爱打卡1 小时前
【机器学习实战入门】使用OpenCV和Keras的驾驶员疲劳检测系统
人工智能·深度学习·opencv·机器学习·数据挖掘·keras
明明真系叻1 小时前
2025.1.18机器学习笔记:PINN文献精读
人工智能·笔记·深度学习·机器学习·1024程序员节
wit_@2 小时前
【深入解析】 RNN 算法:原理、应用与实现
python·rnn·深度学习·神经网络
元宇宙时间2 小时前
DPIN与CESS Network达成全球战略合作,推动DePIN与AI领域创新突破
人工智能
雨后的路2 小时前
小雨:2024年,有哪些有趣的智能体?附文章总结/收藏/提醒助手教程
人工智能·程序员
格林威2 小时前
工业网口相机:如何通过调整网口参数设置,优化图像传输和网络性能,达到最大帧率
网络·人工智能·数码相机·opencv·计算机视觉·c#
goomind2 小时前
Transformer之Decoder
人工智能·深度学习·llm·nlp·transformer
BTColdman12 小时前
Plume :RWAfi 叙事引领者,全新加密时代的新蓝筹生态
人工智能·区块链