Caffe2——cifar10數據集創建lmdb或leveldb類型的數據
時間:
2015-05-05 15:52:31 ???? 閱讀:
5183 ???? 評論: ???? 收藏:
1 ???? [點我收藏+]
標簽:class???log???com???代碼???使用???src???http???si???html???
Caffe2——cifar10數據集創建lmdb或leveldb類型的數據
cifar10數據集和mnist數據集存儲方式不同,cifar10數據集把標簽和圖像數據以bin文件的方式存放在同一個文件內,這種存放方式使得每個子cifar數據bin文件的結構相同,所以cifar轉換數據代碼比mnist的代碼更加的模塊化,分為源數據讀取模塊(image_read函數),把lmdb(leveldb)數據轉換的變量聲明,句柄(函數)調用都放到定義的caffe::db子空間中,這樣簡化了代碼,而且使得代碼更加清晰。
?
一:程序開始
和轉換mnist數據不同的是,cifar并沒有使用gflags命令行解析工具;所以也沒有通過gflags的宏定義來指定要轉換的數據類型,而是把轉換的類型參數直接作為main()函數的參數(這種方式便于理解)。
在Create.sh文件中,調用convert_cifar_data.bin語句為:
./build/examples/cifar10/convert_cifar_data.bin$DATA $EXAMPLE $DBTYPE
convert_cifar_data.bin程序,程序需要3個參數,分別為源數據路徑,lmdb(leveldb)存儲路徑,要轉換的數據類型lmdb or leveldb
二:數據轉換流程圖
?
三:convert_cifar_data.cpp函數分析
?
1引入必要的頭文件和命名空間
?
[cpp]?view plaincopy
#include?<fstream>???#include?<string>??#include?"boost/scoped_ptr.hpp"??#include?"glog/logging.h"??#include?"google/protobuf/text_format.h"??#include?"stdint.h"??#include?"caffe/proto/caffe.pb.h"??#include?"caffe/util/db.hpp"?? 頭文件和convert_mnist_data.cpp的區別:
?
1,沒有引入gflags命令行解析工具;
2,沒有引入leveldb和lmdb的數據頭文件
3,引入了"boost/scoped_ptr.hpp"智能指針頭文件
4,引入"caffe/util/db.hpp"頭文件,里面包裝了對lmdb和leveldb數據對象的操作內容
?
[cpp]?view plaincopy
using?caffe::Datum;??using?boost::scoped_ptr;??using?std::string;??namespace?db?=?caffe::db;?? 命名空間區別:
?
1,沒有引入全部caffe命名空間,而是局部引入了兩個caffe命名空間下的子空間 caffe::Datum和caffe::db
2,引入boost::scoped_ptr;智能指針命名空間,智能指針,它能夠保證在離開作用域后對象被自動釋放;在mnist數據轉換代碼中,經常出現delete batch等刪除臨時變量的指令,通過智能指針可以自動刪除過期的變量,對于控制程序內存占用很實用。
2 main()函數
接收參數,調用轉換函數convet_dataset()
3 convet_dataset()函數
3.1以智能指針的方式創建db::DB類型的對象 train_db
?
[cpp]?view plaincopy
scoped_ptr<db::DB>??train_db(db::GetDB(db_type));?? 智能指針的創建方式類似泛型的格式,上面通過db.cpp內定義的命名的子命名空間中db的“成員函數”GetDB函數來初始化train_db對象
?
3.2 創建lmdb數據對象
3.2.1創建環境;設置環境參數,打開環境
調用tran_db對象的open方法,以“對db::NEW的方式,創建lmdb(leveldb)類型文件
?
[cpp]?view plaincopy
train_db->Open(output_folder+?"/cifar10_train_"?+?db_type,db::NEW);?? db命名空間中open函數具體實現代碼:
?
?
[cpp]?view plaincopy
void?LMDB::Open(const?string&?source,?Mode?mode)?{????MDB_CHECK(mdb_env_create(&mdb_env_));?MDB_CHECK(mdb_env_set_mapsize(mdb_env_,?LMDB_MAP_SIZE));??if?(mode?==?NEW)?{??????CHECK_EQ(mkdir(source.c_str(),0744),?0)?<<?"mkdir?"?<<?source?<<"failed";????}??int?flags?=?0;????if?(mode?==?READ)?{??????flags?=?MDB_RDONLY?|?MDB_NOTLS;????}????MDB_CHECK(mdb_env_open(mdb_env_,source.c_str(),?flags,?0664));??LOG(INFO)?<<?"Openedlmdb?"?<<?source;??}?? 3.2.2創建并打開transaction操作句柄,打開數據庫句柄
?
調用db命名空間中的Transaction方法,來創建句柄對象txn
scoped_ptr<db::Transaction> ?txn(train_db->NewTransaction());
db命名空間中NewTransaction()函數代碼
//在lmdb環境中創建操作句柄
?
[cpp]?view plaincopy
LMDBTransaction*?LMDB::NewTransaction()?{????MDB_txn*?mdb_txn;????MDB_CHECK(mdb_txn_begin(mdb_env_,NULL,?0,?&mdb_txn));??MDB_CHECK(mdb_dbi_open(mdb_txn,NULL,?0,?&mdb_dbi_));??return?new?LMDBTransaction(&mdb_dbi_,mdb_txn);??}?? 3.3 定義數據結構文件
?
?
[cpp]?view plaincopy
const?int?kCIFARSize?=32;??const?intkCIFARImageNBytes?=?3072;?const?intkCIFARBatchSize?=?10000;?const?int?kCIFARTrainBatches=?5;??????int?label;????charstr_buffer[kCIFARImageNBytes];???Datum?datum;????datum.set_channels(3);????datum.set_height(kCIFARSize);????datum.set_width(kCIFARSize);?? 3.4 打開源數據文件
?
下載的Cifar數據存放在6個bin文件內,從data_batch_1.bin到data_batch_5.bin;本文以循環的方式分別讀取每個bin文件。每個bin文件存儲1萬張圖片
?
[cpp]?view plaincopy
for?(int?fileid?=?0;fileid?<?kCIFARTrainBatches;?++fileid)?{??snprintf(str_buffer,?kCIFARImageNBytes,?"/data_batch_%d.bin",?fileid?+?1);??std::ifstream?data_file((input_folder?+?str_buffer).c_str(),std::ios::in|?std::ios::binary);??????CHECK(data_file)?<<?"Unable?to?open?train?file?#"?<<fileid?+?1;????????????????????????????? 3.5 讀取源數據文件
?
和mnist不同的是,mnist源數據集有4個文件;mnist讀取數據時,分別調用文件讀取函數read(),感覺這是由于mnist源數據中label數據和image數據中存儲的內容不統一,image文件中除了存儲圖像數據外,還存儲了圖像結構數據;而圖像結構數據和圖像數據讀取的方式不一樣,而且還涉及到大端小端的轉換;所以沒有定義一個統一的圖像讀取函數來讀取;本項由于image和標簽數據都存儲在同一個bin文件中,所以可以定義統一的圖片讀取函數read_image來讀取源數據內容。
?
[cpp]?view plaincopy
for?(int?itemid?=?0;itemid?<?kCIFARBatchSize;?++itemid)?{????????read_image(&data_file,?&label,str_buffer);??void?read_image(std::ifstream*?file,int*?label,?char*buffer)?{???????????charlabel_char;???????????file->read(&label_char,?1);???????????*label?=?label_char;??????????file->read(buffer,kCIFARImageNBytes);???????????return;???????????}?? 3.6 讀取的數據賦值到“轉換”數據對象datum,并序列化
?
?
[cpp]?view plaincopy
datum.set_label(label);??datum.set_data(str_buffer,kCIFARImageNBytes);??string?out;??CHECK(datum.SerializeToString(&out));?? 3.7 把數據寫入數據庫
?
?
[cpp]?view plaincopy
int?length?=snprintf(str_buffer,?kCIFARImageNBytes,?"%05d",fileid?*kCIFARBatchSize?+?itemid);?? //上一行代碼有兩個作用:
?
1,把fileid * kCIFARBatchSize + itemid的值賦值給str_buffer,此處的賦值為每個樣本(圖片)的id,
2,給length賦值,此處length=5
?
[cpp]?view plaincopy
string?out;??txn->Put(string(str_buffer,?length),out); //db命名空間中,Put函數代碼;
?
?
[cpp]?view plaincopy
void?LMDBTransaction::Put(conststring&?key,const?string&?value)?{????MDB_val?mdb_key,?mdb_value;??mdb_key.mv_data?=?const_cast<char*>(key.data());??mdb_key.mv_size?=?key.size();????mdb_value.mv_data?=?const_cast<char*>(value.data());????mdb_value.mv_size?=?value.size();????MDB_CHECK(mdb_put(mdb_txn_,?*mdb_dbi_,&mdb_key,?&mdb_value,?0));??}?? 3.8 把數據庫寫入lmdb文件并關閉寫入環境
?
//這個commit函數和close函數,不是在caffe:db命名空間中定義的函數,估計是caffe命名空間中自帶的函數。
?
[cpp]?view plaincopy
txn->Commit();??train_db->Close();?? 3.9用上面類似的方法把測試集寫入lmdb文件中
?
?
四,相關文件
convert_cifar10_data.cpp文件
?
[cpp]?view plaincopy
??#include?<fstream>??//?NOLINT(readability/streams),文件輸入輸出必備的文件流??#include?<string>????#include?"boost/scoped_ptr.hpp"//智能指針??#include?"glog/logging.h"//用于日志記錄,具體記錄什么不是很清楚,??#include?"google/protobuf/text_format.h"//用于解析.prototxt文件的??#include?"stdint.h"????#include?"caffe/proto/caffe.pb.h"?//解析.prototxt文件的頭文件??#include?"caffe/util/db.hpp"?//db.cpp文件中定義了NewTransaction(),Open()等leveldb和lmdb操作函數????using?caffe::Datum;??using?boost::scoped_ptr;using?std::string;??namespace?db?=?caffe::db;??const?int?kCIFARSize?=?32;??const?int?kCIFARImageNBytes?=?3072;const?int?kCIFARBatchSize?=?10000;const?int?kCIFARTrainBatches?=?5;???????void?read_image(std::ifstream*?file,?int*?label,?char*?buffer)?{??????char?label_char;??????file->read(&label_char,?1);????*label?=?label_char;????file->read(buffer,?kCIFARImageNBytes);??????return;??????}????void?convert_dataset(const?string&?input_folder,?const?string&?output_folder,??????const?string&?db_type)?{????scoped_ptr<db::DB>?train_db(db::GetDB(db_type));??train_db->Open(output_folder?+?"/cifar10_train_"?+?db_type,?db::NEW);??scoped_ptr<db::Transaction>?txn(train_db->NewTransaction());????int?label;????char?str_buffer[kCIFARImageNBytes];??Datum?datum;????datum.set_channels(3);????datum.set_height(kCIFARSize);????datum.set_width(kCIFARSize);??????LOG(INFO)?<<?"Writing?Training?data";????for?(int?fileid?=?0;?fileid?<?kCIFARTrainBatches;?++fileid)?{????????LOG(INFO)?<<?"Training?Batch?"?<<?fileid?+?1;??????snprintf(str_buffer,?kCIFARImageNBytes,?"/data_batch_%d.bin",?fileid?+?1);?????std::ifstream?data_file((input_folder?+?str_buffer).c_str(),????????std::ios::in?|?std::ios::binary);????CHECK(data_file)?<<?"Unable?to?open?train?file?#"?<<?fileid?+?1;??????for?(int?itemid?=?0;?itemid?<?kCIFARBatchSize;?++itemid)?{????????read_image(&data_file,?&label,?str_buffer);??????datum.set_label(label);????????datum.set_data(str_buffer,?kCIFARImageNBytes);????????int?length?=?snprintf(str_buffer,?kCIFARImageNBytes,?"%05d",????????????fileid?*?kCIFARBatchSize?+?itemid);??????string?out;????????CHECK(datum.SerializeToString(&out));????????txn->Put(string(str_buffer,?length),?out);????}????}????txn->Commit();????train_db->Close();??????LOG(INFO)?<<?"Writing?Testing?data";????scoped_ptr<db::DB>?test_db(db::GetDB(db_type));????test_db->Open(output_folder?+?"/cifar10_test_"?+?db_type,?db::NEW);????txn.reset(test_db->NewTransaction());??????std::ifstream?data_file((input_folder?+?"/test_batch.bin").c_str(),????????std::ios::in?|?std::ios::binary);????CHECK(data_file)?<<?"Unable?to?open?test?file.";????for?(int?itemid?=?0;?itemid?<?kCIFARBatchSize;?++itemid)?{??????read_image(&data_file,?&label,?str_buffer);??????datum.set_label(label);??????datum.set_data(str_buffer,?kCIFARImageNBytes);??????int?length?=?snprintf(str_buffer,?kCIFARImageNBytes,?"%05d",?itemid);??????string?out;??????CHECK(datum.SerializeToString(&out));??????txn->Put(string(str_buffer,?length),?out);????}????txn->Commit();????test_db->Close();??}????int?main(int?argc,?char**?argv)?{????if?(argc?!=?4)?{??????printf("This?script?converts?the?CIFAR?dataset?to?the?leveldb?format?used\n"?????????????"by?caffe?to?perform?classification.\n"?????????????"Usage:\n"?????????????"????convert_cifar_data?input_folder?output_folder?db_type\n"?????????????"Where?the?input?folder?should?contain?the?binary?batch?files.\n"?????????????"The?CIFAR?dataset?could?be?downloaded?at\n"?????????????"????http://www.cs.toronto.edu/~kriz/cifar.html\n"?????????????"You?should?gunzip?them?after?downloading.\n");????}?else?{??????google::InitGoogleLogging(argv[0]);??????convert_dataset(string(argv[1]),?string(argv[2]),?string(argv[3]));????????????}????return?0;??}?? db.cpp 文件
?
里面定義了caffe名字空間和其子空間db
?
[cpp]?view plaincopy
#include?"caffe/util/db.hpp"????#include?<sys/stat.h>??#include?<string>????namespace?caffe?{?namespace?db?{????const?size_t?LMDB_MAP_SIZE?=?1099511627776;????void?LevelDB::Open(const?string&?source,?Mode?mode)?{????leveldb::Options?options;??options.block_size?=?65536;????options.write_buffer_size?=?268435456;????options.max_open_files?=?100;????options.error_if_exists?=?mode?==?NEW;??options.create_if_missing?=?mode?!=?READ;??leveldb::Status?status?=?leveldb::DB::Open(options,?source,?&db_);??CHECK(status.ok())?<<?"Failed?to?open?leveldb?"?<<?source???????????????????????<<?std::endl?<<?status.ToString();????LOG(INFO)?<<?"Opened?leveldb?"?<<?source;??}??????void?LMDB::Open(const?string&?source,?Mode?mode)?{????MDB_CHECK(mdb_env_create(&mdb_env_));??MDB_CHECK(mdb_env_set_mapsize(mdb_env_,?LMDB_MAP_SIZE));??if?(mode?==?NEW)?{??????CHECK_EQ(mkdir(source.c_str(),?0744),?0)?<<?"mkdir?"?<<?source?<<?"failed";????}??int?flags?=?0;????if?(mode?==?READ)?{??????flags?=?MDB_RDONLY?|?MDB_NOTLS;????}????MDB_CHECK(mdb_env_open(mdb_env_,?source.c_str(),?flags,?0664));??LOG(INFO)?<<?"Opened?lmdb?"?<<?source;??}????LMDBCursor*?LMDB::NewCursor()?{????MDB_txn*?mdb_txn;????MDB_cursor*?mdb_cursor;????MDB_CHECK(mdb_txn_begin(mdb_env_,?NULL,?MDB_RDONLY,?&mdb_txn));????MDB_CHECK(mdb_dbi_open(mdb_txn,?NULL,?0,?&mdb_dbi_));????MDB_CHECK(mdb_cursor_open(mdb_txn,?mdb_dbi_,?&mdb_cursor));????return?new?LMDBCursor(mdb_txn,?mdb_cursor);??}????LMDBTransaction*?LMDB::NewTransaction()?{????MDB_txn*?mdb_txn;????MDB_CHECK(mdb_txn_begin(mdb_env_,?NULL,?0,?&mdb_txn));??MDB_CHECK(mdb_dbi_open(mdb_txn,?NULL,?0,?&mdb_dbi_));??return?new?LMDBTransaction(&mdb_dbi_,?mdb_txn);??}????void?LMDBTransaction::Put(const?string&?key,?const?string&?value)?{????MDB_val?mdb_key,?mdb_value;????mdb_key.mv_data?=?const_cast<char*>(key.data());????mdb_key.mv_size?=?key.size();????mdb_value.mv_data?=?const_cast<char*>(value.data());????mdb_value.mv_size?=?value.size();????MDB_CHECK(mdb_put(mdb_txn_,?*mdb_dbi_,?&mdb_key,?&mdb_value,?0));??}????DB*?GetDB(DataParameter::DB?backend)?{????switch?(backend)?{????case?DataParameter_DB_LEVELDB:??????return?new?LevelDB();????case?DataParameter_DB_LMDB:??????return?new?LMDB();????default:??????LOG(FATAL)?<<?"Unknown?database?backend";????}??}????DB*?GetDB(const?string&?backend)?{????if?(backend?==?"leveldb")?{??????return?new?LevelDB();????}?else?if?(backend?==?"lmdb")?{??????return?new?LMDB();????}?else?{??????LOG(FATAL)?<<?"Unknown?database?backend";????}??}????}??}??
五,以上代碼注釋為個人理解,如有遺漏,錯誤還望大家多多交流,指正,以便共同學習,進步!!
Caffe2——cifar10數據集創建lmdb或leveldb類型的數據
標簽:class???log???com???代碼???使用???src???http???si???html???
原文:http://www.cnblogs.com/yymn/p/4479218.html
總結
以上是生活随笔為你收集整理的Caffe2——cifar10数据集创建lmdb或leveldb类型的数据的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。