【darknet源码解析-27】l2norm_layer.h 与 l2norm_layer.c 解析

本系列为darknet源码解析,本次解析为src/l2norm_layer.h 和 src/l2norm_layer.c 两个,l2norm_layer主要是完成在每个batch对每个通道进行l2标准化操作;

正向传播:

y_i=\frac{x_i}{\sqrt{\sum_{i=1}^{D}x_i^2}}

反向传播:

\frac{\partial y_j}{\partial x_i}=\frac{\partial }{\partial x_i}\left [ x_j \left( \sum_{k=1}^{D}x_k^2 \right)^{- \frac{1}{2}} \right ]

       =\frac{\partial x_j}{\partial x_i} \left( \sum_{k=1}^{D}x_k^2 \right)^{- \frac{1}{2}} - x_j \left( \sum_{k=1}^{D}x_k^2 \right)^{- \frac{3}{2}}\sum_{k=1}^{D}x_k\frac{\partial x_k}{\partial x_i}

       =\delta_{ij}\left( \sum_{k=1}^{D}x_k^2 \right)^{- \frac{1}{2}}-x_j\left( \sum_{k=1}^{D}x_k^2 \right)^{- \frac{3}{2}}x_i

       =\left( \sum_{k=1}^{D}x_k^2 \right)^{- \frac{1}{2}} \left( \delta_{ij}-y_jy_i \right )

如果i=j,则\delta_{ij}=1, 否则 \delta_{ij}=0,这与源码上的反传存在差入;

l2norm_layer.h的详细定义如下:

#ifndef L2NORM_LAYER_H
#define L2NORM_LAYER_H
#include "layer.h"
#include "network.h"

// 构建l2标准化层
layer make_l2norm_layer(int batch, int inputs);
// l2标准化层的前向,反向传播函数
void forward_l2norm_layer(const layer l, network net);
void backward_l2norm_layer(const layer l, network net);

#ifdef GPU
void forward_l2norm_layer_gpu(const layer l, network net);
void backward_l2norm_layer_gpu(const layer l, network net);
#endif

#endif

l2norm_layer.c 的详细解析

#include "l2norm_layer.h"
#include "activations.h"
#include "blas.h"
#include "cuda.h"

#include <float.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>

/**
 * 构造l2标准化层
 * @param batch
 * @param inputs
 * @return
 */
layer make_l2norm_layer(int batch, int inputs)
{
    fprintf(stderr, "l2norm                                         %4d\n",  inputs);
    layer l = {0};
    l.type = L2NORM; // 层类别
    l.batch = batch; // 一个batch包含图片的张数
    l.inputs = inputs; // l2norm_layer层一张输入图片元素的个数
    l.outputs = inputs; // l2norm_layer层对应输入图片的输出元素的个数,
    l.output = calloc(inputs*batch, sizeof(float)); // l2norm_layer 所有输出(包含整个batch的)
    l.scales = calloc(inputs*batch, sizeof(float)); //
    l.delta = calloc(inputs*batch, sizeof(float)); // l2norm_layer 误差项(包含整个batch的)

    l.forward = forward_l2norm_layer; // l2norm_layer 前向传播
    l.backward = backward_l2norm_layer; // l2norm_layer 反向传播
    #ifdef GPU
    l.forward_gpu = forward_l2norm_layer_gpu;
    l.backward_gpu = backward_l2norm_layer_gpu;

    l.output_gpu = cuda_make_array(l.output, inputs*batch); 
    l.scales_gpu = cuda_make_array(l.output, inputs*batch); 
    l.delta_gpu = cuda_make_array(l.delta, inputs*batch); 
    #endif
    return l;
}


// l2normalize_cpu(l.output, l.scales, l.batch, l.out_c, l.out_w*l.out_h);
void l2normalize_cpu(float *x, float *dx, int batch, int filters, int spatial)
{
    int b,f,i;
    for(b = 0; b < batch; ++b){ //遍历每一张图片
        for(i = 0; i < spatial; ++i){ //遍历每一个通道上的所有元素
            float sum = 0;
            for(f = 0; f < filters; ++f){ // 遍历所有通道
                int index = b*filters*spatial + f*spatial + i;
                sum += powf(x[index], 2); // 计算每个batch中,每个像素点所有通道上平方和
            }
            sum = sqrtf(sum);//计算二范数
            for(f = 0; f < filters; ++f){
                int index = b*filters*spatial + f*spatial + i;
                x[index] /= sum; //对每个元素进行l2标准化
                dx[index] = (1 - x[index]) / sum; // 计算反传梯度
            }
        }
    }
}

/**
 * l2norm前向传播函数
 * @param l 当前l2norm层
 * @param net 整个网络
 */
void forward_l2norm_layer(const layer l, network net)
{
    // l.output = net.input 初始化操作
    copy_cpu(l.outputs*l.batch, net.input, 1, l.output, 1);
    l2normalize_cpu(l.output, l.scales, l.batch, l.out_c, l.out_w*l.out_h);
}

void backward_l2norm_layer(const layer l, network net)
{
    // l.delta = l.scales 多出一个l.scales奇葩;
    axpy_cpu(l.inputs*l.batch, 1, l.scales, 1, l.delta, 1);
    // net.data = l.delta
    axpy_cpu(l.inputs*l.batch, 1, l.delta, 1, net.delta, 1);
}

#ifdef GPU

void forward_l2norm_layer_gpu(const layer l, network net)
{
    copy_gpu(l.outputs*l.batch, net.input_gpu, 1, l.output_gpu, 1);
    l2normalize_gpu(l.output_gpu, l.scales_gpu, l.batch, l.out_c, l.out_w*l.out_h);
}

void backward_l2norm_layer_gpu(const layer l, network net)
{
    axpy_gpu(l.batch*l.inputs, 1, l.scales_gpu, 1, l.delta_gpu, 1);
    axpy_gpu(l.batch*l.inputs, 1, l.delta_gpu, 1, net.delta_gpu, 1);
}

#endif

完,

发布了401 篇原创文章 · 获赞 39 · 访问量 45万+

猜你喜欢

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