日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

tensorflow2caffe(1) : caffemodel解析,caffemodel里面到底记录了什么?

發布時間:2024/9/21 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 tensorflow2caffe(1) : caffemodel解析,caffemodel里面到底记录了什么? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

? ?在本文正式開始之前,筆者要先和各位讀者朋友們道個歉。因為身為研一小白的筆者實在身不由己,除了各種任務之外,還要應付繁忙的課程,忙于各種考試像一只咸魚。因此耽誤了博文的撰寫,對不起各位讀者朋友,筆者在忙完6月進入研二之后一定再接再厲。下面開始干貨~

? ?本篇還是一個插播的博客,旨在向大家分享caffemodel里面記錄的信息。在我們使用caffe框架訓練網絡時,最終總會生成一個caffemodel,我們大概知道里面記錄了模型的參數。而作為初學者的筆者,總是不分青紅皂白地就直接在模型的驗證階段就調用了。從來沒有去看過caffemodel里面到底講了什么,那么,本篇中筆者就解析一下caffemodel。

? ?有讀者朋友未免會問,筆者是出于什么目的想解析caffemodel的呢?這說來話長,是筆者最近做的項目需要將model拆開并進行改動,因此需要去解析caffemodel。那么筆者是怎么摸索的呢?各位讀者朋友們是否還記得,筆者前兩期的博客里面提及的caffe官方提供的classification.cpp文件,里面在執行Classifier類的構造函數的時候,有一個net_指針,并且執行了一個操作:

