darknet代码注释--1.激活函数

激活函数

神经网络其实可以简单理解为将各种变量作为输入,然后对每个输入进行加权,但是对于我们想要的结果如果是回归还好,如果是分类,我们想得到的其实就是个概率,但是有时候一些输入是一种异常值(可以对输入进行预处理),可能会导致输出超出我们想要的范围,因此需要激活函数将输出约束到一定的范围
在这里插入图片描述

一下简单记录一下darknet中的激活函数和他们的梯度(倒数),在darknet中是将他们作为静态的内敛函数,这样节省了调用开销

1.linear_activate

线性激活函数,什么也不做,输入等于输出,在darknet中

static inline float linear_activate(float x)
{
	return x;
}

函数图像
在这里插入图片描述

2.logistic_activate

我们叫做sigmoid激活函数,这个函数的图像像是s形,它将输入压缩到[0,1]之间,如果我们想要的结果就是概率的话,这个激活函数就非常适合,他的有点就是连续,方便求导,但是计算量大

static inline float logistic_activate(float x)
{
	return 1./(1. + exp(-x));
}

函数图像
在这里插入图片描述

3.loggy_activate

这个激活函数将结果压缩到了-1,1,如下图蓝色的线
函数方程为

static inline float loggy_activate(float x)
{
	return 2./(1. + exp(-x)) - 1;
}

在这里插入图片描述

4.relu_activate

根据图像就可以看出来,当输入小于0的时候输出0,当x>0的时候原样输出
优点:

  1. 计算量小;
  2. 激活函数导数维持在1,可以有效缓解梯度消失和梯度爆炸问题;
  3. 使用Relu会使部分神经元为0,这样就造成了网络的稀疏性,并且减少了参数之间的相互依赖关系,缓解了过拟合问题的发生。

缺点:输入激活函数值为负数的时候,会使得输出为0,那么这个神经元在后面的训练迭代的梯度就永远是0了(由反向传播公式推导可得),参数w得不到更新,也就是这个神经元死掉了。这种情况在你将学习率设得较大时(网络训练刚开始时)很容易发生(波浪线一不小心就拐到负数区域了,然后就拐不回来了)。

解决办法:一些对Relu的改进,如ELU、PRelu、Leaky ReLU等,给负数区域一个很小的输出,不让其置0,从某种程度上避免了使部分神经元死掉的问题。

static inline float relu_activate(float x)
{
	return x*(x>0);
}

函数图像
在这里插入图片描述

5.elu_activate

上面的relu激活函数在x<0时候,输出0,那么导数就是0,出现梯度消失,为了解决这个现象,elu激活函数在x<0的时候做了指数处理,可以让梯度不为零,继续学习权重
在x>0:输入==输出
在x<0:做指数处理

右侧线性部分使得elu能够缓解梯度消失,而左侧软饱部分能够让ELU对输入变化或噪声更鲁棒。elu的输出均值接近于零

static inline float elu_activate(float x)
{
	return (x >= 0)*x + (x < 0)*(exp(x)-1);
}

函数图像
在这里插入图片描述

6.selu_activate

和上面的elu相比,对输入做了修正,1.0507 是修正系数,如下面蓝色的图像,selu和elu缺点就是在x<0的时候计算量大

static inline float selu_activate(float x)
{
	return (x >= 0)*1.0507*x + (x < 0)*1.0507*1.6732*(exp(x)-1);
}

函数图像
在这里插入图片描述

7.relie_activate

relie激活函数在x<0的时候添加了要给小的梯度,解决x<0的时候梯度为0的情况,

在x>0:输入==输出
在x<0:0.01x

static inline float relie_activate(float x)
{
	return (x>0) ? x : .01*x;
}

在这里插入图片描述

8.ramp_activate

ramp和relie类似,就是在斜率上做了修正

static inline float ramp_activate(float x)
{
	return x*(x>0)+.1*x;
}

函数图像:青色
在这里插入图片描述

9.leaky_activate

可以看出来leaky和relie就是在x<0的时候修正系数不同

static inline float leaky_activate(float x)
{
	return (x>0) ? x : .1*x;
}

函数图像:青色
在这里插入图片描述

10.tanh_activate

tanh是双曲线函数,tanh 是一个双曲正切函数。tanh 函数和 sigmoid 函数的曲线相对相似。但是它比 sigmoid 函数更有一些优势。
首先,当输入较大或较小时,输出几乎是平滑的并且梯度较小,这不利于权重更新。二者的区别在于输出间隔,tanh 的输出间隔为 1,并且整个函数以 0 为中心,比 sigmoid 函数更好;
在 tanh 图中,负输入将被强映射为负,而零输入被映射为接近零。
注意:在一般的二元分类问题中,tanh 函数用于隐藏层,而 sigmoid 函数用于输出层,但这并不是固定的,需要根据特定问题进行调整。

static inline float tanh_activate(float x)
{
	return (exp(2*x)-1)/(exp(2*x)+1);
}

static inline float tanh_activate(float x)
{
	return exp(*x)-exp(*-x)/exp(*x)+exp(*-x);
}


函数图像
红色:sigmoid
青色:对sigmoid做了修正
蓝色:tanh

在这里插入图片描述

11.plse_activate

使用分段函数

static inline float plse_activate(float x)
{
    if(x < -4) return .01 * (x + 4);
    if(x > 4)  return .01 * (x - 4) + 1;
    return .125*x + .5;
}

在这里插入图片描述

12.lhtan_activate

比plse减小了梯度

static inline float lhtan_activate(float x)
{
    if(x < 0) return .001*x;
    if(x > 1) return .001*(x-1) + 1;
    return x;
}

在这里插入图片描述

求导函数

对于求导,也就是梯度,对于线性函数,这个很简单,我们这里主要说明非线性函数,并画出图像

1.lhtan_gradient

2.hardtan_gradient

3.linear_gradient

4.logistic_gradient

5.loggy_gradient

6.stair_gradient

7.relu_gradient

8.elu_gradient

9.selu_gradient

10.relie_gradient

11.ramp_gradient

12.leaky_gradient

13.tanh_gradient

14.plse_gradient

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值