您的位置:首页 > Web前端

caffe中的softmax layer

2016-05-25 11:01 399 查看
在caffe中的lenet实现最后一层是softmax layer,输出分类的结果,下面就简单介绍一下softmax回归。

1,首先,在caffe中,softmax layer输出的是原始的输入在每一个分类标签上的概率,例如在lenet网络中,输出的分类共有0-9的10中分类,那么softmax layer就会输出含有10个元素的向量,每一个元素表示输入在每一个分类上的概率。

那么,用softmax的目的是让输入在正确的分来标签上的概率最大,这就是我们优化的目标函数,普通的优化函数只是比较输出和标签的差值,然后对差值进行优化,让其最小,就可以得出网络的参数值。但是在分类中,这种方法不太适用,因为输出的结果不是连续的,而是离散的,是无法对其求梯度的,所以要从概率的角度进行考虑。

那么问题来了,从概率的角度进行优化是可行的,但是输入在每个标签上的概率应该怎么求呢,这是一个多元分布问题,而softmax就是解决多元分布问题的,在介绍具体的过程之前,我们先看softmax layer的输入代表的含义,在《deeping learning》的181页有这么一句话:we can think of a as a vector of scores whose elements a(i) as associated with each category i, with larger relative
scores yielding exponentially larger probabilities. 就是说softmax layer的输入可以看作是输入在每个标签上的打分,分数越高,说明输入越有可能属于这个标签上,那么我们也可以利用这个分数求输入相对于每个标签的概率,分数越高,概率越大。

2, softmax回归

网上有很多关于softmax回归的帖子,我的理解是softmax本质的作用就是计算softmax layer的输入在每一个标签上的概率,caffe中softmax_layer的过程如下:

(1)找出输入的最大值;

(2)输入的每一个变量都减去最大值;

(3)对(2)中结果求去指数函数;

(4)对(3)中结果归一化,得出的结果就是输入在每一个标签上概率。

caffe中代码是在softmax_layer.cpp Line 37

for (int i = 0; i < outer_num_; ++i) { // use softmax to calculate the hypothesis function
// initialize scale_data to the first plane
caffe_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]);
}
}
// subtraction
caffe_cpu_gemm<Dtype>(CblasNoTrans, CblasNoTrans, channels, inner_num_,
1, -1., sum_multiplier_.cpu_data(), scale_data, 1., top_data);
// exponentiation
caffe_exp<Dtype>(dim, top_data, top_data);
// sum after exp
caffe_cpu_gemv<Dtype>(CblasTrans, channels, inner_num_, 1.,
top_data, sum_multiplier_.cpu_data(), 0., scale_data);
// division
for (int j = 0; j < channels; j++) {
caffe_div(inner_num_, top_data, scale_data, top_data);
top_data += inner_num_;
}
}


下面最重要的是求去代价函数,代价函数本质上就是输入在对应的正确的标签上的概率,我们优化的目标就是使这个概率最大,一般我们都是对概率取个log运算,然后,由于网络的训练是以batch为单位的,假如一个batch里有100个样本,我们就要对这100个样本的log(概率)进行求和,然后平均,最后我们就是利用这个代价函数求梯度,然后利用梯度更新权值。caffe中代码是在softmax_loss_layer.cpp中Line 100

for (int i = 0; i < outer_num_; ++i){ // sample by sample
for (int j = 0; j < inner_num_; j++) {
const int label_value = static_cast<int>(label[i * inner_num_ + j]);
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)));  // cost function
++count;
}
}
top[0]->mutable_cpu_data()[0] = loss / get_normalizer(normalization_, count);


关于softmax的具体原理,参考下面两个博客:

(1)http://ufldl.stanford.edu/wiki/index.php/Softmax%E5%9B%9E%E5%BD%92

(2)http://blog.csdn.net/acdreamers/article/details/44663305
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: