caffe原始碼解析 — solver.cpp
Solver<Dtype>::Solver(const SolverParameter& param)
功能:建構函式
步驟:初始化兩個Net類,net_和test_net_,並呼叫Init()函式
輸入:SolverParameter型別的param
輸出:無
Solver<Dtype>::Solver(const string& param_file)
功能:建構函式
步驟:初始化兩個Net類,net_和test_net_,並呼叫Init()函式
輸入:string型別的param_file
輸出:無
void Solver<Dtype>::Init(const SolverParameter& param)
功能:初始化網路
步驟:
1. 設定隨機數種子
2. 申請一塊Net空間以下面的建構函式進行初始化
param_file=train_net_
,net_指向這塊空間
3. 如果有test_net,則申請一塊Net空間,test_net_指向這塊空間
輸入:SolverParameter型別的param
輸出:無
Net<Dtype>::Net(const string& param_file) {
NetParameter param;
ReadNetParamsFromTextFileOrDie(param_file, ¶m) ;
Init(param);
}
void Solver<Dtype>::Solve(const char* resume_file)
功能:訓練網路
步驟:
1. 設定Caffe的mode(GPU還是CPU)
2. 如果是GPU且有GPU晶片的ID,則設定GPU
3. 設定當前階段(TRAIN還是TEST/TRAIN)
4. 呼叫PreSolve函式:PreSolve()
5. 呼叫Restore函式:Restore(resume_file)
6. 呼叫一遍Test(),判斷記憶體是否夠
7. 對於每一次訓練時的迭代(遍歷整個網路):while (iter_++ < param_.max_iter())
- 計算loss:
loss = net_->ForwardBackward(bottom_vec)
其中:
*************** ForwardBackward() ************
Dtype ForwardBackward(const vector<Blob<Dtype>* > & bottom) {
Dtype loss;
Forward(bottom, &loss);
Backward();
return loss;
}
*************** Forward() ***********
const vector<Blob<Dtype>*>& Net<Dtype>::Forward(
const vector<Blob<Dtype>*> & bottom, Dtype* loss) {
// Copy bottom to internal bottom
for (int i = 0; i < bottom.size(); ++i)
net_input_blobs_[i]->CopyFrom(*bottom[i]){;
}
return ForwardPrefilled(loss);
}
*************** ForwardPrefilled() ************
const vector<Blob<Dtype>*>& Net<Dtype>::ForwardPrefilled(Dtype* loss) {
if (loss != NULL) {
*loss = Dtype(0.);
}
for (int i = 0; i < layers_.size(); ++i) {
// LOG(ERROR) << "Forwarding " << layer_names_[i];
Dtype layer_loss = layers_[i]->Forward(bottom_vecs_[i], &top_vecs_[i]);
if (loss != NULL) {
*loss += layer_loss;//對於非loss層都會返回0:return Dtype(0.);
}
}
return net_output_blobs_;
}
*************** Layer::Forward() ************
inline Dtype Layer<Dtype>::Forward(const vector<Blob<Dtype>*>& bottom,
vector<Blob<Dtype>*>* top) {
switch (Caffe::mode()) {
case Caffe::CPU:
return Forward_cpu(bottom, top);//虛擬函式,不同層有不同層的計算方法
case Caffe::GPU:
return Forward_gpu(bottom, top);
default:
LOG(FATAL) << "Unknown caffe mode.";
return Dtype(0);
}
}
*************** Backward() ************
void Net<Dtype>::Backward() {
for (int i = layers_.size() - 1; i >= 0; --i) {
if (layer_need_backward_[i]) {
layers_[i]->Backward(top_vecs_[i], true, &bottom_vecs_[i]);
}
}
}
2.呼叫ComputeUpdateValue函式:ComputeUpdateValue()
3. 輸出loss
4. 達到test_interval時呼叫Test()
5. 達到snapshot時呼叫snapshot()
6. 呼叫Snapshot函式:Snapshot()
輸入:char*型別的resume_file
輸出:無
void Solver<Dtype>::Test()
功能:測試網路
輸入:無
輸出:無
步驟:
1. 設定當前階段(TRAIN還是TEST/TEST)
2. 將test_net_指向net_,即對同一個網路操作
3. 對於每一次測試時的迭代:for (int i = 0; i < param_.test_iter(); ++i)
- 用下面語句給result賦值net_output_blobs_ //result是所有的輸出層blob
同時得到這次測試的iter_loss
result = test_net_->Forward(bottom_vec, &iter_loss)
- 第一次測試時:
- 取每一個輸出層的blob
result_vec = result[j]->cpu_data()
- 把每一個blob的資料(降為一維)存入一個vector–“test_score”
- 取每一個輸出層的blob
- 不是第一次測試:
- 用
test_score[idx++] += result_vec[k]
而不是test_score.push_back(result_vec[k])
- 把輸出層對應位置的blob值累加
test_score[idx++] += result_vec[k]
- 用
- 是否要輸出Test loss
- 是否要輸出test_score
- 設定當前階段(TRAIN還是TEST/TRAIN)
void Solver<Dtype>::Snapshot()
功能:輸出當前網路狀態到一個檔案中,不重要
輸入:無
輸出:無
void Solver<Dtype>::Restore(const char* state_file)
功能:從一個檔案中讀入網路狀態,並可以從那個狀態恢復,不重要
輸入:檔名
輸出:無
Dtype SGDSolver<Dtype>::GetLearningRate()
功能:得到學習率
步驟:
1. 得到學習率型別 const string& lr_policy = this->param_.lr_policy()
2. 判斷學習率型別(註釋有介紹)
3. 返回學習率
輸入:無
輸出:Dtype型別的rate
void SGDSolver<Dtype>::PreSolve()
功能:提前訓練
步驟:
1. 將訓練網路net_的引數讀到net_params net_params = this->net_->params()
其中params_是一個存blob指標的vector
2. 清空歷史殘留值
3. 向history壓入與網路的每一層blob相同大小的空間
輸入:無
輸出:無
void SGDSolver<Dtype>::ComputeUpdateValue()
功能:用隨機梯度下降法計算更新值
輸入:無
輸出:無
步驟:
1. (所有的)讀取網路引數net_params,網路學習速率 net_params_lr,
權值衰減net_params_weight_decay 讀取學習速率rate
2. (當前層)讀取動量,權值衰減
3. 如果是CPU:
對於每一次層:
- 計算local_rate,local_decay
- 呼叫caffe_cpu_axpby,caffe_axpy,caffe_copy函式:
caffe_cpu_axpby(net_params[param_id]->count(), local_rate, net_params[param_id]->cpu_diff(), momentum, history_[param_id]->mutable_cpu_data());
caffe_axpy(net_params[param_id]->count(), local_decay*local_rate, net_params[param_id]->cpu_data(),history_[param_id]->mutable_cpu_data());
void caffe_cpu_axpby<float>(const int N, const float alpha, const float* X,const float beta, float* Y)
{
cblas_saxpby(N, alpha, X, 1, beta, Y, 1);
}
其中:
inline void cblas_saxpby(const int N, const float alpha, const float* X,const int incX, const float beta, float* Y, const int incY)
{
cblas_sscal(N, beta, Y, incY);
cblas_saxpy(N, alpha, X, incX, Y, incY);
}
caffe_cpu_axpby呼叫了cblas_saxpby,即呼叫了cblas_sscal和cblas_saxpy
void caffe_axpy<float>(const int N, const float alpha, const float* X,float* Y)
{
cblas_saxpy(N, alpha, X, 1, Y, 1);
}
caffe_axpy呼叫了cblas_saxpy,即呼叫了cblas_saxpy
所以caffe_cpu_axpby比caffe_axpy多輸入了一個beta引數,多呼叫了cblas_sscal(N, beta, Y, incY);
4. GPU同理
void SGDSolver<Dtype>::SnapshotSolverState(SolverState* state)
略
void SGDSolver<Dtype>::RestoreSolverState(const SolverState& state)
略