
Date: 04/01/2018
一般的神经网络课程在讲述BP算法的时候都会用sigmoid 函数来作为最后一层的激活函数来实现二分类,这是因为其sigmoid求导的便利,非常适合用来讲课(吴大大的课也是如此)。
但是对于多分类的问题很多小伙伴表示喜欢直接调库。其实了解softmax反向传播原理,或者可以自己手推一遍softmax的BP算法,才能彰显一个AI从业人员的内功。
此文会通过一个案例为大家一步一步讲解softmax 反向传播的多个知识点,只要仔细看完此文你会对整个流程豁然开朗。
现有如下的分类问题,可以通过动物的4个特征来区分此动物到底是什么种类(猫,狗,人 3个类别)
我们可以建立如下NN模型来解决这个问题:
在开始讲解之前,首先定义一下此文的统一符号命名,(很重要)
红色的是Input 简写为
蓝色的是Output 简写为 O
红色和蓝色之间的是权重矩阵 简写为 W
绿色的是Output经过Softmax之后的结果 简写为 yhat
1 、正向传播:
O = X W
yhat = Softmax(O)
此时softmax 有三个神经元输出 m = 3
重要 :
X (Shape 为(1,4)的向量)
W (Shape为(4,3)的矩阵)
yhat (Shape 为(1,3)的向量)
2、反向传播
1) 求损失
因为是分类问题,我们采用交叉熵作为 loss function(关于为什么交叉熵可以作为损失函数我会在后期写一篇文章进行介绍,敬请期待), 如下:
2) 求梯度
我先给出梯度公式也就是项目中的error-term :
− x⋅( yhat − y) **
想必各位想知道这个公式到底怎么推导得到的呢?
接下来我会讲解此文的重点
重要 求权重的梯度需要运用 链式求导法则 ,如下:
我们来分别计算后面的三项:
第一项:
第二项:
稍微有点复杂。
为什么yhat下标为i 而O下标为j 呢?
这是由于softmax 函数的分母有多个输出,但是针对yhati 需要计算所有的softmax
由于softmax有多个输出,所以需要考虑 i = j 与 i != j 两种情形。
当 i != j 时:
当 i = j 时:
将 j 替换为 i如下
第三项:
第三项非常简单,我们先来算前两项
到这里别忘了 我们经过softmax 的输出只有一个类别也就是 yi = 1, 其他的都等于0
最终我们就得到了结果:
但是Error - term 为 − x⋅( yhat − y) **
这里为什么有个负号?
是因为模型应该朝着负梯度的方向优化,所以加了一个负号。
到此softmax 的正向与反向传播都讲清楚了,欢迎支持 《原理就是这么简单系列》
使用pytorch框架进行神经网络训练时,涉及到分类问题,就需要使用softmax函数,这里以二分类为例,介绍nn.Softmax()函数中,参数的含义。
1. 新建一个2x2大小的张量,一行理解成一个样本经过前面网络计算后的输出(1x2),则batch_size是2。
import numpy as np
import torch
import torch.nn as nn
a = np.array([[1.5, 6.7],[6.8, 3.4]])
b = torch.from_numpy(a)
2. 下面调用nn.Softmax(dim),dim分别为0,1,看看结果是什么样子
f = nn.Softmax(dim = 0)
c = f(b)
结果: tensor([[0.0050, 0.9644], [0.9950, 0.0356]], dtype=torch.float64)
可以发现,是每一列和为1.
f = nn.Softmax(dim = 1)
结果:tensor([[0.0055, 0.9945], [0.9677, 0.0323]], dtype=torch.float64)
可以发现是每一行和为1
所以,当nn.Softmax的输入是一个二维张量时,其参数dim = 0,是让列之和为1;dim = 1,是让行之和为1。
若nn.Softmax的输入是三维张量时,dim的取值就变成了0,1,2,那又是代表什么意思呢,看下面的例子。
a = np.array([[[1.5, 6.7, 2.4],
[6.8, 3.4, 9.3]],
[[3.1, 6.5, 1.9],
[8.9, 1.2, 2.5]]])
我们把a换成一个三维数组,大小是2x2x3,可以看成是2个2x3大小的输入。
这时,我们定义Softmax函数的dim为0,则结果是:
tensor([[[0.1680, 0.5498, 0.6225],
[0.1091, 0.9002, 0.9989]],
[[0.8320, 0.4502, 0.3775],
[0.8909, 0.0998, 0.0011]]], dtype=torch.float64)
可以发现,0.1680+0.8320 = 1, 0.5498+0.4502 = 1,即dim = 0,是让两个2x3数据的对应位置和为1.
使dim=1,结果是:
tensor([[[0.0050, 0.9644, 0.0010],
[0.9950, 0.0356, 0.9990]],
[[0.0030, 0.9950, 0.3543],
[0.9970, 0.0050, 0.6457]]], dtype=torch.float64)
可以发现,0.0050+0.9950 = 1,0.9644+0.0356 = 1,即dim = 1,是让张量每个2x3数据自己的列之和为1.
使dim=2,就是让张量每个2x3数据自己的行之和为1.
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)