darknet 源码阅读笔记-01-activation_kernels.cu

目录

1. lhtan_activate_kernel

2. lhtan_gradient_kernel

3. hardtan_activate_kernel

4. linear_activate_kernel

5. logistic_activate_kernel

6. loggy_activate_kernel

7.relu_activate_kernel

8. relu6_activate_kernel

9. elu_activate_kernel

10. selu_activate_kernel

11. relie_activate_kernel

12. ramp_activate_kernel

13. leaky_activate_kernel

 14. tanh_activate_kernel

15. gelu_activate_kernel

16. softplus_kernel

17. plse_activate_kernel

18. sech_gpu

19. activate_kernel

20. gradient_kernel


1. lhtan_activate_kernel

lhtan是light tanh,近似tanh激活函数。

//! __device__ 函数限定符,指定函数在设备端执行。
__device__ float lhtan_activate_kernel(float x)
{
    if(x < 0) return .001*x;
    if(x > 1) return .001*(x-1) + 1;
    return x;
}

红色的是tanh函数,绿色的是lhtan函数,值的范围是(负无穷小,正无穷大),梯度很小,看不出来是无穷大。 

2. lhtan_gradient_kernel

是lhtan_activate_kernel函数的梯度,x<0时,-0.001*x的梯度是0.001,0<=x<=1时,梯度是1.

//! lhtan_activate_kernel的梯度值
__device__ float lhtan_gradient_kernel(float x)
{
    if(x > 0 && x < 1) return 1;
    return .001;
}

3. hardtan_activate_kernel

hard tanh激活函数。

//! hard tanh激活函数
__device__ float hardtan_activate_kernel(float x)
{
    if (x < -1) return -1;
    if (x > 1) return 1;
    return x;
}

红色是tanh正切函数,黑色是hard tanh函数,绿色是hard tanh的梯度函数。 

4. linear_activate_kernel

线性激活函数.

__device__ float linear_activate_kernel(float x){return x;}

5. logistic_activate_kernel

逻辑回归的激活函数,也称sigmoid激活函数,特点是将y值归一化到(0,1)之间。画图工具

__device__ float logistic_activate_kernel(float x){return 1.f/(1.f + expf(-x));}

红色的是sigmoid函数,绿色是其倒数f(x) * (1-f(x)),可以看到x=0时,梯度值最大。

求梯度代码:

__device__ float logistic_gradient_kernel(float x){return (1-x)*x;}  // 这里的x应该是sigmoid的y值

6. loggy_activate_kernel

与上面的sigmoid函数形态类似,不同的是归一化后y范围是(-1,1).

y = 2 / ( 1 + exp(-x) ) - 1.

参考sigmoid函数求导方法,求导y’ =  2*sigmoid(x)(1-sigmoid(x))

紫色是loggy激活函数,红色是其倒数。

__device__ float loggy_activate_kernel(float x){return 2.f/(1.f + expf(-x)) - 1;}  // 范围(-1,1)
__device__ float loggy_gradient_kernel(float x)  // x = 2 / (1+exp(-a)) - 1
{
    float y = (x+1.F)/2.F;  // y =  (2 / (1+exp(-a)) - 1 + 1) / 2 = 1 / (1+exp(-a)) = y,即sigmoid函数。
    return 2*(1-y)*y;  // 
}

7.relu_activate_kernel

常用的relu激活函数。ReLU = max(0, x),小于0的梯度为0.

推荐一个好用的画图工具

__device__ float relu_activate_kernel(float x){return x*(x>0);}
__device__ float relu_gradient_kernel(float x){return (x>0);}

8. relu6_activate_kernel

相对于relu,不止抑制了小于0的值,也抑制了较大的值(大于6的值)。ReLU6=min(6, max(0,x))

__device__ float relu6_activate_kernel(float x) { return min_val_cmp(max_val_cmp(x, 0), 6); }
__device__ float relu6_gradient_kernel(float x) { return (x > 0 && x < 6); }

9. elu_activate_kernel

ELU相对于ReLU的特点是多了个"e",即没有直接丢弃左边小于0的部分,而是用e^x激活。

(1)大于0的部分:(x >= 0)*x,和ReLU一样,不变;

(2)小于0的部分:(x < 0)*(expf(x)-1),即e^x-1;

