本文仅分析了softmax_layer.cpp 和 softmax_loss_layer.cpp两个文件中的forward函数,backward函数有待补充。


1、softmax_layer.cpp

softmax function

设有m个已标记样本,σ(z)=(σ1(z),σ2(z),...,σm(z))\sigma\mathit(z)=(\sigma_1(\mathit{z}),\sigma_2(\mathit{z}),...,\sigma_m(\mathit{z}))定义:

σi(z)=exp(zi)∑mj=1exp(zj),i=1,...,m

\sigma_\mathit{i}(\mathit{z})=\frac{\exp(z_i)}{\sum_{j=1}^m\exp(z_j)},\quad i=1,...,m
其中, σi(z)\sigma_\mathit{i}(\mathit{z})是loss层的输入; zi=WTix+biz_i=W_i^Tx+b_i,表示第i类的线性预测结果, WTiW_i^T为权重, bib_i为偏置值。
带入softmax进行计算其实就是先对每一个ziz_i取exponential变为非负,然后除以所有项之和进行归一化。
在softmax_layer.cpp中,可以将forward函数比较直观的表现为以下形式:

hθ(x(i))=⎡⎣⎢⎢⎢⎢⎢p(y(i)=1|x(i);θ)p(y(i)=2|x(i);θ)⋮p(y(i)=k|x(i);θ)⎤⎦⎥⎥⎥⎥⎥=1∑kl=1eθTjx(i)⎡⎣⎢⎢⎢⎢⎢⎢eθT1x(i)eθT2x(i)⋮eθTkx(i)⎤⎦⎥⎥⎥⎥⎥⎥

h_\theta\left(x^\mathit{(i)}\right)=\left[\begin{matrix}p(y^\mathit{(i)}=1|x^\mathit{(i)};\theta)\\p(y^\mathit{(i)}=2|x^\mathit{(i)};\theta)\\\vdots\\p(y^\mathit{(i)}=k|x^\mathit{(i)};\theta)\end{matrix}\right]=\frac{1}{\sum_{l=1}^ke^\mathit{\theta_j^Tx^\mathit{(i)}}}\left[\begin{matrix}e^\mathit{\theta_\mathsf{1}^Tx^\mathit{(i)}}\\e^\mathit{\theta_\mathsf{2}^Tx^\mathit{(i)}}\\\vdots\\e^\mathit{\theta_\mathsf{k}^Tx^\mathit{(i)}}\end{matrix}\right]
softmax.cppforward函数代码:

template <typename Dtype>
void SoftmaxLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,const vector<Blob<Dtype>*>& top) {const Dtype* bottom_data = bottom[0]->cpu_data();Dtype* top_data = top[0]->mutable_cpu_data();Dtype* scale_data = scale_.mutable_cpu_data();int channels = bottom[0]->shape(softmax_axis_);int dim = bottom[0]->count() / outer_num_;caffe_copy(bottom[0]->count(), bottom_data, top_data);// We need to subtract the max to avoid numerical issues, compute the exp,// and then normalize.for (int i = 0; i < outer_num_; ++i) {// initialize scale_data to the first planecaffe_copy(inner_num_, bottom_data + i * dim, scale_data);for (int j = 0; j < channels; j++) {for (int k = 0; k < inner_num_; k++) {scale_data[k] = std::max(scale_data[k],bottom_data[i * dim + j * inner_num_ + k]);}}// subtractioncaffe_cpu_gemm<Dtype>(CblasNoTrans, CblasNoTrans, channels, inner_num_,1, -1., sum_multiplier_.cpu_data(), scale_data, 1., top_data);// exponentiationcaffe_exp<Dtype>(dim, top_data, top_data);// sum after expcaffe_cpu_gemv<Dtype>(CblasTrans, channels, inner_num_, 1.,top_data, sum_multiplier_.cpu_data(), 0., scale_data);// divisionfor (int j = 0; j < channels; j++) {caffe_div(inner_num_, top_data, scale_data, top_data);top_data += inner_num_;}}
}

代码不多,针对Line 21至Line 32分析如下:
1、//division

top_data=top_data/scale_data;
top_data=top_data+inner_num_;

2、//sum after exp

scale_data=top_data*sum_multiplier_.cpu_data()

分析:求和,每一层各自求和放到scale_data中
3、//exponentiation

top_data=exp(top_data)

分析:比较直观,能看出是在exponentiation。函数caffe_exp()的第一个参数是dim,那么应该是对K维列向量做exp
4、//subtraction

通过矩阵相乘的方式来计算,有channels层的top_data,每层元素减去该层的最大值

2、softmax_loss_layer.cpp

softmax loss function

根据上面讲到的softmax函数,假设x属于第i类,我们要最大似然化σi(z)\sigma_i(z),通常使用negtive log-likelihood ,也就是要最小化−log(oy)-log(o_y)的值。
loss function:

J(θ)=−1m⎡⎣∑i=1m∑j=1k1{y(i)=j}logeθTjx(i)∑kl=1eθTjx(i)⎤⎦

J(\theta)=-\frac{1}{m}\left[\sum_{i=1}^m\sum_{j=1}^k1\{y^\mathit{(i)}=j\}log\frac{e^\mathit{\theta_j^Tx^\mathit{(i)}}}{\sum_{l=1}^ke^\mathit{\theta_j^Tx^\mathit{(i)}}}\right]
其中, 1{y(i)=j}1\{y^\mathit{(i)}=j\}为示性函数。
softmax_loss_layer.cpp中forward函数代码:

