拟合非线性函数。
当目标函数是非线性时,比如拟合二次函数,神经网络需要引如激活函数。激活函数是用来加入非线性因素的,解决线性模型所不能解决的问题。
Sigmoid函数时使用范围最广的一类非线性激活函数,具有指数函数的形状,它在物理意义上最为接近生物神经元。其自身的缺陷,最明显的就是饱和性。从函数图可以看到,其两侧导数逐渐趋近于0,杀死梯度。
Sigmoid优点:
这应该是神经网络中使用最频繁的激励函数了,它把一个实数(输入的连续实值)压缩到0到1之间,当输入的数字非常大的时候,结果会接近1,当输入非常大的负数时,则会得到接近0的结果。在早期的神经网络中使用地非常多,因为它很好地解释了神经元受到刺激后是否被激活和向后传递的场景(0:几乎没有被激活;1:完全被激活)。
Sigmoid缺点:
不过近几年在深度学习的应用中比较少见到它的身影,因为使用Sigmoid函数容易出现梯度弥散或者梯度饱和。当神经网络的层数很多时,如果每一层的激活函数都采用Sigmoid函数的话,就会产生梯度弥散和梯度爆炸的问题,其中梯度爆炸发生的概率非常小,而梯度消失发生的概率比较大。
tanh是双曲函数中的一个,tanh() 为双曲正切,关于原点中心对称。
正切函数时非常常见的激活函数,与Sigmoid函数相比,它的输出均值是0,使得其收敛速度要比Sigmoid快,减少迭代次数。相对于Sigmoid的好处是它的输出的均值为0,克服了第二点缺点。但是当饱和的时候还是会杀死梯度。
在神经网络的应用中,tanh通常要优于Sigmoid的,因为 tanh的输出在 -1~1之间,均值为0,更方便下一层网络的学习。但是有一个例外,如果做二分类,输出层可以使用 Sigmoid,因为它可以算出属于某一类的概率。
针对Sigmoid函数和tanh的缺点,提出ReLU函数。
线性整流函数(Rectified Linear Unit, ReLU),又称修正线性单元,是一种人工神经网络中常用的激活函数(activation function),通常指代以斜坡函数及其变种为代表的非线性函数。
ReLU优点:
ReLU缺点:
Leaky ReLU解决了ReLU会杀死一部分神经元的情况。Leaky ReLU 是给所有负值赋予一个非零斜率。Leaky ReLU 激活函数是在声学模型(2013)中首次提出。
理论上来说,Leaky ReLU 有ReLU的所有优点,外加不会有 Dead ReLU 问题,但是在实际操作当中,并没有完全证明 Leaky ReLU 总是好于 ReLU。
Leaky ReLU 主要是为了避免梯度消失,当神经元处于非激活状态时,允许一个非0的梯度存在,这样不会出现梯度消失,收敛速度快。他的优缺点和ReLU类似。
ReLU 在 x > 0 的区域使用 x 进行线性激活,有可能造成激活后的值太大,影响模型的稳定性,为抵消 ReLU激活函数的线性增长部分,可以使用ReLU6函数。
ReLU6 就是普通的 ReLU,但是限制最大输出值为6(对输出值做 clip),这是为了在移动端设备 float16的低精度的时候,也能够有很好的数值分辨率,如果对ReLU的激活范围不加限制,输出范围为0到正无穷,如果激活值非常大,分布在一个很大的范围内,则低精度的 float16 无法很好地精确描述如此大范围的数值,带来精度损失。
拟合目标函数 y=x^2 + x + 1
import numpy as np
import paddle
import paddle.nn as nn
import paddle.nn.functional as F
from paddle.io import DataLoader, Dataset
import matplotlib.pyplot as plt
# 模拟数据
x = np.array([np.random.randn() for x in range(100)])
y = np.array([i * i + i + 1 for i in x])
# 定义数据集
class CurDataSet(Dataset):
def __init__(self, x, y):
self.x = x
self.y = y
def __getitem__(self, idx):
data = paddle.to_tensor(self.x[idx], dtype='float32')
label = paddle.to_tensor(self.y[idx], dtype='float32')
return data, label
def __len__(self):
return len(self.x)
# 定义网络
layer_num = 32
class CurNet(nn.Layer):
def __init__(self):
super(CurNet, self).__init__()
self.fc1 = nn.Linear(1, layer_num)
self.fc2 = nn.Linear(layer_num, 1)
self.reu = nn.ReLU()
def forward(self, inputs):
x = self.fc1(inputs)
x = F.relu(x)
x = self.fc2(x)
return x
net = CurNet()
opt = paddle.optimizer.Adam(learning_rate=1e-2,
beta1=0.8,
parameters=net.parameters())
dataset = CurDataSet(x, y)
loader = DataLoader(dataset,
shuffle=True,
drop_last=True,
batch_size= 20)
# 开始训练
net.train()
for e in range(100):
for i, (data, label) in enumerate(loader()):
out = net(data)
loss = nn.functional.mse_loss(out, label)
loss = paddle.mean(loss)
loss.backward()
opt.step()
opt.clear_grad()
print("Epoch {} batch {}: loss = {}".format(
e, i, np.mean(loss.numpy())))
# 开始评估
net.eval()
plt.scatter(x, y, color='blue', label="act")
x = sorted(x)
z = np.array([net(paddle.to_tensor(i)).numpy()[0] for i in x])
plt.plot(x, z, color='red', label="eval")
plt.legend()
plt.show()
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。