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

本系列为darknet源码解析,本次解析src/logistic_layer.h 与 src/logistic_layer.c 两个。logistic_layer主要完成了逻辑回归。

在这里,我们推导一下梯度反传,详细请参看李航 《统计学习方法》一书。

设: P(Y=1|x)=\pi (x),P(Y=0|x)=1-\pi (x)

似然函数为:\prod_{i=1}^{N}\left [ \pi (x_i) \right ]^{y_i} \left[ 1 - \pi (x) \right ]^{1-y_i}

对数似然函数为:L(w)= \sum _{i=1}^{N} \left [y_i \log\pi (x_i)+(1-y_i)\log(1- \pi(x_i)) \right ] = \sum_{i=1}^{N} \left [ y_{i} \log\frac{\pi(x_i)}{1-\pi(x_i)} + \log(1-\pi(x_i)) \right ] = \sum _{i=1}^{N} \left[ y_i(w\cdot x_i)-\log (1+exp(w \cdot x_i)) \right ]

L(w)求极大值,就得到w的估计值。将其前边添加负号,变为求极小值,就是我们的代价函数

\frac{\partial L(w)}{\partial w}=\frac{\sum _{i=1}^{N} \left[ y_i(w\cdot x_i)-\log (1+exp(w \cdot x_i)) \right ]}{\partial w}=x_i(y_i-\pi(x_i))求极小值,则乘上一个符号即可

\frac{\partial y_i(w\cdot x_i)}{\partial w}=y_ix_i

\frac{\partial \log(1+exp(w\cdot x_i))}{\partial w} =\frac{1}{1+exp(w\cdot x_i)}\frac{\partial exp(w\cdot x_i)}{\partial w}=\frac{x_i\cdot exp(w\cdot x_i)}{1+exp(w\cdot x_i)}=x_i\cdot \pi(x_i)

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

 ,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值