[深度学习]激活函数(Sigmoid等)、前向传播、反向传播和梯度优化;optimizer.zero_grad(), loss.backward(), optimizer.step()的作用及原理

用Matt Mazur的例子,来简单告诉读者推导过程吧(其实就是链式)!

在这里插入图片描述

先初始化权重和偏置量,得到如下效果:

在这里插入图片描述

一、激活函数

在这里插入图片描述

1.1 什么是激活函数?

激活函数可以分为线性激活函数(线性方程控制输入到输出的映射,如f(x)=x等)以及非线性激活函数(非线性方程控制输入到输出的映射,比如Sigmoid、Tanh、ReLU、LReLU、PReLU、Swish 等)

激活函数是向神经网络中引入非线性因素,通过激活函数神经网络就可以拟合各种曲线。激活函数又可以分为饱和激活函数(Saturated Neurons)和非饱和函数(One-sided Saturations)。Sigmoid和Tanh是饱和激活函数而ReLU以及其变种为非饱和激活函数。非饱和激活函数主要有如下优势:

  1. 非饱和激活函数可以解决梯度消失问题。
  2. 非饱和激活函数可以加速收敛。

在这里插入图片描述

1.2 常见的激活函数

1.2.1 Sigmoid函数

S i g m o i d 函 数 也 叫 L o g i s t i c 函 数 \color{red}{Sigmoid函数也叫Logistic函数} SigmoidLogistic,用于隐层神经元输出,取值范围为(0,1),它可以将一个实数映射到(0,1)的区间,可以用来做二分类。在特征相差比较复杂或是相差不是特别大时效果比较好。sigmoid是一个十分常见的激活函数,函数的表达式如下:
在这里插入图片描述
图像类似一个S形曲线:
在这里插入图片描述

  • Sigmoid 函数的输出范围是 0 到 1。由于输出值限定在 0 到1,因此它对每个神经元的输出进行了归一化;
  • 函数是可微的。这意味着可以找到任意两个点的 sigmoid 曲线的斜率;
  • 但是Sigmoid 函数趋近 0 和 1 的时候变化率会变得平坦,也就是说,Sigmoid 的梯度趋近于 0。神经网络使用 Sigmoid 激活函数进行反向传播时,输出接近 0 或 1 的神经元其梯度趋近于 0。这些神经元叫作饱和神经元。因此,这些神经元的权重不会更新。此外,与此类神经元相连的神经元的权重也更新得很慢。该问题叫作 梯 度 消 失 \color{red}{梯度消失}

1.2.2 ReLU激活函数

ReLU函数又称为修正线性单元(Rectified Linear Unit),是一种分段线性函数,其弥补了sigmoid函数以及tanh函数的梯度消失问题,在目前的深度神经网络中被广泛使用。ReLU函数本质上是一个斜坡(ramp)函数,公式及函数图像如下:
在这里插入图片描述
图像:
在这里插入图片描述

  • 当输入为正时,导数为1,一定程度上改善了梯度消失问题,加速梯度下降的收敛速度;
  • 计算速度快得多。ReLU 函数中只存在线性关系,因此它的计算速度比 sigmoid 和 tanh 更快。
    被认为具有生物学合理性(Biological Plausibility),比如单侧抑制、宽兴奋边界(即兴奋程度可以非常高)

1.2.3 Softmax激活函数

Softmax 是用于多类分类问题的激活函数,在多类分类问题中,超过两个类标签则需要类成员关系。对于长度为 K 的任意实向量,Softmax 可以将其压缩为长度为 K,值在(0,1)范围内,并且向量中元素的总和为 1 的实向量。函数表达式如下:
在这里插入图片描述
图像:
在这里插入图片描述
作用示例: 一 般 用 来 放 在 网 络 最 后 输 出 各 类 别 概 率 值 \color{red}{一般用来放在网络最后输出各类别概率值}
在这里插入图片描述
Softmax 激活函数的不足:

  • 在零点不可微;
  • 负输入的梯度为零,这意味着对于该区域的激活,权重不会在反向传播期间更新,因此会产生永不激活的死亡神经元。

1.2.4 其他激活函数参考深度学习笔记:如何理解激活函数?(附常用激活函数)

