#include "caffe/layers/softmax_layer.hpp"
#include <algorithm>
#include <vector>
#include "caffe/util/math_functions.hpp"
namespace caffe {
template <typename Dtype>
void SoftmaxLayer<Dtype>::Reshape(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top) {
softmax_axis_ =
bottom[0]->CanonicalAxisIndex(this->layer_param_.softmax_param().axis());
top[0]->ReshapeLike(*bottom[0]); // softmax用于归一化,所以属于输出维度相同
vector<int> mult_dims(1, bottom[0]->shape(softmax_axis_));
sum_multiplier_.Reshape(mult_dims);
Dtype* multiplier_data = sum_multiplier_.mutable_cpu_data();
caffe_set(sum_multiplier_.count(), Dtype(1), multiplier_data);
outer_num_ = bottom[0]->count(0, softmax_axis_);// 图片数量
inner_num_ = bottom[0]->count(softmax_axis_ + 1);// 长x宽
vector<int> scale_dims = bottom[0]->shape();
scale_dims[softmax_axis_] = 1;
scale_.Reshape(scale_dims);
}
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();
// vector<int> scale_dims = bottom[0]->shape();
// scale_dims[softmax_axis_] = 1;
// scale_.Reshape(scale_dims);
Dtype* scale_data = scale_.mutable_cpu_data();
int channels = bottom[0]->shape(softmax_axis_); //通道数
// outer_num_:图片数量,dim:通道x长x宽
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.
// outer_num_ = bottom[0]->count(0, softmax_axis_); //图片数量
for (int i = 0; i < outer_num_; ++i) {
// initialize scale_data to the first plane
caffe_copy(inner_num_, bottom_data + i * dim, scale_data);
//遍历找到最大数 在(h ,w)位置的不同通道下的最大数
for (int j = 0; j < channels; j++) { //通道数
// inner_num_ = bottom[0]->count(softmax_axis_ + 1); 长x宽
for (int k = 0; k < inner_num_; k++) { // 长x宽
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);
// vector<int> mult_dims(1, bottom[0]->shape(softmax_axis_));
// sum_multiplier_.Reshape(mult_dims);
// top_data=-(sum_multiplier_.cpu_data())*scale_data+ top_data
// (sum_multiplier_.cpu_data())*scale_data将scale_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);
// scale_data=转置(top_data) * (sum_multiplier_.cpu_data())
// scale_data: (H*W) x 1
// division
for (int j = 0; j < channels; j++) {
caffe_div(inner_num_, top_data, scale_data, top_data);
top_data += inner_num_; // inner_num_=长x宽
} // top_data增加一张图(C x H x W)的距离
}
}
template <typename Dtype>
void SoftmaxLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
const vector<bool>& propagate_down,
const vector<Blob<Dtype>*>& bottom) {
const Dtype* top_diff = top[0]->cpu_diff();
const Dtype* top_data = top[0]->cpu_data();
Dtype* bottom_diff = bottom[0]->mutable_cpu_diff();
Dtype* scale_data = scale_.mutable_cpu_data();
int channels = top[0]->shape(softmax_axis_);
int dim = top[0]->count() / outer_num_;
caffe_copy(top[0]->count(), top_diff, bottom_diff);
for (int i = 0; i < outer_num_; ++i) { // 图片数量
// compute dot(top_diff, top_data) and subtract them from the bottom diff
for (int k = 0; k < inner_num_; ++k) { //长 x 宽
//同一(h,w)下,top_diff和op_data不同通道求内积
// (a1*d1+d2*d2+a3*d3)
scale_data[k] = caffe_cpu_strided_dot<Dtype>(
channels, bottom_diff + i * dim + k, inner_num_,
top_data + i * dim + k, inner_num_);
}
// subtraction
caffe_cpu_gemm<Dtype>(CblasNoTrans, CblasNoTrans, channels, inner_num_, 1,
-1., sum_multiplier_.cpu_data(), scale_data, 1.,
bottom_diff + i * dim);
// bottom_diff + i * dim=
// -(sum_multiplier_.cpu_data())*scale_data+(bottom_diff + i * dim)
// di-(a1*d1+d2*d2+a3*d3)
}
// elementwise multiplication //逐元素积
caffe_mul(top[0]->count(), bottom_diff, top_data, bottom_diff);
}
#ifdef CPU_ONLY
STUB_GPU(SoftmaxLayer);
#endif
INSTANTIATE_CLASS(SoftmaxLayer);
} // namespace caffe