[caffe筆記008]:使用matlab除錯caffe中新加的層
阿新 • • 發佈:2019-02-17
寫在前面: caffe的底層是c++實現的,所以當自己新增層時自然可以用除錯c++的方法進行除錯。一方面除錯c++需要偵錯程式,另一方面c++除錯的時候觀測矩陣或者向量的資料不是很方便。由於caffe有比較好的matlab介面,採用matlab進行輔助除錯也就成為了一個很好的選擇。
1. 利用MATLAB進行除錯流程
我們這邊需要除錯自己實現的SoftProposal
層。編譯通過而且編譯了matlab的介面。
Step1:構建單層測試網路
第一步便是編寫一個測試網路’test.prototxt’,具體如下:
name: "TEST"
input: "data"
input_dim : 1
input_dim: 512
input_dim: 40
input_dim: 30
force_backward: true
layer {
name: "testlayer"
type: "SoftProposal"
bottom: "data"
top: "testlayer"
}
Step2:觀測單層測試輸出
接下來,開啟Matlab,
編寫.m檔案如下:
addpath $CAFFE_ROOT/matlab
model = 'test.prototxt';
caffe.set_mode_cpu();
% 測試gpu程式碼時請用GPU模式
% caffe.set_mode_gpu();
% caffe.set_device(gpu_id);
net = caffe.Net(model, 'test');
% 生成data同緯度的資料,並填入'data'層的blobs
net.blobs('data').set_data(randn(net.blobs('data').shape));
% 前向過程
net.forward();
% 檢查生成的"res"是否是期望的結果
res = net.blobs('testlayer').get_data();
% 後向過程
% diff為自己設定的梯度值,保證維度一致
net.blobs('testlayer').set_diff(diff);
net. backward();
% 檢查生成的"data_diff"是否是期望的結果
data_diff = net.blobs('data').get_diff();
在matlab中可以分別觀測層輸出和層反向傳播的值,以判斷是否實現正確。
2. 一些除錯技巧
2.1. 利用LOG(INFO)觀測單個數值
在caffe的底層c++程式碼中可以用LOG(INFO)
在linux的shell視窗中輸出一些簡單的變數。
觀測新新增的層的一些常量引數是否配置成功
例如我們新建的SoftProposal
層,該層有引數maxiteration
,如果設定了這個引數就採用設定值,否則採用預設值20。
if(soft_proposal_param.has_maxiteration())
maxIteration_ = soft_proposal_param.maxiteration();
else
maxIteration_ = 20;
LOG(INFO) << "maxIteration: " << maxIteration_;
觀測一些中間結果
例如迭代優化時觀測每次迭代終止條件的判定值。
for (j = 0; j < maxIteration_; j++) {
// proposalBuffer_data = transferMatrix_data * proposal_data - proposalBuffer_data;
caffe_cpu_gemv<Dtype>(CblasNoTrans, N_, N_, 1.,
transferMatrix_data, proposal_data, -1., proposalBuffer_data);
float normDiff = sqrt(proposalBuffer_.sumsq_data());
LOG(INFO) << "normDiff(" << j << "): " << normDiff;
if (normDiff < tolerance_) break;
// proposalBuffer_data = proposal_data + proposalBuffer_data;
UpdateProposalKernel(N_, proposal_data, proposalBuffer_data, proposalBuffer_data, -1.0f);
end
2.2. 利用Blob的存取觀測矩陣或者向量的值
儲存Blob
到檔案(底層c++程式碼中)。
儲存Blob
到檔案可以採用如下程式碼儲存到指定檔案中。
#include "caffe/util/io.hpp"
... ...
BlobProto sp;
proposal_.ToProto(&sp, false);// false只儲存blob.data,ture則同時儲存blob.data和blob.diff
WriteProtoToBinaryFile(sp, "proposal.blob"); //儲存到proposal.blob檔案中
從檔案中讀取Blob
資料(matlab中)
matlab中讀取blob檔案可以通過read_mean
函式來實現。
proposal = caffe.io.read_mean('proposal.blob'); //從proposal.blob檔案中讀入資料到proposal
讀入之後就可以在matlab中方便的查看了。
2.3. 除錯一些子函式
子函式的除錯,其實是利用了第一部分除錯層的方式,只不過把和需要觀測的子函式的輸出值放入到當前層的topblob中。
例如有子函式InitDistanceMetricKernel
,作用是初始化Blob<Dtype> distanceMetric_
這個成員變數。
// for page rank
template <typename Dtype>
void SoftProposalLayer<Dtype>::InitDistanceMetricKernel(){
Dtype* distanceMetric_data = distanceMetric_.mutable_cpu_data();
long nthreads = N_ * N_;
for(long n=0;n<nthreads;n++)
{
const long q = n % width_;
const long p = (n / width_) % height_;
const long j = (n / N_) % width_;
const long i = n / N_ / width_;
const long u = i * width_ + j;
const long v = p * width_ + q;
if (u >= v) {
*(distanceMetric_data + n) = expf(((i - p) * (i - p) + (j - q) * (j - q)) / (-2 * factor_ * factor_));
*(distanceMetric_data + v*N_ + u) = *(distanceMetric_data + n);
}
}
}
我們需要觀測初始化是否成功,那麼在Forward_cpu
中
template <typename Dtype>
void SoftProposalLayer<Dtype>::Forward_cpu(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top) {
Dtype* top_data = top[0]->mutable_cpu_data();
InitDistanceMetricKernel();
const Dtype* distanceMetric_data = distanceMetric_.cpu_data();
/*
編寫一節程式,將distanceMetric_data賦值到top_data當中
*/
}
當再次編譯後執行第一部分的測試網路,就可以獲得distanceMetric_
的資料。