tensorflow2.0实现鸢尾花数据集的分类(3)——激活函数

1.谜题揭晓

在上一篇博客:
tensorflow2.0实现鸢尾花数据集的分类(2)——神经网络搭建
笔者在结尾留了一个问题,今天我们就来解释一下

我们搭建神经网络比较重要的一步是前向传播,这一步少了一点东西,我们是这样做得:

with tf.GradientTape() as tape:
	#前向传播计算 y, y为预测结果
	y = tf.matmul(x_train, w) + b
	# 计算损失函数
	loss = (y - y_train)**2
	loss = tf.reduce_mean(loss, axis=0)

你可能会说,对啊,这没错啊,神经网络模型不就是:y=xw+by = x*w + b,这么做有什么错吗??


那我再举一个例子:如果搭建两层神经网络:
y1=xw1+b1(1)y2=y1w2+b2(2) y_1 = x*w_1 + b_1\qquad(1)\\ y_2 = y_1 * w_2 + b_2\qquad(2)
那么模型的表达力一定会增强吧?!
答案是否定的

将式(1)(1)带入式(2)(2)中,你会发现:
y2=y1w2+b2=(xw1+b1)w2+b2=x(w1w2)+(b1w2+b2) \begin{aligned} y_2 &= y_1 * w_2 + b_2\\ &= ( x*w_1 + b_1) * w_2 + b_2\\ &=x * (w_1 * w_2) + (b_1 * w_2 + b_2) \end{aligned}
这本质上还是我们原来的模型y=xw+by = x*w + b,可以很容易的想到,无论经过多少层神经元,最后的模型依然是y=xw+by = x*w + b,所以模型表达力并不会有很大的提升。


现在终于可以揭晓答案了,原因是,我们的"神经网络"模型,其实仍然是个线性模型,因为无论多少层,其最终化简依然是线性模型!而线性模型的不能够表达非线性的部分

那我们怎样做才能将模型非线性话呢?对的,就是引入非线性的激活函数


2.激活函数特点

早在1943年提出的MP模型 y=f(xw+b)y = f(x*w + b) 中,就已经提出引入非线性函数ff:
在这里插入图片描述
而就是由于非线性函数的加入,使得输出yy不再是输入xx的线性组合,神经网络可以随着层数的增加提示表达力!

我们之前一定听说过,relurelu激活函数和sigmoidsigmoid激活函数,那他们这么有名,是具备了什么优秀的性质呢??

  • 非线性: 只有激活函数非线性时,才不会被单层网络所替代,多层神经网络可逼近所有函数
  • 可微性: 优化器大多用梯度下降更新参数 ,若激活函数不可微,则无法更新参数
  • 单调性: 当激活函数是单调的,能保证单层网络的损失函数是凸函数
  • 近似恒等性: 有f(x)xf(x)\approx x,当参数初始化为随机小值时,神经网络更稳定

在今后的实践中,我们可以通过以上性质来寻找属于自己模型的激活函数!


3.常用激活函数介绍

(1).SigmoidSigmoid函数
  • 表达式:f(x)=11+exf(x)=\frac{1}{1+e^{-x}}
  • tensorflow API :tf.nn.sigmoid(x)
  • 函数图像:
    在这里插入图片描述
  • 导数图像:在这里插入图片描述
  • 重要特点:
  1. sigmoidsigmoid将输入变为0到1的值,相当于对输入进行了归一化
  2. 容易造成梯度消失,因为在更新参数时,需要从输出层到输入层进行链式求导,而我们可以从导数图线看出其导数值的范围是0到0.25,所以在进行链式求导时,需要多个0到0.25的数字相乘,容易造成梯度消失,使得参数无法继续更新(可以看做存在饱和(SaturatedSaturated)现象)
  3. 输出的均值非0,收敛慢,我们希望输出是以0为均值的,而其输出为0到1使得收敛变慢
  4. 存在幂运算,计算复杂度大,训练时间长
(2).TanhTanh函数
  • 表达式:f(x)=1e2x1+e2xf(x)=\frac{1-e^{-2x}}{1+e^{-2x}}
  • tensorflow API :tf.math.tanh(x)
  • 函数图像:
    在这里插入图片描述
  • 导数图像:
  • 重要特点:
  1. 输出均值为0
  2. 仍然易造成梯度消失(可以看做存在饱和现象)
  3. 含有幂运算,训练时间长
(3).relurelu函数
  • 表达式:f(x)=max{x,0}={xx00x<0 \begin{aligned} f(x)&=max\{x, 0\}\\ &=\left\{\begin{matrix} x \qquad x\geqslant 0 \\ 0 \qquad x<0 \end{matrix}\right. \end{aligned}
  • tensorflow API :tf.nn.relu(x)
  • 函数图像:
    在这里插入图片描述
  • 导数图像:
    在这里插入图片描述
  • 重要特点:
  1. 在正区间内解决了梯度消失问题
  2. 计算速度快,只需要解决输入是否大于0
  3. 收敛速度快于sigmoidsigmoidtanhtanh
  4. 输出均值非0
  5. 存在 Dead reluDead\ relu问题,即送入激活函数的特征是负数时,激活函数输出是0,反向传播得到的梯度为0,导致参数无法更新,造成神经元死亡
(4).leaky reluleaky\ relu函数
  • 表达式:f(x)=max{x,ax}={xx0axx<0 \begin{aligned} f(x)&=max\{x, ax\}\\ &=\left\{\begin{matrix} x \qquad x\geqslant 0 \\ ax \qquad x<0 \end{matrix}\right. \end{aligned}
  • tensorflow API :tf.nn.leaky_relu(x)
  • 函数图像:
    在这里插入图片描述
    -导数图像
    在这里插入图片描述
  • 重要特点:
    理论上来讲,Leaky ReLULeaky\ ReLUReLUReLU的所有优点,外加不会有Dead ReLUDead\ ReLU问题,但是在实际操作当 中,并没有完全证明Leaky ReLULeaky\ ReLU总是好于ReLUReLU

4.更改神经网络:

with tf.GradientTape() as tape:
	#前向传播计算 y, y为预测结果
	y = tf.matmul(x_train, w) + b
	y = tf.nn.relu(y)       # <-------------------------在此处加入激活函数即可,没错,就加一句代码
	# 计算损失函数
	loss = (y - y_train)**2
	loss = tf.reduce_mean(loss, axis=0)

加上激活函数,再去训练你的模型试试准确率,应该能达到95%95\%以上


5.感谢在线绘图网站:

https://www.desmos.com/calculator
注:在该网站还可以画分段函数,如绘制relurelu函数:
{x>0} x{x<0} 0 \{x>0\}\ x\\ \{x<0\}\ 0

发布了51 篇原创文章 · 获赞 9 · 访问量 4044
App 阅读领勋章
微信扫码 下载APP
阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 数字20 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览