二、前向传播推理inference计算示例

  • 计算neth1=w*i+b
  • 通过激活函数计算outh1
  • 计算下一层的neth2、通过下一层的激活函数
  • 计算误差Etotal

在这里插入图片描述
在这里插入图片描述

三、反向传播backward计算示例

  • 链式法则:计算Etotal关于w5的偏导,其实=计算Etotal关于outh1的偏导 * outh1关于neth1的偏导 * neth1关于w5的偏导
  • 分别对应三个函数:误差函数、激活函数、y=w*i+b

在这里插入图片描述
在这里插入图片描述
通过相同的步骤就可以更新所有的w:
在这里插入图片描述
参考

四、梯度优化

4.1 如何最小化一个任意函数?

仔细观察成本函数,其形式为Y=X²。在笛卡尔坐标系中,这是一个抛物线方程,用图形表示如下:
在这里插入图片描述
为了最小化上面的函数,需要找到一个x,函数在该点能产生小值Y,即图中的红点

由于这是一个二维图像,因此很容易找到其最小值,但是在 维 度 比 较 大 \color{red}{维度比较大} 的情况下,情况会更加复杂。对于这种情况,需要设计一种算法来定位最小值,该算法称为梯度下降算法(Gradient Descent)。

梯度下降是优化模型的方法中最流行的算法之一,也是迄今为止优化神经网络的最常用方法。它本质上是一种迭代优化算法,用于查找函数的最小值。

4.2 表示

假设你是沿着下面的图表走,目前位于曲线’绿’点处,而目标是到达最小值,即红点位置,但你是无法看到该最低点。
在这里插入图片描述
可能采取的行动:

  • 可能向上或向下;
  • 如果决定走哪条路,可能会采取更大的步伐或小的步伐来到达目的地;

在下图中,在绿点处绘制切线,如果向上移动,就将远离最小值,反之亦然。此外,切线也能让我们感觉到斜坡的陡峭程度:
在这里插入图片描述
蓝点处的斜率比绿点处的斜率低,这意味着从蓝点到绿点所需的步长要小得多。
参考:图解梯度下降背后的数学原理

4.3 深度学习中的梯度优化

在机器学习的核心内容就是把数据喂给一个人工设计的模型,然后让模型自动的“学习”,从而优化模型自身的各种参数,最终使得在某一组参数下该模型能够最佳的匹配该学习任务。那么这个“学习”的过程就是机器学习算法的关键。梯度下降法就是实现该“学习”过程的一种最常见的方式,尤其是在深度学习(神经网络)模型中,BP反向传播方法的核心就是对每层的权重参数不断使用梯度下降来进行优化。
在这里插入图片描述
参考:梯度下降法 —— 经典的优化方法

4.4 不同的优化器Optimization(从SGD到Adam至Lookahead…)

4.4.1 随机梯度下降法SGD

批梯度下降法(stochastic gradient descent)是指使用每一条数据来计算梯度值更新参数:
在这里插入图片描述
通常,随机梯度下降法相比于批梯度下降法具有更快的速度,可用于在线学习,SGD以高方差频繁地更新,因此容易出现下列剧烈波动的情况。

4.4.2 其他优化器详解参考史上最详细的梯度下降优化算法介绍(从SGD到Adam至Lookahead)

五、理解optimizer.zero_grad(), loss.backward(), optimizer.step()的作用及原理

在用pytorch训练模型时,通常会在遍历epochs的过程中依次用到optimizer.zero_grad(),loss.backward()和optimizer.step()三个函数,如下所示:

model = MyModel()
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.001, momentum=0.9, weight_decay=1e-4)
 
for epoch in range(1, epochs):
    for i, (inputs, labels) in enumerate(train_loader):
        output= model(inputs)
        loss = criterion(output, labels)
        
        # compute gradient and do SGD step
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

总得来说,在学习pytorch的时候注意到,对于每个batch大都执行了这三种操作。这三个函数的作用是

  • 先将每一个batsize的梯度归零(optimizer.zero_grad()),
  • 然后反向传播计算得到 l o s s 关 于 每 个 参 数 的 梯 度 值 \color{red}{loss关于每个参数的梯度值} loss(loss.backward())【此处和具体的loss值无关,和其梯度有关】,
  • 最后通过梯度下降执行一步参数更新(optimizer.step())