[cpp]?view plaincopy
  • net_->CopyTrainedLayersFrom(trained_file);??

  • ? ?這個CopyTrainedLayersFrom函數就是從caffemodel里面載入我們需要的參數了。然后筆者就從這個函數開始挖,進入net.cpp文件:

    [cpp]?view plaincopy
  • template?<typename?Dtype>??
  • void?Net<Dtype>::CopyTrainedLayersFrom(const?string?trained_filename)?{??
  • ??if?(H5Fis_hdf5(trained_filename.c_str()))?{??
  • ????CopyTrainedLayersFromHDF5(trained_filename);??
  • ??}?else?{??
  • ????CopyTrainedLayersFromBinaryProto(trained_filename);??
  • ??}??
  • }??

  • ? ?在這里很明顯執行了else下面的語句,從二進制文件中去讀取了參數,然后,筆者又找到了CopyTrainedLayersFromBinaryProto函數,很巧就在CopyTrainedLayersFrom函數的下方:

    [cpp]?view plaincopy
  • template?<typename?Dtype>??
  • void?Net<Dtype>::CopyTrainedLayersFromBinaryProto(??
  • ????const?string?trained_filename)?{??
  • ??NetParameter?param;??
  • ??ReadNetParamsFromBinaryFileOrDie(trained_filename,?&parm);??
  • ??CopyTrainedLayersFrom(param);??
  • }??

  • ? ?在里面首先執行了一個ReadNetParamsFromBinaryFileOrDie函數,把二進制文件中的參數讀到parm里面,parm是一個NetParameter類型的,NetParameter繼承了實際是一個Message,Message是proto類型的,詳細的筆者后話解析。然后筆者去找了一下ReadNetParamsFromBinaryFileOrDie函數,這個函數在upgrade_proto.cpp里面:

    ?

    [cpp]?view plaincopy
  • void?ReadNetParamsFromBinaryFileOrDie(const?string&?param_file,??
  • ??????????????????????????????????????NetParameter*?param)?{??
  • ??CHECK(ReadProtoFromBinaryFile(param_file,?param))??
  • ??????<<?"Failed?to?parse?NetParameter?file:?"?<<?param_file;??
  • ??UpgradeNetAsNeeded(param_file,?param);??
  • }??
  • ? ?這個函數完成的功能是首先進行ReadProtoFromBinaryFile,然后執行了一個更新的操作。然后筆者就去找這個ReadProtoFromBinaryFile函數,這個函數在io.cpp里面:

    [cpp]?view plaincopy
  • bool?ReadProtoFromBinaryFile(const?char*?filename,?Message*?proto)?{??
  • ??int?fd?=?open(filename,?O_RDONLY);??
  • ??CHECK_NE(fd,?-1)?<<?"File?not?found:?"?<<?filename;??
  • ??ZeroCopyInputStream*?raw_input?=?new?FileInputStream(fd);??
  • ??CodedInputStream*?coded_input?=?new?CodedInputStream(raw_input);??
  • ??coded_input->SetTotalBytesLimit(kProtoReadBytesLimit,?536870912);??
  • ??
  • ??bool?success?=?proto->ParseFromCodedStream(coded_input);??
  • ??
  • ??delete?coded_input;??
  • ??delete?raw_input;??
  • ??close(fd);??
  • ??return?success;??
  • }??

  • ? ?這個函數就比較底層了,讀者朋友們可以看到,這個函數里面就使用了open函數,和一些底層的google::protobuf的數據流。在這里我們其實就明白,是先把二進制文件(caffemodel)轉化成文件流,再放入proto里面。

    ? ?那么,筆者大膽猜想,能讀就能寫。

    ? ?其實io.cpp里面已經定義了這種接口:

    [cpp]?view plaincopy
  • void?WriteProtoToTextFile(const?Message&?proto,?const?char*?filename)?{??
  • ??int?fd?=?open(filename,?O_WRONLY?|?O_CREAT?|?O_TRUNC,?0644);??
  • ??FileOutputStream*?output?=?new?FileOutputStream(fd);??
  • ??CHECK(google::protobuf::TextFormat::Print(proto,?output));??
  • ??delete?output;??
  • ??close(fd);??
  • }??

  • ? ?也就是說:先用ReadProtoFromBinaryFile函數將二進制文件讀入proto里面,再將proto文件讀入txt文件就行了。

    ? ?筆者迫不及待地拿lenet網絡訓練生成的caffemodel做了個測試:

    [cpp]?view plaincopy
  • #include?<caffe/caffe.hpp>??
  • #include?<google/protobuf/io/coded_stream.h>??
  • #include?<google/protobuf/io/zero_copy_stream_impl.h>??
  • #include?<google/protobuf/text_format.h>??
  • #include?<algorithm>??
  • #include?<iosfwd>??
  • #include?<memory>??
  • #include?<string>??
  • #include?<utility>??
  • #include?<vector>??
  • #include?<iostream>??
  • #include?"caffe/common.hpp"??
  • #include?"caffe/proto/caffe.pb.h"??
  • #include?"caffe/util/io.hpp"??
  • ??
  • using?namespace?caffe;??
  • using?namespace?std;??
  • using?google::protobuf::io::FileInputStream;??
  • using?google::protobuf::io::FileOutputStream;??
  • using?google::protobuf::io::ZeroCopyInputStream;??
  • using?google::protobuf::io::CodedInputStream;??
  • using?google::protobuf::io::ZeroCopyOutputStream;??
  • using?google::protobuf::io::CodedOutputStream;??
  • using?google::protobuf::Message;??
  • ??
  • int?main()??
  • {??
  • ????NetParameter?proto;??
  • ????ReadProtoFromBinaryFile("/home/cvlab/files/caffe-master/data/mnist/lenet_iter_10000.caffemodel",?&proto);??
  • ????WriteProtoToTextFile(proto,?"/home/cvlab/files/caffe-master/data/mnist/test.txt");??
  • ????return?0;??
  • }??

  • ? ?筆者訓練了一個lenet訓練生成的二進制文件,并將其寫入了一個名為test.txt的文件中。

    ? ?其對應的CMakeLists.txt文件為:

    [cpp]?view plaincopy
  • cmake_minimum_required?(VERSION?2.8)??
  • ??
  • project?(pt_test)??
  • ??
  • add_executable(pt_test?pt.cpp)??
  • ??
  • include_directories?(?/home/cvlab/files/caffe-master/include??
  • ????/usr/local/include??
  • ????/usr/local/cuda/include??
  • ????/usr/include?)??
  • ??
  • target_link_libraries(pt_test??
  • ????/home/cvlab/files/caffe-master/build/lib/libcaffe.so??
  • ????/usr/lib/x86_64-linux-gnu/libglog.so??
  • ????/usr/lib/x86_64-linux-gnu/libboost_system.so??
  • ????)??
  • ? ?編譯執行:



    ? ?然后我們打開test.txt文件可以見到:



    ? ?一共43萬多行,記錄了lenet-5的網絡參數。因為lenet-5使用了全連接層,因此參數規模是龐大的(全連接層的參數約占了總體參數規模的90%)。

    ? ?同時也可以看到,讀出的二進制文件中參數規格是按照caffe.proto中協定的格式來的。

    ? ?到此,我們就能清晰地看到caffemodel中記載的數據和格式了。

    ? ?歡迎閱讀筆者后續博客,各位讀者朋友的支持與鼓勵是我最大的動力!


    written by jiong

    故上兵伐謀,其次伐交,其次伐兵,其下攻城;攻城之法為不得已。

    與50位技術專家面對面20年技術見證,附贈技術全景圖

    總結

    以上是生活随笔為你收集整理的tensorflow2caffe(1) : caffemodel解析,caffemodel里面到底记录了什么?的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。