1. 程式人生 > >【神經網路與深度學習】Caffe原始碼中各種依賴庫的作用及簡單使用

【神經網路與深度學習】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資料交換格式。可用於通訊協議、資料儲存等領域的語言無關、平臺無關、可擴充套件的序列化結構資料格式。

要使用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.html
	boost::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=270
	int 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.aspx
	const 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;

	//單個日誌檔案最大,單位M
	FLAGS_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/1255365
	leveldb::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,value1
	std::string key = "key";
	std::string value = "value";

	//write
	status = db->Put(leveldb::WriteOptions(), key, value);
	assert(status.ok());

	//read
	status = db->Get(leveldb::ReadOptions(), key, &value);
	assert(status.ok());
	std::cout << value << std::endl;
	std::string key2 = "key2";

	//move the value under key to key2
	status = db->Put(leveldb::WriteOptions(), key2, value);
	assert(status.ok());
	//delete
	status = 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.c
	int 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;  // ID
		required string    str = 2;  // str
		optional 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			2

int 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		3

int 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 file
	test_HDF5_write_HDF5_Data();
	// 2-->./examples/h5_read.c:This example reads hyperslab from the SDS.h5 file
	test_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;
}

GitHubhttps://github.com/fengbingchun/Caffe_Test