1. 程式人生 > >caffe原始碼解析 — solver.cpp

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, &param)
; 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())

  1. 計算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)

  1. 用下面語句給result賦值net_output_blobs_ //result是所有的輸出層blob
    同時得到這次測試的iter_loss
    result = test_net_->Forward(bottom_vec, &iter_loss)
  2. 第一次測試時:
    1. 取每一個輸出層的blob result_vec = result[j]->cpu_data()
    2. 把每一個blob的資料(降為一維)存入一個vector–“test_score”
  3. 不是第一次測試:
    1. test_score[idx++] += result_vec[k]
      而不是 test_score.push_back(result_vec[k])
    2. 把輸出層對應位置的blob值累加
      test_score[idx++] += result_vec[k]
  4. 是否要輸出Test loss
  5. 是否要輸出test_score
  6. 設定當前階段(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:
對於每一次層:

  1. 計算local_rate,local_decay
  2. 呼叫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)