DeepLearning学习笔记-HDF5
前言
理论上,HDF5
与深度学习是半毛钱关系没有的,因为它定义了一种数据格式与解析方法,同时,也提供了开源库代码,但是,是因为PointNet
才接触的这个库,PointNet
的数据集是*.h5
的文件,要想解析这个文件,就得了解下HDF5
这个格式。
一、HDF5简介
HDF5
全称Hierarchical Data Format
翻译成中文为层次性数据格式第5版,是一种存储相同数据类型的大数据组的机制,适用于可被层次性组织且数据集需要被元数据标记的数据模型。上述介绍晦涩难懂,翻译成人话
就是,可存储多组类型一致,数量一致的数据。
1.1 组织结构
整个文件格式的组织结构如上图所示(经典图,百度盗图,应该不算是侵权吧)。
先看左边的图吧,Group
与Dataset
是两个核心概念,Group
类似与一个文件夹(容器),其中包含多个Dataset
,而Dataset
中则包含数据的属性与数据本身的信息,可以将这个过程看做是win
下的文件管理模式,Group
是文件夹,Dataset
是文件夹里面的数据,采用这种机制的目的是为了更高效的实现数据的管理,从某种意义上说,h5
是实现了将多种数据存在同一个文件中进行保存与传递。
需要注意的是,Group
的名字可以随便设置,但是,root
点的group name
是恒定的,叫做/
,对于一个陌生的h5
文件,只需要找到/
,就可以随意访问子Group
了。ps
: 利用C++
进行数据访问的时候就采用从root
入手的方式进行遍历的。
1.2 数据构成
介绍图之二,介绍的是Dataset
的组成关系,对于一组数据而言,需要了解一下数据的组成部分,比如,数据类型是什么,比如该数据中包含的数据的组数,以及数据本身的一些属性,在这里,会有一个Metadata
的构造,其中存储的就是有关于数据本身的一系列属性,例如,Dataspace
中的Dimensions
可以指导如何解析Data
。
解释下上图中的一些数字,首先看Dataspace
里面的数据Rank = 3
该数据表示,在Dimensions
中有3(Rank)
个数据Dim 1,Dim 2, Dim 3
来介绍数据;接下来讲解下Dimensions
中的4,5,6
,其中,4,5
表示每个数据中有4行5列,6
则表示有6个数据。
二、HDF5库介绍
2.1下载与安装
由于我的系统是win10
,所以在这里我主要提供win
下的一些方法,HDF5
的下载链接为:
下载地址
2.2数据查看
数据查看,可使用的方法有:
HDFView
H5dump
第一个工具,我下载下来了,但是,win
下运行闪退,相关文档介绍需要配置java
的环境,不专业,所以放弃了;
H5dump
是在py
下用的,使用方法为:
H5dump *.h5
即可显示该文件中存放的数据。如果想要校验下自己文件中的数据是否正常或了解数据形式,可以通过该命令查看。
三、读取*.h5文件
vs2015
相关的库可从链接中下载:
下载地址
#include <iostream>
#include <H5Cpp.h>
#include <fstream>
using namespace std;
using namespace H5;
int main(int argc, char **argv)
{
//打开文件
H5File file(argv[1], H5F_ACC_RDONLY);
//获取根节点并打印root的子节点数量
Group root(file.getObjId("/"));
cout << "size() = " << root.getNumObjs() << endl;
//for循环,依次访问root的子节点
for (hsize_t i = 0; i < root.getNumObjs(); i++)
{
// 用 Index 为参数获取 Object 名字
const H5std_string name = root.getObjnameByIdx(i);
cout << "Obj_name_" << i + 1 << ": " << name.c_str() << endl;
//打开数据
DataSet dset(root.getObjId(name));
DataSpace dsp = dset.getSpace();
//记录该dataspace中的数据维度,是指有rank个维度记录数据的维度属性
//例如,有rank个数据来记录data所包含的信息
int rank = dsp.getSimpleExtentNdims();
//创建数组存储数据本身的维度:2048*2048*3
//表示:2048个数据,每组数据有2048个点位,每个点位有3个维度(xyz)组成
//创建数组存储维度大小
hsize_t *dims = new hsize_t[rank];
int ndims = dsp.getSimpleExtentDims(dims);
for (int i = 0; i < rank; i++)
cout << "Dimension_ " << i + 1 << " = " << dims[i] << endl;
DataType dt = dset.getDataType();
//将data读取到buf中
hsize_t data_size = dset.getInMemDataSize() / sizeof(float);
float *buf = new float[data_size];
dset.read(buf, dt);
//根据属性信息,解析buf
char file[50];
int elementSize = 1;
if (rank == 3) elementSize = dims[2];
for (int count = 0; count < dims[0]; count++) {
sprintf(file, "data//%d.asc", count);
ofstream ofout(file);
for (int i = dims[1] * count * elementSize; i < dims[1] * (count +1) * elementSize; i++)
{
if (i % elementSize != 0 && i != dims[1] * count * elementSize) ofout << buf[i] << " ";
else ofout << endl << buf[i] << " ";
}
ofout.close();
}
delete[]dims;
dims = nullptr;
delete[]buf;
buf = nullptr;
dt.close();
dsp.close();
dset.close();
system("pause");
}
root.close();
file.close();
system("pause");
return 0;
}
四、写入*.h5文件
折腾了一上午,总算是可以将数据保存为*.h5
文件了,对我而言,我用的事最简单的方法,当然,此方法可能还存在诸多bug
,但目前没有过多的纠结,先以实现功能,满足需求为主,对了,在这里,我需要重申下我的需求:可手动制作PointNet
的数据集。
//filename表示要保存的文件名,后缀名为h5
//indata表示要保存的数据
void createFile(char *filename, std::vector<std::vector<point>> indata)
{
int i, j;
int data[2][5][3] = {0}; // buffer for data to write
for (j = 0; j <2; j++)
{
for (i = 0; i < 5; i++) {
data[j][i][0] = indata[j][i](0);
data[j][i][1] = indata[j][i](1);
data[j][i][2] = indata[j][i](2);
}
}
//新建文件
H5File file(filename, H5F_ACC_TRUNC);
//根据数据描述信息构建space
size_t dimsf[3];
dimsf[0] = 2;
dimsf[1] = 5;
dimsf[2] = 3;
DataSpace dataspace(3, dimsf);
//设定保存数据的类型
IntType datatype(PredType::NATIVE_INT);
datatype.setOrder(H5T_ORDER_LE);
//创建dataset
DataSet dataset = file.createDataSet("first", datatype, dataspace);
//写入文件
dataset.write(data, PredType::NATIVE_INT);
//关闭数据集与文件
dataset.close();
file.close();
}
测试程序
int main(int argc, char **argv)
{
if (argc == 1) {
//模拟数据
std::vector<std::vector<point>> data;
std::vector<point> epch;
epch.push_back(point(1, 2, 4));
epch.push_back(point(3, 2, 9));
epch.push_back(point(4, 2, 3));
epch.push_back(point(6, 7, 1));
epch.push_back(point(9, 1, 8));
data.push_back(epch);
std::vector<point> epch1;
epch1.push_back(point(11, 2, 4));
epch1.push_back(point(31, 2, 9));
epch1.push_back(point(41, 2, 3));
epch1.push_back(point(61, 7, 1));
epch1.push_back(point(91, 1, 8));
data.push_back(epch1);
createFile("out.h5", data);
}
if (argc == 2)
readFile(argv[1]);
}