CRF as RNN 程式碼解讀
論文:http://www.robots.ox.ac.uk/~szheng/papers/CRFasRNN.pdf,
CRF as RNN論文的程式碼在https://github.com/torrvision/crfasrnn可以找到。
有一個線上的demo可以演示http://www.robots.ox.ac.uk/~szheng/crfasrnndemo
這篇博文主要是記錄自己對CRF as RNN中的 MultiStageMeanfieldLayer 的解讀。涉及到的檔案有multi_stage_meanfield的標頭檔案與實現、meanfield的標頭檔案與實現。
這個程式碼是基於老版本的caffe,大部分的層的標頭檔案都在vision_layers.hpp中,
對應的位置是class MultiStageMeanfieldLayer 和 class MeanfieldIteration,比較簡單,MultiStageMeanfieldLayer才是真正的層,而MeanfieldIteration是一個輔助類,直接看實現。
層運算的入口便是LayerSetUp,前面都是成員變數的初始化,接著是讀取spatial.par和bilateral.par。 然後是計算spatial_kernel,直接呼叫了
compute_spatial_kernel()函式:
template <typename Dtype>
void MultiStageMeanfieldLayer<Dtype>::compute_spatial_kernel(float* const output_kernel) {
for (int p = 0; p < num_pixels_; ++p) {
output_kernel[2*p] = static_cast<float>(p % width_) / theta_gamma_;
output_kernel[2*p + 1] = static_cast<float>(p / width_) / theta_gamma_;
}
}
這個功能很簡單,就是用一個2倍於畫素點個數的矩陣,儲存 (列/theta_gamma_,行/theta_gamma_)的kernel.
接下來就是將spatial_lattice_初始化。然後將後面計算需要的一元項先分配記憶體。由於需要使用多次的meanfield,所以接下來就為每個meanfield進行了一次初始化。就這樣,層就可以啟動了。
接下來就是Forward_cpu
/**
* Performs filter-based mean field inference given the image and unaries.
*
* bottom[0] - Unary terms
* bottom[1] - Softmax input/Output from the previous iteration (a copy of the unary terms if this is the first stage).
* bottom[2] - RGB images
*
* top[0] - Output of the mean field inference (not normalized).
*/
template <typename Dtype>
void MultiStageMeanfieldLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top) {
split_layer_bottom_vec_[0] = bottom[0];
split_layer_->Forward(split_layer_bottom_vec_, split_layer_top_vec_);
// Initialize the bilateral lattices.
bilateral_lattices_.resize(num_);
for (int n = 0; n < num_; ++n) {
compute_bilateral_kernel(bottom[2], n, bilateral_kernel_buffer_.get());
bilateral_lattices_[n].reset(new ModifiedPermutohedral());
bilateral_lattices_[n]->init(bilateral_kernel_buffer_.get(), 5, num_pixels_);
// Calculate bilateral filter normalization factors.
Dtype* norm_output_data = bilateral_norms_.mutable_cpu_data() + bilateral_norms_.offset(n);
bilateral_lattices_[n]->compute(norm_output_data, norm_feed_.get(), 1);
for (int i = 0; i < num_pixels_; ++i) {
norm_output_data[i] = 1.f / (norm_output_data[i] + 1e-20f);
}
}
for (int i = 0; i < num_iterations_; ++i) {
meanfield_iterations_[i]->PrePass(this->blobs_, &bilateral_lattices_, &bilateral_norms_);
meanfield_iterations_[i]->Forward_cpu();
}
}
功能就是讓前面的多次meanfield每一個跑一次。
下面是Backward_cpu()
/**
* Backprop through filter-based mean field inference.
*/
template<typename Dtype>
void MultiStageMeanfieldLayer<Dtype>::Backward_cpu(
const vector<Blob<Dtype>*>& top, const vector<bool>& propagate_down,
const vector<Blob<Dtype>*>& bottom) {
for (int i = (num_iterations_ - 1); i >= 0; --i) {
meanfield_iterations_[i]->Backward_cpu();
}
vector<bool> split_layer_propagate_down(1, true);
split_layer_->Backward(split_layer_top_vec_, split_layer_propagate_down, split_layer_bottom_vec_);
// Accumulate diffs from mean field iterations.
for (int blob_id = 0; blob_id < this->blobs_.size(); ++blob_id) {
Blob<Dtype>* cur_blob = this->blobs_[blob_id].get();
if (this->param_propagate_down_[blob_id]) {
caffe_set(cur_blob->count(), Dtype(0), cur_blob->mutable_cpu_diff());
for (int i = 0; i < num_iterations_; ++i) {
const Dtype* diffs_to_add = meanfield_iterations_[i]->blobs()[blob_id]->cpu_diff();
caffe_axpy(cur_blob->count(), Dtype(1.), diffs_to_add, cur_blob->mutable_cpu_diff());
}
}
}
}
開始就是讓每個MeanfieldIteration進行一個Backward_cpu。然後有兩個for迴圈,第一個就是迴圈所有的blob,第二個就是把每個blob的所有迭代時的diff相加,放到對應blob的diff中。
PS:
- 有關caffe數學計算的,可以在math_functions中找到,也可以看看http://www.cnblogs.com/jianyingzhou/p/4444728.html。
- 關於cblas計算的內容,可以參考http://www.math.utah.edu/software/lapack/lapack-blas.html
- Blob的解讀http://www.tuicool.com/articles/6rUVNf2
- CRF可以參考這篇http://blog.csdn.net/thesby/article/details/50969788
————————————————-我是分割線2016.06.23———————————————————————————–
我把這個版本的caffe已經merge到了最新的官方版caffe,因為它的原始版本實在太老了。下載地址在此.
相關文章
- RNN程式碼解讀之char-RNN with TensorFlow(model.py)RNN
- 為 Capped CRF 編碼選擇最佳 CRF 值APPCRF
- kafka程式碼解讀Kafka
- Torch中的RNN底層程式碼實現RNN
- 機器學習:crf機器學習CRF
- 解讀tensorflow之rnn 的示例 ptb_word_lm.pyRNN
- Linklist程式碼實現以及程式碼解讀
- RNN 結構詳解RNN
- LSTM Keras下的程式碼解讀Keras
- [譯] RNN 迴圈神經網路系列 3:編碼、解碼器RNN神經網路
- 零程式碼的多方面解讀
- 目標識別程式碼解讀整理
- 解讀基礎設施即程式碼
- 技術解讀 | 基於fastText和RNN的語義消歧實戰ASTRNN
- LSTM解決RNN梯度爆炸(消失)RNN梯度
- Hanlp分詞之CRF中文詞法分析詳解HanLP分詞CRF詞法分析
- OceanBase 原始碼解讀(九):儲存層程式碼解讀之「巨集塊儲存格式」原始碼
- Flutter 極簡 App 程式碼簡單解讀FlutterAPP
- 單週期cpu設計程式碼解讀
- 零程式碼開發的價值解讀
- 谷歌官方 Android MVP 模式程式碼解讀谷歌AndroidMVP模式
- 小程式之豆瓣電影原始碼解讀原始碼
- 大棚解讀卓越程式設計師密碼程式設計師密碼
- 如何更好、更快的解讀jive的程式碼
- xView2 比賽冠軍程式碼解讀View
- 條件隨機場CRF(三) 模型學習與維特比演算法解碼條件隨機場CRF模型維特比演算法
- 【精讀】自然語言處理基礎之RNN自然語言處理RNN
- SVCHOST程式解讀
- OceanBase 儲存層程式碼解讀(一)引言
- PostgreSQL 原始碼解讀(236)- 後臺程式#14(autovacuum程式#2)SQL原始碼
- PostgreSQL 原始碼解讀(124)- 後臺程式#4(autovacuum程式#1)SQL原始碼
- [論文閱讀] RNN 在阿里DIEN中的應用RNN阿里
- 從解讀 BDC 自動生成的程式碼談起,講解 SAPGUI 的程式組成部分試讀版GUI
- 使用Keras進行深度學習:(五)RNN和雙向RNN講解及實踐Keras深度學習RNN
- RNN、LSTMRNN
- WeakHashMap,原始碼解讀HashMap原始碼
- Handler原始碼解讀原始碼
- Laravel 原始碼解讀Laravel原始碼