【darknet源码解析-13】activation_layer.h 和 activation_layer.c 解析

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/caicaiatnbu/article/details/102664528

本系列为darknet源码解析,本次解析src/activation_layer.h 和 src/activation_layer.c 两个,activation_layer 主要用于构建激活函数层,完成激活函数的前向,梯度反向传播。

关于激活函数的一层底层实现,请先阅读【darknet源码解析-07】activations.h 和 activations.c 解析

activation_layer.h 的解析如下:

#ifndef ACTIVATION_LAYER_H
#define ACTIVATION_LAYER_H

#include "activations.h"
#include "layer.h"
#include "network.h"

// 构建激活函数层
layer make_activation_layer(int batch, int inputs, ACTIVATION activation);

// 激活函数层前向传播函数
void forward_activation_layer(layer l, network net);

// 激活函数层反向传播函数
void backward_activation_layer(layer l, network net);

#ifdef GPU
void forward_activation_layer_gpu(layer l, network net);
void backward_activation_layer_gpu(layer l, network net);
#endif

#endif

activation_layer.c 的解析如下:

#include "activation_layer.h"
#include "utils.h"
#include "cuda.h"
#include "blas.h"
#include "gemm.h"

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/**
 * 构建激活函数层
 * @param batch 一个batch包含的图片的张数
 * @param inputs  //
 * @param activation  //激活函数类型
 * @return
 */
layer make_activation_layer(int batch, int inputs, ACTIVATION activation)
{
    layer l = {0};
    l.type = ACTIVE;//层类别

    l.inputs = inputs; //激活函数层一张输入图片中所有元素个数
    l.outputs = inputs; //激活函数层对应一张输入图片的输出元素个数,激活函数层不改变输入输出的个数
    l.batch=batch; //一个batch中图片的张数

    l.output = calloc(batch*inputs, sizeof(float*)); // 激活函数层的所有输出(包含整个batch的)
    l.delta = calloc(batch*inputs, sizeof(float*)); // 激活函数层的误差损失项 (包含整个batch的)

    // 激活函数层的前向,反向传播函数
    l.forward = forward_activation_layer;
    l.backward = backward_activation_layer;
#ifdef GPU
    l.forward_gpu = forward_activation_layer_gpu;
    l.backward_gpu = backward_activation_layer_gpu;

    l.output_gpu = cuda_make_array(l.output, inputs*batch);
    l.delta_gpu = cuda_make_array(l.delta, inputs*batch);
#endif
    l.activation = activation;
    fprintf(stderr, "Activation Layer: %d inputs\n", inputs);
    return l;
}


void copy_cpu(int N, float *X, int INCX, float *Y, int INCY)
{
    int i;
    for(i = 0; i < N; ++i) Y[i*INCY] = X[i*INCX];
}
// 计算激活函数的输出值
void activate_array(float *x, const int n, const ACTIVATION a)
{
    int i;
    for(i = 0; i < n; ++i){
        x[i] = activate(x[i], a); // 调用不同的激活函数类型,调用不同的激活函数处理输入
    }
}


/**
 * 激活函数层前向传播函数
 * @param l 当前激活函数层
 * @param net 整个网络
 */
void forward_activation_layer(layer l, network net)
{
    // l.output = net.input
    copy_cpu(l.outputs*l.batch, net.input, 1, l.output, 1);
    // 计算输入经过激活函数的输出值
    activate_array(l.output, l.outputs*l.batch, l.activation);
}

// 计算激活函数对加权输入的导数,并乘以delta,得到当前层最终的误差项delta
void gradient_array(const float *x, const int n, const ACTIVATION a, float *delta)
{
    int i;
    for(i = 0; i < n; ++i){
        delta[i] *= gradient(x[i], a);
    }
}
/**
 * 激活函数层反向传播函数
 * @param l 当前激活函数层
 * @param net 整个网络
 */
void backward_activation_layer(layer l, network net)
{
    // 计算激活函数对加权输入的导数,并乘以delta,得到当前层最终的误差项delta
    gradient_array(l.output, l.outputs*l.batch, l.activation, l.delta);
    // net.delta = l.delta 误差项向前一层传播,存入中转位置 net.delta
    copy_cpu(l.outputs*l.batch, l.delta, 1, net.delta, 1);
}

#ifdef GPU

void forward_activation_layer_gpu(layer l, network net)
{
    copy_gpu(l.outputs*l.batch, net.input_gpu, 1, l.output_gpu, 1);
    activate_array_gpu(l.output_gpu, l.outputs*l.batch, l.activation);
}

void backward_activation_layer_gpu(layer l, network net)
{
    gradient_array_gpu(l.output_gpu, l.outputs*l.batch, l.activation, l.delta_gpu);
    copy_gpu(l.outputs*l.batch, l.delta_gpu, 1, net.delta_gpu, 1);
}
#endif

完,

猜你喜欢

转载自blog.csdn.net/caicaiatnbu/article/details/102664528
今日推荐