参考:理解optimizer.zero_grad(), loss.backward(), optimizer.step()的作用及原理
参考:[pytorch] torch代码解析 为什么要使用optimizer.zero_grad()

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
import torchimport torch.nn as nnimport torch.optim as optimimport numpy as np# 定义视频特征提取模型class VideoFeatureExtractor(nn.Module): def __init__(self): super(VideoFeatureExtractor, self).__init__() self.conv1 = nn.Conv2d(3, 16, kernel_size=3, stride=1, padding=1) self.conv2 = nn.Conv2d(16, 32, kernel_size=3, stride=1, padding=1) self.pool = nn.MaxPool2d(kernel_size=2, stride=2) def forward(self, x): x = self.pool(torch.relu(self.conv1(x))) x = self.pool(torch.relu(self.conv2(x))) x = x.view(-1, 32 * 8 * 8) return x# 定义推荐模型class VideoRecommendationModel(nn.Module): def __init__(self, num_videos, embedding_dim): super(VideoRecommendationModel, self).__init__() self.video_embedding = nn.Embedding(num_videos, embedding_dim) self.user_embedding = nn.Embedding(num_users, embedding_dim) self.fc1 = nn.Linear(2 * embedding_dim, 64) self.fc2 = nn.Linear(64, 1) def forward(self, user_ids, video_ids): user_embed = self.user_embedding(user_ids) video_embed = self.video_embedding(video_ids) x = torch.cat([user_embed, video_embed], dim=1) x = torch.relu(self.fc1(x)) x = self.fc2(x) return torch.sigmoid(x)# 加载数据data = np.load('video_data.npy')num_users, num_videos, embedding_dim = data.shapetrain_data = torch.tensor(data[:int(0.8 * num_users)])test_data = torch.tensor(data[int(0.8 * num_users):])# 定义模型和优化器feature_extractor = VideoFeatureExtractor()recommendation_model = VideoRecommendationModel(num_videos, embedding_dim)optimizer = optim.Adam(recommendation_model.parameters())# 训练模型for epoch in range(10): for user_ids, video_ids, ratings in train_data: optimizer.zero_grad() video_features = feature_extractor(video_ids) ratings_pred = recommendation_model(user_ids, video_ids) loss = nn.BCELoss()(ratings_pred, ratings) loss.backward() optimizer.step() # 计算测试集准确率 test_ratings_pred = recommendation_model(test_data[:, 0], test_data[:, 1]) test_loss = nn.BCELoss()(test_ratings_pred, test_data[:, 2]) test_accuracy = ((test_ratings_pred > 0.5).float() == test_data[:, 2]).float().mean() print('Epoch %d: Test Loss %.4f, Test Accuracy %.4f' % (epoch, test_loss.item(), test_accuracy.item()))解释每一行代码
05-22
1. `import torch`: 导入 PyTorch 模块 2. `import torch.nn as nn`: 导入 PyTorch 中的神经网络模块 3. `import torch.optim as optim`: 导入 PyTorch 中的优化器模块 4. `import numpy as np`: 导入 NumPy 模块,并将其重命名为 np 5. `class VideoFeatureExtractor(nn.Module):`:定义视频特征提取模型,继承自 nn.Module 6. `def __init__(self):`:定义初始化函数,初始化视频特征提取模型中的卷积层和池化层 7. `super(VideoFeatureExtractor, self).__init__()`: 调用父类的初始化函数 8. `self.conv1 = nn.Conv2d(3, 16, kernel_size=3, stride=1, padding=1)`: 定义一个 3 x 3 的卷积层,输入通道数为 3 ,输出通道数为 16,卷积核大小为 3,步长为 1,填充为 1 9. `self.conv2 = nn.Conv2d(16, 32, kernel_size=3, stride=1, padding=1)`: 定义一个 3 x 3 的卷积层,输入通道数为 16 ,输出通道数为 32,卷积核大小为 3,步长为 1,填充为 1 10. `self.pool = nn.MaxPool2d(kernel_size=2, stride=2)`: 定义一个大小为 2x2 的最大池化层 11. `def forward(self, x):`: 定义前向传播函数,将输入 x 经过卷积层和池化层后展平输出 12. `x = self.pool(torch.relu(self.conv1(x)))`: 将输入 x 经过第一层卷积层、ReLU 激活函数和最大池化层 13. `x = self.pool(torch.relu(self.conv2(x)))`: 将输入 x 经过第二层卷积层、ReLU 激活函数和最大池化层 14. `x = x.view(-1, 32 * 8 * 8)`: 将输出结果展平为一维向量,大小为 32*8*8 15. `return x`: 返回输出结果 x 16. `class VideoRecommendationModel(nn.Module):`:定义推荐模型,继承自 nn.Module 17. `def __init__(self, num_videos, embedding_dim):`:定义初始化函数,初始化推荐模型中的用户嵌入层、视频嵌入层和全连接层 18. `super(VideoRecommendationModel, self).__init__()`: 调用父类的初始化函数 19. `self.video_embedding = nn.Embedding(num_videos, embedding_dim)`: 定义视频嵌入层,输入维度为 num_videos,输出维度为 embedding_dim 20. `self.user_embedding = nn.Embedding(num_users, embedding_dim)`: 定义用户嵌入层,输入维度为 num_users,输出维度为 embedding_dim 21. `self.fc1 = nn.Linear(2 * embedding_dim, 64)`: 定义一个全连接层,输入维度为 2*embedding_dim,输出维度为 64 22. `self.fc2 = nn.Linear(64, 1)`: 定义一个全连接层,输入维度为 64,输出维度为 1 23. `def forward(self, user_ids, video_ids):`: 定义前向传播函数,将用户和视频 id 经过嵌入层和全连接层计算得到推荐评分 24. `user_embed = self.user_embedding(user_ids)`: 将用户 id 经过用户嵌入层得到用户嵌入 25. `video_embed = self.video_embedding(video_ids)`: 将视频 id 经过视频嵌入层得到视频嵌入 26. `x = torch.cat([user_embed, video_embed], dim=1)`: 将用户嵌入和视频嵌入拼接起来 27. `x = torch.relu(self.fc1(x))`: 将拼接后的结果经过激活函数和全连接层 28. `x = self.fc2(x)`: 将全连接层的输出作为推荐评分 29. `return torch.sigmoid(x)`: 将推荐评分经过 sigmoid 函数转换到 [0,1] 区间内 30. `data = np.load('video_data.npy')`: 从文件中读取数据 31. `num_users, num_videos, embedding_dim = data.shape`: 获取数据的形状,即用户数、视频数和嵌入维度 32. `train_data = torch.tensor(data[:int(0.8 * num_users)])`: 将前 80% 的数据作为训练集,并转换为 PyTorch 的 tensor 格式 33. `test_data = torch.tensor(data[int(0.8 * num_users):])`: 将后 20% 的数据作为测试集,并转换为 PyTorch 的 tensor 格式 34. `feature_extractor = VideoFeatureExtractor()`: 创建视频特征提取模型的实例 35. `recommendation_model = VideoRecommendationModel(num_videos, embedding_dim)`: 创建推荐模型的实例 36. `optimizer = optim.Adam(recommendation_model.parameters())`: 创建优化器,使用 Adam 算法优化推荐模型的参数 37. `for epoch in range(10):`: 开始训练,进行 10 轮迭代 38. `for user_ids, video_ids, ratings in train_data:`: 对训练集中的每个样本进行训练 39. `optimizer.zero_grad()`: 将梯度清零 40. `video_features = feature_extractor(video_ids)`: 提取视频特征 41. `ratings_pred = recommendation_model(user_ids, video_ids)`: 通过推荐模型得到预测评分 42. `loss = nn.BCELoss()(ratings_pred, ratings)`: 计算二分类交叉熵损失 43. `loss.backward()`: 反向传播梯度 44. `optimizer.step()`: 更新模型参数 45. `test_ratings_pred = recommendation_model(test_data[:, 0], test_data[:, 1])`: 对测试集进行评分预测 46. `test_loss = nn.BCELoss()(test_ratings_pred, test_data[:, 2])`: 计算测试集上的损失 47. `test_accuracy = ((test_ratings_pred > 0.5).float() == test_data[:, 2]).float().mean()`: 计算测试集上的准确率 48. `print('Epoch %d: Test Loss %.4f, Test Accuracy %.4f' % (epoch, test_loss.item(), test_accuracy.item()))`: 输出每轮迭代的测试集损失和准确率

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值