template <typename Dtype>
void SoftmaxWithLossLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {// The forward pass computes the softmax prob values.softmax_layer_->Forward(softmax_bottom_vec_, softmax_top_vec_);const Dtype* prob_data = prob_.cpu_data();//定义了一个指针指向最初的可能值const Dtype* label = bottom[1]->cpu_data();//原始的labelint dim = prob_.count() / outer_num_;//输入图像类的个数int count = 0;Dtype loss = 0;for (int i = 0; i < outer_num_; ++i) {//outer_num_=batch_sizefor (int j = 0; j < inner_num_; j++) {//inner_num_的存在可解决多标签问题,对于单一标签问题inner_num_=1const int label_value = static_cast<int>(label[i * inner_num_ + j]);//对于多标签问题还不是很理解,在单一标签问题中inner_num_=1,那么label[i * inner_num_ + j]表示第i * inner_num_ + j个输入图像的标签值,label[i * inner_num_ + j]一定属于[0,输入图像类别数-1]if (has_ignore_label_ && label_value == ignore_label_) {continue;}DCHECK_GE(label_value, 0);DCHECK_LT(label_value, prob_.shape(softmax_axis_));loss -= log(std::max(prob_data[i * dim + label_value * inner_num_ + j],Dtype(FLT_MIN)));//对于单标签问题,每张图像经过计算后都会输出一个dim×1大小的矩阵(列向量),矩阵中的第k个值表示该图像属于第k类的概率;prob_data[i * dim + label_value * inner_num_ + j]表示第i个输入图像属于第label_value的概率。++count;}}if (normalize_) {top[0]->mutable_cpu_data()[0] = loss / count;} else {top[0]->mutable_cpu_data()[0] = loss / outer_num_;}if (top.size() == 2) {top[1]->ShareData(prob_);}
}

caffe源码分析:softmax_layer.cpp softmax_loss_layer.cpp相关推荐

  1. caffe源码分析--SyncedMemory 内存管理机制

    caffe源码分析–SyncedMemory 内存管理机制 ​ SyncedMemory 是caffe中用来管理内存分配和CPU.GPU数据及同步的类,只服务于Blob类.SyncedMemory 对 ...

  2. caffe源码分析-layer

    本文主要分析caffe layer层,主要内容如下: 从整体上说明下caffe的layer层的类别,以及作用 通过proto定义与类Layer简要说明下Layer的核心成员变量; Layer类的核心成 ...

  3. x265源码分析 main函数 x265.cpp

    图片转载于x265源码流程分析_Dillon2015的博客-CSDN博客_x265编码流程 cliopt.prase main ()函数--解析函数参数并进行编码准备工作:x265.cpp (1)Ge ...

  4. 【AI】caffe源码分析(一)

    [一]caffe依赖开源库 [C++]google gflags详解 [C++]google glog详解 [C++]Google Protocol Buffer(protobuf)详解(一) [C+ ...

  5. caffe源码分析:layer.hpp分析

    文件路径:caffe-master_github/include/caffe/ Backward函数: template <typename Dtype> inline void Laye ...

  6. caffe 源码分析:Euclidean loss layer

    最近做项目需要修改Euclidean loss函数,所以就先分析了一下Euclidean loss layer的代码 以gpu版本的为例: 一. 前向函数 template <typename ...

  7. caffe源码分析:blob.hpp分析

    文件路径:caffe-master_github/include/caffe/ 如果想对blob有详细了解,参考Caffe官网教程:http://caffe.berkeleyvision.org/tu ...

  8. Android之vold进程启动源码分析

    1.Vold (Volume Daemon)介绍 vold进程接收来自内核的外部设备消息,用于管理和控制Android平台外部存储设备,包括SD插拨.挂载.卸载.格式化等:当外部设备发生变化时,内核通 ...

  9. 【Android 逆向】整体加固脱壳 ( DEX 优化流程分析 | DexPrepare.cpp 中 dvmOptimizeDexFile() 方法分析 | /bin/dexopt 源码分析 )

    文章目录 前言 一.DexPrepare.cpp 中 dvmOptimizeDexFile() 方法分析 二./bin/dexopt 源码分析 前言 上一篇博客 [Android 逆向]整体加固脱壳 ...

最新文章

  1. 2021年大数据ELK(十九):使用FileBeat采集Kafka日志到Elasticsearch
  2. 022_applescript快速入门教程
  3. 剑指offer 算法 (代码的完整性)
  4. 【ABAP】根据Tcode查找后台IMG路径
  5. python一个富翁试图与陌生人做一笔生意_VB实验报告一
  6. 说说MaxTenuringThreshold这个参数
  7. Jmeter plugins 之 Perfmon Metrics Collector(服务器性能监控)
  8. java中date类型如何赋值_Java 中的类型传递问题解惑
  9. DropBox:机器学习每年可以为我们节省170万的文档预览费用
  10. 2015/10/19总结:ajax传参、jquery.validate自定义日期校验
  11. Navicat工具怎么连接oracle数据库
  12. 拿工资,要做差不多的事
  13. 空号检测和手机在网状态查询的区别
  14. 如何合并excel文件
  15. pc端ui图片尺寸_PC端网页尺寸设计一
  16. 第一节课 opencv图像处理,对图片进行叠加处理
  17. .m3u8视频格式转换
  18. Echarts双Y轴图表处理
  19. 公众号php关键词回复小程序,微信自定义关键词回复信息
  20. 一文搞懂 | ARM微架构的变化

热门文章

  1. 【转】 DOTA2中的伪随机及其lua实现
  2. smarty课程---最最最简单的smarty例子
  3. 用rvest包来抓取Google学术搜索数据
  4. 【转】C#获取电脑客户端IP地址及当前用户名
  5. mysql定时执行存储过程
  6. 网络性能测试工具Iperf上手指南
  7. 基于IPSec的×××配置实验
  8. [翻译]在GridView中插入新记录
  9. NYOJ 709 异形卵
  10. CodeForce 534C Polycarpus' Dice (数学推理)