tiny_cnn源码阅读(2)-激活函数

  • 激活函数概述
    • identiti函数
    • sigmoid函数
    • relu函数
    • leaky_relu
    • elu
    • softmax
    • tanh
    • tanh p1m2
  • 源码阅读
  • 参考

激活函数概述

神经网络都有各个层组成,在不同的层中,用到不同的激活函数。在看layer之前,先了解一下定义的激活函数。
数据”经过一个神经网络时,经过卷积或池化等运算后,最终输出的一个值。这个“输出值”就是经过激活函数计算的来的,反向求导,也是对激活函数来求导的。
激活函数通常有以下性质:
非线性:如果激活函数都为线性,那么神经网络的最终输出都是和输入呈线性关系;显然这不符合事实。
可导性:神经网络的优化都是基于梯度的,求解梯度时需要确保函数可导。
单调性:激活函数是单调的,否则不能保证神经网络抽象的优化问题为凸优化问题了。
输出范围有限:激活函数的输出值的范围是有限时,基于梯度的方法会更加稳定。输入值范围为 (,+) ,如果输出范围不加限制,虽然训练会更加高效,但是learning rate将会更小,且给工程实现带来许多困难。
f(x)x(x0) :当 x0 时,需要满足这个条件。这样权重初始化为很小的值时,训练神经网络会更加高效。否则需要细心设置权重的初始值。

identiti函数

从名字看出,这是个“相等”学习函数,数据通过这个函数不会有任何变化。所以其函数float_t f(const vec_t& v, cnn_size_t i)返回变量的值,求导时导数为1

sigmoid函数

sigmoid函数定义为:

f(x)=1(1+ex)

它是是连续、光滑、严格单调的非线性函数,它把数值(-inf, +inf)映射到了(0 , 1)。它的导数

df(y)=y(1y)

relu函数

relu函数定义为

f(x)=max(0,x)

当信号小于0时,输出为0;信号大于0时,输出值为信号的值。rule函数计算非常简单,只需要一个阀值就可以得到激活值,不用进行复杂的计算。使用SGD时,用rule代替sigmod/tanh的话,收敛速度会快很多。

leaky_relu

leaky_relu定义为:

f(x)={ax,x<0x,x0

使用rule时,如果一个很大的梯度经过relu神经元,那么这个神经元可能不会再对其他数据起作用了,这会造成部分这个神经元“死掉”,使用leaky_relu可以解决这个问题。a的值很小,这样可以保留部分负值信息。
定义为:当x<0时,f(x)=(e^x-x)

elu

elu定义为:

f(x)={a(ex1),x<0x,x0

elu全称为exponential linear unit。

softmax

softmax用来归一化,把输出值归一化为(0,1)之间的值,且总和为1。对于SoftMax输出,可以理解为概率。计算过程为:
1、求出集合中最大的值alpha。
2、使用指数,将数值转换为0-1之间的数exp(v[i]-alpha)。
3、归一化,即将上步求得的数值求和sum,所求结果为exp(v[i]-alpha)/sum。

tanh

tanh的定义为

f(x)=exexex+ex

它的形状和sigmod有点像,但是它是0均值的,取值范围为(-1,1)。

tanh p1m2

这是tanh的变形,定义为:

f(x)=exex+ex

源码阅读

激活函数在tiny-cnn-master/tiny_cnn/activations/activation_function.h中。
首先定义了基类function

class function {
public:
    function() = default;
    function(const function &) = default;
#ifndef CNN_DEFAULT_MOVE_CONSTRUCTOR_UNAVAILABLE
    function(function &&) = default;
#endif
    function &operator =(const function &) = default;
#ifndef CNN_DEFAULT_ASSIGNMENT_OPERATOR_UNAVAILABLE
    function &operator =(function &&) = default;
#endif
    virtual ~function() = default;

    virtual float_t f(const vec_t& v, cnn_size_t index) const = 0;//前向传播

    // dfi/dyi
    virtual float_t df(float_t y) const = 0;//反向求导

    // dfi/dyk (k=0,1,..n)
    virtual vec_t df(const vec_t& y, cnn_size_t i) const { vec_t v(y.size(), 0); v[i] = df(y[i]); return v; }

    // target value range for learning
    virtual std::pair scale() const = 0;//输出值的范围
};

函数float_t f(const vec_t&, cnn_size_t index)为前向传播,float_t df(float_t y)vec_t df(const vec_t& y, cnn_size_t i)为求导,前者是对一个数求导,后者是对容器所有数求导。std::pair scale()是来控制函数输出的范围。
前向传播和反向传播都是虚函数,在其派生类中有实现。

参考

【机器学习】神经网络-激活函数-面面观(Activation Function)

你可能感兴趣的:(tiny_cnn源码阅读)