Caffe源码中各种依赖库的作用及简单使用
1.??????Boost庫:它是一個可移植、跨平臺,提供源代碼的C++庫,作為標準庫的后備。
在Caffe中用到的Boost頭文件包括:
(1)、shared_ptr.hpp:智能指針,使用它可以不需要考慮內存釋放的問題;
(2)、date_time/posix_time/posix_time.hpp:時間操作函數;
(3)、python.hpp:C++/Python互操作;
(4)、make_shared.hpp:make_shared工廠函數代替new操作符;
(5)、python/raw_function.hpp:C++/Python互操作;
(6)、python/suite/indexing/vector_indexing_suite.hpp:C++/Python互操作;
(7)、thread.hpp:線程操作;
(8)、math/special_functions/next.hpp:數學函數;
2.??????GFlags庫:它是google的一個開源的處理命令行參數的庫,使用C++開發,可以替代getopt函數。GFlags與getopt函數不同,在GFlags中,標記的定義分散在源代碼中,不需要列舉在一個地方。
3.??????GLog庫:它是一個應用程序的日志庫,提供基于C++風格的流的日志API,以及各種輔助的宏。它的使用方式與C++的stream操作類似。
4.??????LevelDB庫:它是google實現的一個非常高效的Key-Value數據庫。它是單進程的服務,性能非常高。它只是一個C/C++編程語言的庫,不包含網絡服務封裝。
LevelDB特點:(1)、LevelDB是一個持久化存儲的KV系統,它將大部分數據存儲到磁盤上;(2)、LevelDB在存儲數據時,是根據記錄的Key值有序存儲的;(3)、像大多數KV系統一樣,LevelDB的操作接口很簡單,基本操作包括寫記錄,讀記錄以及刪除記錄,也支持針對多條操作的原子批量操作;(4)、LevelDB支持數據快照(snapshot)功能,使得讀取操作不受寫操作影響,可以在讀操作過程中始終看到一致的數據;(5)、LevelDB支持數據壓縮(Snappy)等操作。
5.??????LMDB庫:它是一個超級快、超級小的Key-Value數據存儲服務,是由OpenLDAP項目的Symas開發的。使用內存映射文件,因此讀取的性能跟內存數據庫一樣,其大小受限于虛擬地址空間的大小。
6.??????ProtoBuf庫:GoogleProtocol Buffer(簡稱ProtoBuf),它是一種輕便高效的結構化數據存儲格式,可以用于結構化數據串行化,或者說序列化。它很適合做數據存儲或RPC數據交換格式??捎糜谕ㄐ艆f議、數據存儲等領域的語言無關、平臺無關、可擴展的序列化結構數據格式。
要使用ProtoBuf庫,首先需要自己編寫一個.proto文件,定義我們程序中需要處理的結構化數據,在protobuf中,結構化數據被稱為Message。在一個.proto文件中可以定義多個消息類型。用Protobuf編譯器(protoc.exe)將.proto文件編譯成目標語言,會生成對應的.h文件和.cc文件,.proto文件中的每一個消息有一個對應的類。
7.??????HDF5庫:HDF(HierarchicalData File)是美國國家高級計算應用中心(NCSA)為了滿足各種領域研究需求而研制的一種能高效存儲和分發科學數據的新型數據格式。它可以存儲不同類型的圖像和數碼數據的文件格式,并且可以在不同類型的機器上傳輸,同時還有統一處理這種文件格式的函數庫。HDF5推出于1998年,相較于以前的HDF文件,可以說是一種全新的文件格式。HDF5是用于存儲科學數據的一種文件格式和庫文件。
HDF5是分層式數據管理結構。HDF5不但能處理更多的對象,存儲更大的文件,支持并行I/O,線程和具備現代操作系統與應用程序所要求的其它特性,而且數據模型變得更簡單,概括性更強。
HDF5只有兩種基本結構,組(group)和數據集(dataset)。組,包含0個或多個HDF5對象以及支持元數據(metadata)的一個群組結構。數據集,數據元素的一個多維數組以及支持元數據。
8.??????snappy庫:它是一個C++庫,用來壓縮和解壓縮的開發包。它旨在提供高速壓縮速度和合理的壓縮率。Snappy比zlib更快,但文件相對要大20%到100%。
?下面為各個庫的簡單使用舉例:
#include "stdafx.h"
#include <iostream>
#include <string>
#include <assert.h>
#include <fstream>#include <boost/shared_ptr.hpp>
#include <boost/array.hpp>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <gflags/gflags.h>
#include <glog/logging.h>
#include <levelDB/db.h>
#include <lmdb.h>
#include <hdf5.h>
#include <snappy-c.h>#include <windows.h>#include "ml.helloworld.pb.h"int test_Boost();
int test_GFlags(int argc, char* argv[]);
int test_GLog();
int test_LevelDB();
int test_LMDB();
int test_ProtoBuf();
int test_HDF5();
int test_Snappy();int main(int argc, char* argv[])
{//std::cout << argv[0] << std::endl;//E:\GitCode\Caffe\lib\dbg\x86_vc12\testThridLibrary[dbg_x86_vc12].exe//test_Boost();//test_GFlags(argc, argv);//test_GLog();//test_LevelDB();//test_LMDB();//test_ProtoBuf();//test_HDF5();test_Snappy();std::cout << "ok!!!" << std::endl;return 0;
}class implementation {
public:~implementation() { std::cout << "destroying implementation\n"; }void do_something() { std::cout << "did something\n"; }
};int test_Boost()
{//http://www.cnblogs.com/tianfang/archive/2008/09/19/1294521.htmlboost::shared_ptr<implementation> sp1(new implementation());std::cout << "The Sample now has " << sp1.use_count() << " references\n";boost::shared_ptr<implementation> sp2 = sp1;std::cout << "The Sample now has " << sp2.use_count() << " references\n";sp1.reset();std::cout << "After Reset sp1. The Sample now has " << sp2.use_count() << " references\n";sp2.reset();std::cout << "After Reset sp2.\n";return 0;
}DEFINE_bool(big_menu, true, "Include 'advanced' options in the menu listing");
DEFINE_string(languages, "english,french,german", "comma-separated list of languages to offer in the 'lang' menu");int test_GFlags(int argc, char* argv[])
{//http://dreamrunner.org/blog/2014/03/09/gflags-jian-ming-shi-yong///http://www.leoox.com/?p=270int tmp_argc = 3;char** tmp_argv = NULL;tmp_argv = new char*[3];tmp_argv[0] = "";tmp_argv[1] = "--big_menu=false";tmp_argv[2] = "--languages=chinese";//google::ParseCommandLineFlags(&argc, &argv, true);google::ParseCommandLineFlags(&tmp_argc, &tmp_argv, true);std::cout << "argc=" << argc << std::endl;if (FLAGS_big_menu) {std::cout << "big menu is ture" << std::endl;}else {std::cout << "big menu is flase" << std::endl;}std::cout << "languages=" << FLAGS_languages << std::endl;return 0;
}void thread1_test()
{std::string strTmp = "thread1_test";for (int i = 0; i< 1000; i++) {//LOG(INFO) << i;LOG_IF(INFO, i < 10) << i;//CHECK_EQ(i, 100) << "error!";//LOG(INFO) << strTmp;//Sleep(10);}
}void thread2_test()
{std::string strTmp = "thread2_test";for (int i = 1000; i< 2000; i++) {//LOG(INFO) << i;LOG_IF(INFO, i < 1100) << i;//LOG(INFO) << strTmp;//Sleep(10);}
}int test_GLog()
{//http://www.yeolar.com/note/2014/12/20/glog///http://www.cppblog.com/pizzx/archive/2014/06/18/207320.aspxconst char* exe = "E:/GitCode/Caffe/lib/dbg/x86_vc12/testThridLibrary[dbg_x86_vc12].exe";//Initialize Google's logging library.//google::InitGoogleLogging(argv[0]);google::InitGoogleLogging(exe);//為不同級別的日志設置不同的文件basename。google::SetLogDestination(google::INFO, "E:/tmp/loginfo");google::SetLogDestination(google::WARNING, "E:/tmp/logwarn");google::SetLogDestination(google::GLOG_ERROR, "E:/tmp/logerror");//緩存的最大時長,超時會寫入文件FLAGS_logbufsecs = 60;//單個日志文件最大,單位MFLAGS_max_log_size = 10;//設置為true,就不會寫日志文件了FLAGS_logtostderr = false;boost::thread t1(boost::bind(&thread1_test));boost::thread t2(boost::bind(&thread2_test));t1.join();t2.join();//LOG(FATAL)<<"exit";google::ShutdownGoogleLogging();return 0;
}int test_LevelDB()
{//http://www.cnblogs.com/haippy/archive/2011/12/04/2276064.html//http://www.bubuko.com/infodetail-411090.html//http://qiuqiang1985.iteye.com/blog/1255365leveldb::DB* db;leveldb::Options options;options.create_if_missing = true;leveldb::Status status = leveldb::DB::Open(options, "E:/tmp/testLevelDB", &db);assert(status.ok());//write key1,value1std::string key = "key";std::string value = "value";//writestatus = db->Put(leveldb::WriteOptions(), key, value);assert(status.ok());//readstatus = db->Get(leveldb::ReadOptions(), key, &value);assert(status.ok());std::cout << value << std::endl;std::string key2 = "key2";//move the value under key to key2status = db->Put(leveldb::WriteOptions(), key2, value);assert(status.ok());//deletestatus = db->Delete(leveldb::WriteOptions(), key);assert(status.ok());status = db->Get(leveldb::ReadOptions(), key2, &value);assert(status.ok());std::cout << key2 << "===" << value << std::endl;status = db->Get(leveldb::ReadOptions(), key, &value);if (!status.ok())std::cerr << key << " " << status.ToString() << std::endl;else std::cout << key << "===" << value << std::endl;delete db;return 0;
}#define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr)
#define RES(err, expr) ((rc = expr) == (err) || (CHECK(!rc, #expr), 0))
#define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \"%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort()))int test_LMDB()
{//http://www.jianshu.com/p/yzFf8j//./lmdb-mdb.master/libraries/liblmdb/mtest.cint i = 0, j = 0, rc;MDB_env *env;MDB_dbi dbi;MDB_val key, data;MDB_txn *txn;MDB_stat mst;MDB_cursor *cursor, *cur2;MDB_cursor_op op;int count;int *values;char sval[32] = "";srand(time(NULL));count = (rand() % 384) + 64;values = (int *)malloc(count*sizeof(int));for (i = 0; i<count; i++) {values[i] = rand() % 1024;}E(mdb_env_create(&env));E(mdb_env_set_maxreaders(env, 1));E(mdb_env_set_mapsize(env, 10485760));//E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP /*|MDB_NOSYNC*/, 0664));E(mdb_env_open(env, "E:/tmp/testLMDB", MDB_FIXEDMAP /*|MDB_NOSYNC*/, 0664));E(mdb_txn_begin(env, NULL, 0, &txn));E(mdb_dbi_open(txn, NULL, 0, &dbi));key.mv_size = sizeof(int);key.mv_data = sval;printf("Adding %d values\n", count);for (i = 0; i<count; i++) {sprintf(sval, "%03x %d foo bar", values[i], values[i]);/* Set <data> in each iteration, since MDB_NOOVERWRITE may modify it */data.mv_size = sizeof(sval);data.mv_data = sval;if (RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE))) {j++;data.mv_size = sizeof(sval);data.mv_data = sval;}}if (j) printf("%d duplicates skipped\n", j);E(mdb_txn_commit(txn));E(mdb_env_stat(env, &mst));E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn));E(mdb_cursor_open(txn, dbi, &cursor));while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {printf("key: %p %.*s, data: %p %.*s\n",key.mv_data, (int)key.mv_size, (char *)key.mv_data,data.mv_data, (int)data.mv_size, (char *)data.mv_data);}CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");mdb_cursor_close(cursor);mdb_txn_abort(txn);j = 0;key.mv_data = sval;for (i = count - 1; i > -1; i -= (rand() % 5)) {j++;txn = NULL;E(mdb_txn_begin(env, NULL, 0, &txn));sprintf(sval, "%03x ", values[i]);if (RES(MDB_NOTFOUND, mdb_del(txn, dbi, &key, NULL))) {j--;mdb_txn_abort(txn);}else {E(mdb_txn_commit(txn));}}free(values);printf("Deleted %d values\n", j);E(mdb_env_stat(env, &mst));E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn));E(mdb_cursor_open(txn, dbi, &cursor));printf("Cursor next\n");while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) {printf("key: %.*s, data: %.*s\n",(int)key.mv_size, (char *)key.mv_data,(int)data.mv_size, (char *)data.mv_data);}CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");printf("Cursor last\n");E(mdb_cursor_get(cursor, &key, &data, MDB_LAST));printf("key: %.*s, data: %.*s\n",(int)key.mv_size, (char *)key.mv_data,(int)data.mv_size, (char *)data.mv_data);printf("Cursor prev\n");while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_PREV)) == 0) {printf("key: %.*s, data: %.*s\n",(int)key.mv_size, (char *)key.mv_data,(int)data.mv_size, (char *)data.mv_data);}CHECK(rc == MDB_NOTFOUND, "mdb_cursor_get");printf("Cursor last/prev\n");E(mdb_cursor_get(cursor, &key, &data, MDB_LAST));printf("key: %.*s, data: %.*s\n",(int)key.mv_size, (char *)key.mv_data,(int)data.mv_size, (char *)data.mv_data);E(mdb_cursor_get(cursor, &key, &data, MDB_PREV));printf("key: %.*s, data: %.*s\n",(int)key.mv_size, (char *)key.mv_data,(int)data.mv_size, (char *)data.mv_data);mdb_cursor_close(cursor);mdb_txn_abort(txn);printf("Deleting with cursor\n");E(mdb_txn_begin(env, NULL, 0, &txn));E(mdb_cursor_open(txn, dbi, &cur2));for (i = 0; i<50; i++) {if (RES(MDB_NOTFOUND, mdb_cursor_get(cur2, &key, &data, MDB_NEXT)))break;printf("key: %p %.*s, data: %p %.*s\n",key.mv_data, (int)key.mv_size, (char *)key.mv_data,data.mv_data, (int)data.mv_size, (char *)data.mv_data);E(mdb_del(txn, dbi, &key, NULL));}printf("Restarting cursor in txn\n");for (op = MDB_FIRST, i = 0; i <= 32; op = MDB_NEXT, i++) {if (RES(MDB_NOTFOUND, mdb_cursor_get(cur2, &key, &data, op)))break;printf("key: %p %.*s, data: %p %.*s\n",key.mv_data, (int)key.mv_size, (char *)key.mv_data,data.mv_data, (int)data.mv_size, (char *)data.mv_data);}mdb_cursor_close(cur2);E(mdb_txn_commit(txn));printf("Restarting cursor outside txn\n");E(mdb_txn_begin(env, NULL, 0, &txn));E(mdb_cursor_open(txn, dbi, &cursor));for (op = MDB_FIRST, i = 0; i <= 32; op = MDB_NEXT, i++) {if (RES(MDB_NOTFOUND, mdb_cursor_get(cursor, &key, &data, op)))break;printf("key: %p %.*s, data: %p %.*s\n",key.mv_data, (int)key.mv_size, (char *)key.mv_data,data.mv_data, (int)data.mv_size, (char *)data.mv_data);}mdb_cursor_close(cursor);mdb_txn_abort(txn);mdb_dbi_close(env, dbi);mdb_env_close(env);return 0;
}void ListMsg(const lm::helloworld& msg) {std::cout << msg.id() << std::endl;std::cout << msg.str() << std::endl;
}int test_ProtoBuf()
{//http://www.ibm.com/developerworks/cn/linux/l-cn-gpb///http://blog.163.com/jiang_tao_2010/blog/static/12112689020114305013458///http://www.cnblogs.com/dkblog/archive/2012/03/27/2419010.html// 1-->首先編寫一個ml.helloworld.proto文件,內容如下:/*syntax = "proto2";package lm;message helloworld{required int32 id = 1; // IDrequired string str = 2; // stroptional int32 opt = 3; //optional field}*/// 2-->利用protoc.exe生成ml.helloworld.pb.h和ml.hellowrold.ph.cc// 3-->Writer,將把一個結構化數據寫入磁盤,以便其他人來讀取/*lm::helloworld msg1;msg1.set_id(101);msg1.set_str("hello");// Write the new address book back to disk. std::fstream output("./log", std::ios::out | std::ios::trunc | std::ios::binary);if (!msg1.SerializeToOstream(&output)) {std::cerr << "Failed to write msg." << std::endl;return -1;}*/// 4-->Reader,讀取結構化數據,log文件lm::helloworld msg2;std::fstream input("./log", std::ios::in | std::ios::binary);if (!msg2.ParseFromIstream(&input)) {std::cerr << "Failed to parse address book." << std::endl;return -1;}ListMsg(msg2);return 0;
}#define H5FILE_NAME "E:/tmp/HDF5/SDS.h5"
#define DATASETNAME "IntArray"
#define NX 5 /* dataset dimensions */
#define NY 6
#define RANK 2int test_HDF5_write_HDF5_Data()
{hid_t file, dataset; /* file and dataset handles */hid_t datatype, dataspace; /* handles */hsize_t dimsf[2]; /* dataset dimensions */herr_t status;int data[NX][NY]; /* data to write */int i, j;//Data and output buffer initialization.for (j = 0; j < NX; j++)for (i = 0; i < NY; i++)data[j][i] = i + j + 100;//changed/** 0 1 2 3 4 5* 1 2 3 4 5 6* 2 3 4 5 6 7* 3 4 5 6 7 8* 4 5 6 7 8 9*//** Create a new file using H5F_ACC_TRUNC access,* default file creation properties, and default file* access properties.*/file = H5Fcreate(H5FILE_NAME, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);/** Describe the size of the array and create the data space for fixed* size dataset.*/dimsf[0] = NX;dimsf[1] = NY;dataspace = H5Screate_simple(RANK, dimsf, NULL);/** Define datatype for the data in the file.* We will store little endian INT numbers.*/datatype = H5Tcopy(H5T_NATIVE_INT);status = H5Tset_order(datatype, H5T_ORDER_LE);/** Create a new dataset within the file using defined dataspace and* datatype and default dataset creation properties.*/dataset = H5Dcreate2(file, DATASETNAME, datatype, dataspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);//Write the data to the dataset using default transfer properties.status = H5Dwrite(dataset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data);//Close/release resources.H5Sclose(dataspace);H5Tclose(datatype);H5Dclose(dataset);H5Fclose(file);return 0;
}#define NX_SUB 3 /* hyperslab dimensions */
#define NY_SUB 4
#define NX 7 /* output buffer dimensions */
#define NY 7
#define NZ 3
#define RANK 2
#define RANK_OUT 3int test_HDF5_read_HDF5_data()
{hid_t file, dataset; /* handles */hid_t datatype, dataspace;hid_t memspace;H5T_class_t t_class; /* data type class */H5T_order_t order; /* data order */size_t size; /** size of the data element* stored in file*/hsize_t dimsm[3]; /* memory space dimensions */hsize_t dims_out[2]; /* dataset dimensions */herr_t status;int data_out[NX][NY][NZ]; /* output buffer */hsize_t count[2]; /* size of the hyperslab in the file */hsize_t offset[2]; /* hyperslab offset in the file */hsize_t count_out[3]; /* size of the hyperslab in memory */hsize_t offset_out[3]; /* hyperslab offset in memory */int i, j, k, status_n, rank;for (j = 0; j < NX; j++) {for (i = 0; i < NY; i++) {for (k = 0; k < NZ; k++)data_out[j][i][k] = 0 - 1000;//changed}}/** Open the file and the dataset.*/file = H5Fopen(H5FILE_NAME, H5F_ACC_RDONLY, H5P_DEFAULT);dataset = H5Dopen2(file, DATASETNAME, H5P_DEFAULT);/** Get datatype and dataspace handles and then query* dataset class, order, size, rank and dimensions.*/datatype = H5Dget_type(dataset); /* datatype handle */t_class = H5Tget_class(datatype);if (t_class == H5T_INTEGER) printf("Data set has INTEGER type \n");order = H5Tget_order(datatype);if (order == H5T_ORDER_LE) printf("Little endian order \n");size = H5Tget_size(datatype);printf("Data size is %d \n", (int)size);dataspace = H5Dget_space(dataset); /* dataspace handle */rank = H5Sget_simple_extent_ndims(dataspace);status_n = H5Sget_simple_extent_dims(dataspace, dims_out, NULL);printf("rank %d, dimensions %lu x %lu \n", rank,(unsigned long)(dims_out[0]), (unsigned long)(dims_out[1]));/** Define hyperslab in the dataset.*/offset[0] = 1;offset[1] = 2;count[0] = NX_SUB;count[1] = NY_SUB;status = H5Sselect_hyperslab(dataspace, H5S_SELECT_SET, offset, NULL,count, NULL);/** Define the memory dataspace.*/dimsm[0] = NX;dimsm[1] = NY;dimsm[2] = NZ;memspace = H5Screate_simple(RANK_OUT, dimsm, NULL);/** Define memory hyperslab.*/offset_out[0] = 3;offset_out[1] = 0;offset_out[2] = 0;count_out[0] = NX_SUB;count_out[1] = NY_SUB;count_out[2] = 1;status = H5Sselect_hyperslab(memspace, H5S_SELECT_SET, offset_out, NULL,count_out, NULL);/** Read data from hyperslab in the file into the hyperslab in* memory and display.*/status = H5Dread(dataset, H5T_NATIVE_INT, memspace, dataspace,H5P_DEFAULT, data_out);for (j = 0; j < NX; j++) {for (i = 0; i < NY; i++) printf("%d ", data_out[j][i][0]);printf("\n");}/** 0 0 0 0 0 0 0* 0 0 0 0 0 0 0* 0 0 0 0 0 0 0* 3 4 5 6 0 0 0* 4 5 6 7 0 0 0* 5 6 7 8 0 0 0* 0 0 0 0 0 0 0*//** Close/release resources.*/H5Tclose(datatype);H5Dclose(dataset);H5Sclose(dataspace);H5Sclose(memspace);H5Fclose(file);return 0;
}int test_HDF5()
{//http://wenku.baidu.com/link?url=HDnqbrqqJ27GSvVGTcCbfM-bn5K2QCYxSlqTEtY_jwFvBVi3B97DK6s9qBUwXDjVgMHFQq-MLGSKcMKeGJkq87GF_8vchhsleRWISq9PwO3//http://baike.baidu.com/link?url=TqYZDUzu_XFMYa9XswMS1OVSyboWzu3RtK6L-DiOFZT6zugtXjBUIFa4QHerxZcSbPNuTO84BomEGgxpchWojK//http://www.docin.com/p-608918978.html// 1-->./examples/h5_write.c:This example writes data to the HDF5 filetest_HDF5_write_HDF5_Data();// 2-->./examples/h5_read.c:This example reads hyperslab from the SDS.h5 filetest_HDF5_read_HDF5_data();return 0;
}int test_Snappy()
{//http://baike.baidu.com/link?url=X8PCUvwS0MFJF5xS2DdzMrVDj9hNV8VsXL40W_jgiI1DeGNW5q5PsfEbL9RwUSrIilseenbFiulT1ceONYL5E_//exaples:./snappy_unittest.cc、snappy-test.cc//https://snappy.angeloflogic.com/cpp-tutorial/char* filename = "E:/tmp/snappy/fireworks.jpeg";size_t input_length = 200;snappy_status status;size_t output_length = snappy_max_compressed_length(input_length);char* output = (char*)malloc(output_length);status = snappy_compress(filename, input_length, output, &output_length);if (status != SNAPPY_OK) {std::cout << "snappy compress fail!" << std::endl;}free(output);size_t output_length1;snappy_status status1;status1 = snappy_uncompressed_length(filename, input_length, &output_length1);if (status != SNAPPY_OK) {std::cout << "get snappy uncompress length fail!" << std::endl;}char* output1 = (char*)malloc(output_length1);status1 = snappy_uncompress(filename, input_length, output1, &output_length1);if (status != SNAPPY_OK) {std::cout << "snappy uncompress fail!" << std::endl;}free(output1);return 0;
}
GitHub: https://github.com/fengbingchun/Caffe_Test
總結
以上是生活随笔為你收集整理的Caffe源码中各种依赖库的作用及简单使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux下多线程编程互斥锁和条件变量的
- 下一篇: C/C++各种数据类型转换汇总