__device__ float elu_activate_kernel(float x){return (x >= 0)*x + (x < 0)*(expf(x)-1);}
//! x = e^a-1, x'=-e^a = 1+x
__device__ float elu_gradient_kernel(float x){return (x >= 0) + (x < 0)*(x + 1);} // 大于0时,梯度为1,小于0时,梯度为x+1

10. selu_activate_kernel

SELU(the scaled exponential linear units)相对于ELU多了个S,即前面加了大于1的系数。

大于0的部分系数是1.0507;小于0的部分系数是1.0507*1.6732;

__device__ float selu_activate_kernel(float x) { return (x >= 0)*1.0507f*x + (x < 0)*1.0507f*1.6732f*(expf(x) - 1); }
//! x = 1.0507*1.6732*(e^a-1), x' = x(1+b/x)=x+b
__device__ float selu_gradient_kernel(float x) { return (x >= 0)*1.0507f + (x < 0)*(x + 1.0507f*1.6732f); }

蓝色的是ELU, 绿色的是SELU。

11. relie_activate_kernel

 也就是leaky ReLU,相对于ReLU,保留了小于0时的梯度。

__device__ float relie_activate_kernel(float x){return (x>0) ? x : .01f*x;}  // leaky ReLU
__device__ float relie_gradient_kernel(float x){return (x>0) ? 1 : .01f;}

12. ramp_activate_kernel

ramp就是在ReLU+0.1*x

__device__ float ramp_activate_kernel(float x){return x*(x>0)+.1f*x;}  // ReLU + 0.1*x
__device__ float ramp_gradient_kernel(float x){return (x>0)+.1f;}

13. leaky_activate_kernel

相对于ReLU,保留了小于0时的梯度。

__device__ float leaky_activate_kernel(float x){return (x>0) ? x : .1f*x;}  // 和relie_activate_kernel一样。
__device__ float leaky_gradient_kernel(float x){return (x>0) ? 1 : .1f;}

 14. tanh_activate_kernel

tanh激活函数。范围 (-1, 1),相对于前面的loggy_activate_kernel:2.f/(1.f + expf(-x)) - 1,x系数变成了-2,梯度更大。

__device__ float tanh_activate_kernel(float x){return (2/(1 + expf(-2*x)) - 1);}
//! x = 2/(1+exp(-2a)) - 1, x'= (x+1)*2*(1-(x+1)/2) = (x+1)(1-x) = (1-x^2)
__device__ float tanh_gradient_kernel(float x){return 1-x*x;}

红色的是tanh激活函数,绿色的是loggy_activate_kernel,紫色是tanh函数的梯度函数。

15. gelu_activate_kernel

GELU相对于ReLU,越大梯度值越接近1,越小越接近0,没有直接置为0. 范围是(0,无穷大],

__device__ float gelu_activate_kernel(float x){return (0.5*x*(1 + tanhf(0.797885*x + 0.035677*powf(x, 3))));}
__device__ float gelu_gradient_kernel(float x) {
    const float x3 = powf(x, 3);
    return 0.5*tanhf(0.0356774*x3 + 0.797885*x) + (0.0535161*x3 + 0.398942*x) * powf(sech_gpu(0.0356774*x3 + 0.797885*x), 2) + 0.5;
}

16. softplus_kernel

softplus(x) = ln(1+exp(x)),范围(0,无穷大)具体实现如下。

(1)太大的,直接返回;

(2)太小的,返回e^x;

(3)中间的,返回ln(1+exp(x)).

__device__ float softplus_kernel(float x, float threshold = 20) {
    if (x > threshold) return x;                // too large
    else if (x < -threshold) return expf(x);    // too small
    return log1pf(expf(x));  // log1pf(val)返回ln(val+1)
    //return logf(expf(x) + 1);
}

17. plse_activate_kernel

分段线性激活。

__device__ float plse_activate_kernel(float x)
{
    if(x < -4) return .01f * (x + 4);
    if(x > 4)  return .01f * (x - 4) + 1;
    return .125f*x + .5f;
}

18. sech_gpu

__device__ float sech_gpu(float x) { return 2 / (expf(x) + expf(-x)); }

 19. activate_kernel

使用上面定义的激活函数。

