caffe中softmax loss源码阅读
(1) softmax loss
<1> softmax loss的函数形式为:
(1)
zi为softmax的输入,f(zi)为softmax的输出。
<2> softmax loss对其输入zj求导:
(2)
如果j==k,则zk是变量,否则zj是变量。
和的导数等于导数的和,对和中某个元素求导的话有:
(2) softmax_loss_layer.cpp中的Forward_cpu()函数:
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层的forward函数,得到对应的输出,存到prob_中
softmax_layer_->Forward(softmax_bottom_vec_, softmax_top_vec_);
const Dtype* prob_data = prob_.cpu_data();
//一般loss层有两个输入blob,网络的predict blob(bottom[0])和label blob(bottom[1])
const Dtype* label = bottom[]->cpu_data();
//dim = N*C*H*W / N = C*H*W
int dim = prob_.count() / outer_num_;
//count变量是计算loss时的有效样本数
int count = ;
Dtype loss = ;
for (int i = ; i < outer_num_; ++i) {
for (int j = ; j < inner_num_; j++) {
//读取label
const int label_value = static_cast<int>(label[i * inner_num_ + j]);
//如果该样本的label等于deploy中softmaxWithLoss中设定的参数ignore_label_,则该样本不参与前向和后向计算
if (has_ignore_label_ && label_value == ignore_label_) {
continue;
}
//判断label_value是否大于等于0
DCHECK_GE(label_value, );
//判断label_value是否小于prob_.shape(softmax_axis_)=C
DCHECK_LT(label_value, prob_.shape(softmax_axis_));
//对于softmax的输出channel,计算label_value索引对应的channel中prob的log.对应公式(1)
loss -= log(std::max(prob_data[i * dim + label_value * inner_num_ + j],
Dtype(FLT_MIN)));
//有效样本数加一
++count;
}
}
//最终在训练日志中显示的loss为计算的总loss除以有效样本数
top[]->mutable_cpu_data()[] = loss / get_normalizer(normalization_, count);
if (top.size() == ) {
top[]->ShareData(prob_);
}
}
(3) softmax_loss_layer.cpp中的Backward_cpu函数:
template <typename Dtype>
void SoftmaxWithLossLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {
if (propagate_down[]) {
LOG(FATAL) << this->type()
<< " Layer cannot backpropagate to label inputs.";
}
if (propagate_down[]) {
Dtype* bottom_diff = bottom[]->mutable_cpu_diff();
const Dtype* prob_data = prob_.cpu_data();
//将softmax的输出prob_复制给bottom[0]的diff(梯度) blob
caffe_copy(prob_.count(), prob_data, bottom_diff);
const Dtype* label = bottom[]->cpu_data();
int dim = prob_.count() / outer_num_;
int count = ;
for (int i = ; i < outer_num_; ++i) {
for (int j = ; j < inner_num_; ++j) {
const int label_value = static_cast<int>(label[i * inner_num_ + j]);
if (has_ignore_label_ && label_value == ignore_label_) {
for (int c = ; c < bottom[]->shape(softmax_axis_); ++c) {
bottom_diff[i * dim + c * inner_num_ + j] = ;
}
} else {
//对应公式(2),在反传梯度时,label索引对应的diff减1,其他不变。
bottom_diff[i * dim + label_value * inner_num_ + j] -= ;
++count;
}
}
}
// Scale gradient
//top[0]->cpu_diff()[0] = N
//N / count
Dtype loss_weight = top[]->cpu_diff()[] /
get_normalizer(normalization_, count);
caffe_scal(prob_.count(), loss_weight, bottom_diff);
}
}
caffe中softmax loss源码阅读的更多相关文章
- caffe中batch norm源码阅读
1. batch norm 输入batch norm层的数据为[N, C, H, W], 该层计算得到均值为C个,方差为C个,输出数据为[N, C, H, W]. <1> 形象点说,均值的 ...
- 【源码阅读】Java集合之三 - ArrayDeque源码深度解读
Java 源码阅读的第一步是Collection框架源码,这也是面试基础中的基础: 针对Collection的源码阅读写一个系列的文章,本文是第三篇ArrayDeque. ---@pdai JDK版本 ...
- 【源码阅读】Java集合之二 - LinkedList源码深度解读
Java 源码阅读的第一步是Collection框架源码,这也是面试基础中的基础: 针对Collection的源码阅读写一个系列的文章; 本文是第二篇LinkedList. ---@pdai JDK版 ...
- 【源码阅读】Java集合之一 - ArrayList源码深度解读
Java 源码阅读的第一步是Collection框架源码,这也是面试基础中的基础: 针对Collection的源码阅读写一个系列的文章,从ArrayList开始第一篇. ---@pdai JDK版本 ...
- Caffe源码阅读(1) 全连接层
Caffe源码阅读(1) 全连接层 发表于 2014-09-15 | 今天看全连接层的实现.主要看的是https://github.com/BVLC/caffe/blob/master/src ...
- caffe-windows中classification.cpp的源码阅读
caffe-windows中classification.cpp的源码阅读 命令格式: usage: classification string(模型描述文件net.prototxt) string( ...
- 源码阅读笔记 - 1 MSVC2015中的std::sort
大约寒假开始的时候我就已经把std::sort的源码阅读完毕并理解其中的做法了,到了寒假结尾,姑且把它写出来 这是我的第一篇源码阅读笔记,以后会发更多的,包括算法和库实现,源码会按照我自己的代码风格格 ...
- 源码阅读经验谈-slim,darknet,labelimg,caffe(1)
本文首先谈自己的源码阅读体验,然后给几个案例解读,选的例子都是比较简单.重在说明我琢磨的点线面源码阅读方法.我不是专业架构师,是从一个深度学习算法工程师的角度来谈的,不专业的地方请大家轻拍. 经常看别 ...
- SpringMVC源码阅读:Controller中参数解析
1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码(基于Spring ...
随机推荐
- java动态代理之CGLIB实现
动态代理(CGlib 与连接池的案例) Cglib代理: 针对类来实现代理,对指定目标 产生一个子类 通过方法拦截技术拦截所有父类方法的调用. 我们要使用cglib代理必须引入 cglib的jar包 ...
- Scala 系列(十三)—— 隐式转换和隐式参数
一.隐式转换 1.1 使用隐式转换 隐式转换指的是以implicit关键字声明带有单个参数的转换函数,它将值从一种类型转换为另一种类型,以便使用之前类型所没有的功能.示例如下: // 普通人 clas ...
- [Pandas] 02 - Tutorial of NumPy
Ref: NumPy 教程 这里主要是查缺补漏一些常用方法. 初步认识 矩阵常见知识点 矩阵操作 Ref: [Python] 01 - Number and Matrix[总结过一部分] 一.矩阵 ( ...
- elastic集群单节点停机维护
为了elastic时时提供服务,需要elastic至少状态维持在yellow状态.所有,维护时需要依次对elastic单个节点进行维护. 操作步骤如下: 1.停止elastic的自动分配功能 curl ...
- java架构之路-(分布式)初识zookeeper安装与参数详解
ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件.它是一个为分布式应用提供一致性服务的软件,提供的功 ...
- thymeleaf 日期时间格式处理
一.#dates.format()用来格式化日期时间 ${#dates.format(date, 'dd/MMM/yyyy HH:mm')} ${#dates.arrayFormat(datesArr ...
- F#周报2019年第40期
新闻 将项目成熟度重新考虑为一个社区过程 介绍.NET Core Windows Form设计器预览1 F# 4.7可以预览新语言特性与语法 视频及幻灯片 DotnetConf2019展示 .NET设 ...
- 纯 CSS 实现幻灯片播放
介绍: 今日看到一道面试题,关于 使用纯CSS,不利用js, 写一个简单的幻灯效果页面.于是做了一个小demo,建议使用chrome,IE11查看~~ 主要思想: 利用 CSS3的 伪类选择器 : ...
- [LeetCode] 822. Card Flipping Game
Description On a table are N cards, with a positive integer printed on the front and back of each ca ...
- Spark 学习笔记之 aggregateByKey
aggregateByKey: import org.apache.spark.SparkContext import org.apache.spark.rdd.RDD import org.apac ...