caffe 源码阅读之softmax data layer
勿在浮沙筑高台。
国人大多浮躁,猪都喜欢往风口跑,曾经的我也不例外。
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]);
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);
// start of liqiming added code
const string s = "liqiming debuging softmax layer!!"
Log(s)
char* t;
sprintf_s(t,"%d",softmax_axis_) // 这里的输出应该是1,也即是softmax_axis_ = 1;
Log(t)
//// end of liqiming added code
outer_num_ = bottom[0]->count(0, softmax_axis_); // 这里实际上是shape_(0), 对应的维度是n
inner_num_ = bottom[0]->count(softmax_axis_ + 1); // shape_(2)*shape_(4), 对应的是h*w
vector<int> scale_dims = bottom[0]->shape();
scale_dims[softmax_axis_] = 1;
scale_.Reshape(scale_dims);
}
在source insight软件里可以推断出
outer_num = =n;
inner_num = = h*w;
之前一直困扰我的还有怎么从blob里取出数据?
借着读取softmax data layer的机会消除这个疑问。
在深入细节之前,我先画个图来表示下blob:
由此图,我们不难看出要取出blob中的数据:可以采取如下的操作:
for ( int i = 0; i < n; i++)
{
for ( int j = 0; j < c; j++ )
{
for ( int k = 0; k < h*w; k++ )
value = blob[i*c*h*w+j*h*w+k]
}
}
各位看官,请看以下的函数:
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) { // 这里outer_num_ == n
// initialize scale_data to the first plane
caffe_copy(inner_num_, bottom_data + i * dim, scale_data); //
for (int j = 0; j < channels; j++) { // 这里的channels == c
for (int k = 0; k < inner_num_; k++) { // 这里的inner_num_ == h*w
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_;
}
}
}