本系列爲darknet源碼解析,本次解析爲src/l2norm_layer.h 和 src/l2norm_layer.c 兩個,l2norm_layer主要是完成在每個batch對每個通道進行l2標準化操作;
正向傳播:
反向傳播:
如果,則, 否則 ,這與源碼上的反傳存在差入;
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
完,