/***
* 根据传入的枚举类型,返回的激活值
typedef enum {
LOGISTIC, RELU, RELU6, RELIE, LINEAR, RAMP, TANH, PLSE, REVLEAKY, LEAKY, ELU, LOGGY, STAIR, HARDTAN, LHTAN, SELU, GELU, SWISH, MISH, HARD_MISH, NORM_CHAN, NORM_CHAN_SOFTMAX, NORM_CHAN_SOFTMAX_MAXVAL
}ACTIVATION;
***/
__device__ float activate_kernel(float x, ACTIVATION a)
{
    switch(a){
        case LINEAR:
            return linear_activate_kernel(x);
        case LOGISTIC:
            return logistic_activate_kernel(x);
        case LOGGY:
            return loggy_activate_kernel(x);
        case RELU:
            return relu_activate_kernel(x);
        case RELU6:
            return relu6_activate_kernel(x);
        case ELU:
            return elu_activate_kernel(x);
        case SELU:
            return selu_activate_kernel(x);
        case GELU:
            return gelu_activate_kernel(x);
        case RELIE:
            return relie_activate_kernel(x);
        case RAMP:
            return ramp_activate_kernel(x);
        case LEAKY:
            return leaky_activate_kernel(x);
        case TANH:
            return tanh_activate_kernel(x);
        case PLSE:
            return plse_activate_kernel(x);
        case STAIR:
            return stair_activate_kernel(x);
        case HARDTAN:
            return hardtan_activate_kernel(x);
        case LHTAN:
            return lhtan_activate_kernel(x);
    }
    return 0;
}

20. gradient_kernel

/***
根据不同的激活函数,调用对应的梯度函数
***/
__device__ float gradient_kernel(float x, ACTIVATION a)
{
    switch (a) {
    case LINEAR:
        return linear_gradient_kernel(x);
    case LOGISTIC:
        return logistic_gradient_kernel(x);
    case LOGGY:
        return loggy_gradient_kernel(x);
    case RELU:
        return relu_gradient_kernel(x);
    case RELU6:
        return relu6_gradient_kernel(x);
    case NORM_CHAN:
        return relu_gradient_kernel(x);
    case ELU:
        return elu_gradient_kernel(x);
    case SELU:
        return selu_gradient_kernel(x);
    case GELU:
        return gelu_gradient_kernel(x);
    case RELIE:
        return relie_gradient_kernel(x);
    case RAMP:
        return ramp_gradient_kernel(x);
    case LEAKY:
        return leaky_gradient_kernel(x);
    case TANH:
        return tanh_gradient_kernel(x);
    case PLSE:
        return plse_gradient_kernel(x);
    case STAIR:
        return stair_gradient_kernel(x);
    case HARDTAN:
        return hardtan_gradient_kernel(x);
    case LHTAN:
        return lhtan_gradient_kernel(x);
    }
    return 0;
}

参考源码:https://github.com/pjreddie/darknet

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
需要学习Windows系统YOLOv4的同学请前往《Windows版YOLOv4目标检测实战:原理与源码解析》,课程链接 https://edu.csdn.net/course/detail/29865【为什么要学习这门课】 Linux创始人Linus Torvalds有一句名言:Talk is cheap. Show me the code. 冗谈不够,放码过来!  代码阅读是从基础到提高的必由之路。尤其对深度学习,许多框架隐藏了神经网络底层的实现,只能在上层调包使用,对其内部原理很难认识清晰,不利于进一步优化和创新。YOLOv4是最近推出的基于深度学习的端到端实时目标检测方法。YOLOv4的实现darknet是使用C语言开发的轻型开源深度学习框架,依赖少,可移植性好,可以作为很好的代码阅读案例,让我们深入探究其实现原理。【课程内容与收获】 本课程将解析YOLOv4的实现原理和源码,具体内容包括:- YOLOv4目标检测原理- 神经网络及darknet的C语言实现,尤其是反向传播的梯度求解和误差计算- 代码阅读工具及方法- 深度学习计算的利器:BLAS和GEMM- GPU的CUDA编程方法及在darknet的应用- YOLOv4的程序流程- YOLOv4各层及关键技术的源码解析本课程将提供注释后的darknet源码程序文件。【相关课程】 除本课程《YOLOv4目标检测:原理与源码解析》外,本人推出了有关YOLOv4目标检测的系列课程,包括:《YOLOv4目标检测实战:训练自己的数据集》《YOLOv4-tiny目标检测实战:训练自己的数据集》《YOLOv4目标检测实战:人脸口罩佩戴检测》《YOLOv4目标检测实战:中国交通标志识别》建议先学习一门YOLOv4实战课程,对YOLOv4的使用方法了解以后再学习本课程。【YOLOv4网络模型架构图】 下图由白勇老师绘制  

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mr.Q

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值