天天看點

【darknet源碼解析-16】logistic_layer.h 和 logistic_layer.c 解析

本系列為darknet源碼解析,本次解析src/logistic_layer.h 與 src/logistic_layer.c 兩個。logistic_layer主要完成了邏輯回歸。

在這裡,我們推導一下梯度反傳,詳細請參看李航 《統計學習方法》一書。

設:

【darknet源碼解析-16】logistic_layer.h 和 logistic_layer.c 解析

似然函數為:

【darknet源碼解析-16】logistic_layer.h 和 logistic_layer.c 解析

對數似然函數為:

【darknet源碼解析-16】logistic_layer.h 和 logistic_layer.c 解析

【darknet源碼解析-16】logistic_layer.h 和 logistic_layer.c 解析

求極大值,就得到

【darknet源碼解析-16】logistic_layer.h 和 logistic_layer.c 解析

的估計值。将其前邊添加負号,變為求極小值,就是我們的代價函數

【darknet源碼解析-16】logistic_layer.h 和 logistic_layer.c 解析

求極小值,則乘上一個符号即可

【darknet源碼解析-16】logistic_layer.h 和 logistic_layer.c 解析
【darknet源碼解析-16】logistic_layer.h 和 logistic_layer.c 解析

logistic_layer.h 的解析如下:

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

// 邏輯回歸層構造函數
layer make_logistic_layer(int batch, int inputs);

// 邏輯回歸層前向,反向傳播函數
void forward_logistic_layer(const layer l, network net);
void backward_logistic_layer(const layer l, network net);

#ifdef GPU
void forward_logistic_layer_gpu(const layer l, network net);
void backward_logistic_layer_gpu(const layer l, network net);
#endif

#endif
           

logistic_layer.c 的解析如下:

#include "logistic_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>

/**
 * 建構邏輯回歸層
 * @param batch 一個batch中包含神經元的數量
 * @param inputs 邏輯回歸層一張輸入圖檔的元素個數
 * @return
 */
layer make_logistic_layer(int batch, int inputs)
{
    fprintf(stderr, "logistic x entropy                             %4d\n",  inputs);
    layer l = {0};
    l.type = LOGXENT; // 層類别
    l.batch = batch;  // 一個batch中圖檔的張數
    l.inputs = inputs; // 邏輯回歸層一張輸入圖檔的元素個數
    l.outputs = inputs; // 邏輯回歸層對應輸入圖檔的輸出元素個數,邏輯回歸層不改變輸入輸出的個數
    l.loss = calloc(inputs*batch, sizeof(float)); // 邏輯回歸層所有損失(包含整個batch)
    l.output = calloc(inputs*batch, sizeof(float)); // 邏輯回歸層所有輸出(包含整個batch)
    l.delta = calloc(inputs*batch, sizeof(float)); // 邏輯回歸層誤差項(包含整個batch)
    l.cost = calloc(1, sizeof(float)); // 邏輯回歸層的總損失

    l.forward = forward_logistic_layer; // 邏輯回歸層前向傳播
    l.backward = backward_logistic_layer; // 邏輯回歸層反向傳播
    #ifdef GPU
    l.forward_gpu = forward_logistic_layer_gpu;
    l.backward_gpu = backward_logistic_layer_gpu;

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

// 逐元素做logistic計算
void logistic_x_ent_cpu(int n, float *pred, float *truth, float *delta, float *error)
{
    int i;
    for(i = 0; i < n; ++i){
        float t = truth[i];
        float p = pred[i];
        error[i] = -t*log(p) - (1-t)*log(1-p); // 損失計算
        delta[i] = t-p; // 每一項的誤差項

    }
}
/**
 * 邏輯回歸層前向傳播函數
 * @param l 目前邏輯回歸層
 * @param net 整個網絡
 */
void forward_logistic_layer(const layer l, network net)
{
    // l.output = net.input
    copy_cpu(l.outputs*l.batch, net.input, 1, l.output, 1);
    // 利用sigmoid激活函數處理
    activate_array(l.output, l.outputs*l.batch, LOGISTIC);
    if(net.truth){
        logistic_x_ent_cpu(l.batch*l.inputs, l.output, net.truth, l.delta, l.loss); // 逐元素做logistic計算
        l.cost[0] = sum_array(l.loss, l.batch*l.inputs); // 計算目前邏輯回歸層損失總和
    }
}

/**
 * 邏輯回歸層反向傳播函數
 * @param l 目前邏輯回歸層
 * @param net 整個網絡
 */
void backward_logistic_layer(const layer l, network net)
{
    // net.delta = l.delta
    axpy_cpu(l.inputs*l.batch, 1, l.delta, 1, net.delta, 1);
}

#ifdef GPU

void forward_logistic_layer_gpu(const 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, LOGISTIC);
    if(net.truth){
        logistic_x_ent_gpu(l.batch*l.inputs, l.output_gpu, net.truth_gpu, l.delta_gpu, l.loss_gpu);
        cuda_pull_array(l.loss_gpu, l.loss, l.batch*l.inputs);
        l.cost[0] = sum_array(l.loss, l.batch*l.inputs);
    }
}

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

#endif
           

 ,