1. 程式人生 > >caffe之儲存和讀入caffmodel檔案

caffe之儲存和讀入caffmodel檔案

一、caffe如何將卷積層或網路層的權值blob給儲存下來的?

首先Solver類在Step(intiters)中呼叫了Snapshot()函式,voidSolver<Dtype>::Snapshot()函式中能看到儲存caffemodel檔案的重要函式 SnapshotToBinaryProto(),該函式詳細如下:


可看到該函式裡初始化了NetParameternet_param ; 之後呼叫net_->ToProto(&net_param,param_.snapshot_diff())進行初始化, 該函式詳細如下:


在該函式中初始化了NetParameter 類物件net_param,

可看出net_param呼叫了 add_layer()函式將net_的所有層的引數作了處理,可理解為所有層的引數均載入到這個net_param, 採用遍歷的方法使各個層layers_[i]呼叫 ToProto(layer_param,write_diff); write_diff bool型別,表示是否需要儲存偏差;看看各個層的 ToProto函式:


可看到在這個函式裡,各個層的 layer_param又將使用add_blobs()將 層裡的所有blob給載入進去,看看 blobs_[i]ToProto函式:

可看到指向BlobProto類指標的proto(來自layer_paramadd_blobs())

將會通過for迴圈的方式呼叫 add_double_data(data_vec[i])blobdata陣列載入起來.

綜上所述,一個net_的所有層裡的所有blobdata資料將被用於初始化 NetParameter類物件net_param, 又呼叫了WriteProtoToBinaryFile(net_param,model_filename) 將其中重要的權參儲存為caffemodel檔案,如下所示:

實質是呼叫了下面這個,最終儲存為caffemodel檔案


caffe是如何讀入caffemodel檔案的?

caffemodel檔案通常被用於初始化Net類物件,使用Net

類中的相關函式如下:

對於caffemodel檔案,將被呼叫voidCopyTrainedLayersFromBinaryProto(const string trained_filename);該函式如下:

可看到內部呼叫了ReadNetParamsFromBinaryFileOrDie(trained_filename,&param) 初始化了

NetParameter類物件param;param 又將被用於初始化Net類的中各個層的blob;

先看看ReadNetParamsFromBinaryFileOrDie(trained_filename,&param) ,定義在 upgrade_proto.cpp:

內部主要呼叫了ReadProtoFromBinaryFile(param_file,param) , 該函式具體如下:

看看定義在io.cpp的函式ReadProtoFromBinaryFile:


大致也即是從caffemodel檔案寫入proto, 回到voidCopyTrainedLayersFromBinaryProto(const string trained_filename)函式:

看下另一個函式CopyTrainedLayersFrom(param)的實現:


可由該函式得到,已被初始化的NetParameter類物件 param將被用於初始化Net類中各個層的blob;具體方法是先遍歷 param中的各個LayerParameter物件 ,先找到名字相同的層的層id,再獲取這個id號的層的blob,再判斷該blob的形狀是否與LayerParameter物件中的blob一致,如果一致則開始呼叫FromProto複製,否則會報錯,FromProto函式如下:


Net類的各個層初始化的時候均會呼叫setup函式,在這個時候會對blobs_進行判斷,如果是已初始化的則不進行權值引數填充,例如卷積層,base_conv_layer.cpp中的LayerSetUp函式中有: