Skip to content

Commit

Permalink
Support for half-precision (16-bit) floating-point datasets (#587)
Browse files Browse the repository at this point in the history
* Adding support for half-precision floating-point datasets. Depends on Half library (http://half.sourceforge.net/)
  • Loading branch information
ssbotelh committed Jun 8, 2022
1 parent 5acef60 commit b2f49c0
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 17 deletions.
9 changes: 9 additions & 0 deletions CMake/HighFiveTargetDeps.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@ if(NOT TARGET libdeps)
target_compile_definitions(libdeps INTERFACE BOOST_ALL_NO_LIB H5_USE_BOOST)
endif()

# Half
if(HIGHFIVE_USE_HALF_FLOAT)
find_file(FOUND_HALF half.hpp)
if (NOT FOUND_HALF)
message(FATAL_ERROR "Half-precision floating-point support requested but file half.hpp not found")
endif()
target_compile_definitions(libdeps INTERFACE H5_USE_HALF_FLOAT)
endif()

# Eigen
if(HIGHFIVE_USE_EIGEN)
if (NOT EIGEN3_INCLUDE_DIRS)
Expand Down
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ set(HIGHFIVE_UNIT_TESTS AUTO CACHE STRING "Enable unit tests (requires Catch2 to
set_property(CACHE HIGHFIVE_UNIT_TESTS PROPERTY STRINGS AUTO ON OFF)

option(HIGHFIVE_USE_BOOST "Enable Boost Support" ${USE_BOOST})
option(HIGHFIVE_USE_HALF_FLOAT "Enable half-precision floats" ${USE_HALF_FLOAT})
option(HIGHFIVE_USE_EIGEN "Enable Eigen testing" ${USE_EIGEN})
option(HIGHFIVE_USE_OPENCV "Enable OpenCV testing" ${USE_OPENCV})
option(HIGHFIVE_USE_XTENSOR "Enable xtensor testing" ${USE_XTENSOR})
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ It integrates nicely with other CMake projects by defining (and exporting) a Hig
- selection() / slice support
- parallel Read/Write operations from several nodes with Parallel HDF5
- Advanced types: Compound, Enum, Arrays of Fixed-length strings, References
- half-precision (16-bit) floating-point datasets
- etc... (see [ChangeLog](./CHANGELOG.md))

### Dependencies
Expand All @@ -40,6 +41,7 @@ It integrates nicely with other CMake projects by defining (and exporting) a Hig
- boost >= 1.41 (recommended, opt-out with -D*HIGHFIVE_USE_BOOST*=OFF)
- eigen3 (optional, opt-in with -D*HIGHFIVE_USE_EIGEN*=ON)
- xtensor (optional, opt-in with -D*HIGHFIVE_USE_XTENSOR*=ON)
- half (optional, opt-in with -D*HIGHFIVE_USE_HALF_FLOAT*=ON)


## Examples
Expand Down
20 changes: 19 additions & 1 deletion include/highfive/bits/H5DataType_misc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
#include <H5Ppublic.h>
#include <H5Tpublic.h>

#ifdef H5_USE_HALF_FLOAT
#include <half.hpp>
#endif

namespace HighFive {

Expand Down Expand Up @@ -125,7 +128,22 @@ inline AtomicType<unsigned long long>::AtomicType() {
_hid = H5Tcopy(H5T_NATIVE_ULLONG);
}

// float, double and long double mapping
// half-float, float, double and long double mapping
#ifdef H5_USE_HALF_FLOAT
using float16_t = half_float::half;

template <>
inline AtomicType<float16_t>::AtomicType() {
_hid = H5Tcopy(H5T_NATIVE_FLOAT);
// Sign position, exponent position, exponent size, mantissa position, mantissa size
H5Tset_fields(_hid, 15, 10, 5, 0, 10);
// Total datatype size (in bytes)
H5Tset_size(_hid, 2);
// Floating point exponent bias
H5Tset_ebias(_hid, 15);
}
#endif

template <>
inline AtomicType<float>::AtomicType() {
_hid = H5Tcopy(H5T_NATIVE_FLOAT);
Expand Down
6 changes: 6 additions & 0 deletions src/examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ function(compile_example exemple_source)
endif()
endif()

if(${example_filename} MATCHES ".*half_float.*")
if(NOT HIGHFIVE_USE_HALF_FLOAT)
return()
endif()
endif()

add_executable(${example_name} ${exemple_source})
target_link_libraries(${example_name} HighFive)

Expand Down
56 changes: 56 additions & 0 deletions src/examples/create_dataset_half_float.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright (c), 2022, Blue Brain Project
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
*/

#ifdef H5_USE_HALF_FLOAT

#include <iostream>
#include <string>
#include <vector>

#include <highfive/H5DataSet.hpp>
#include <highfive/H5DataSpace.hpp>
#include <highfive/H5File.hpp>

const std::string FILE_NAME("create_dataset_half_float_example.h5");
const std::string DATASET_NAME("dset");

// Create a dataset name "dset", size 4x6, and type float16_t (i.e., 16-bit half-precision
// floating-point format)
//
int main(void) {
using namespace HighFive;
try {
// Create a new file using the default property lists.
File file(FILE_NAME, File::ReadWrite | File::Create | File::Truncate);

// Define the size of our dataset: 4x6
std::vector<size_t> dims{4, 6};

// Create the dataset
DataSet dataset = file.createDataSet<float16_t>(DATASET_NAME, DataSpace(dims));

std::vector<std::vector<float16_t>> data;
for (size_t i = 0; i < 4; ++i) {
data.emplace_back();
for (size_t j = 0; j < 6; ++j)
data[i].emplace_back((i + 1) * (j + 1));
}

// write it
dataset.write(data);

} catch (Exception& err) {
// catch and print any HDF5 error
std::cerr << err.what() << std::endl;
}

return 0; // successfully terminated
}

#endif
41 changes: 25 additions & 16 deletions tests/unit/tests_high_five.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,35 @@
#include <random>
#include <string>
#include <vector>
#include <tuple>

using ldcomplex = std::complex<long double>;
using dcomplex = std::complex<double>;
using fcomplex = std::complex<float>;

using floating_numerics_test_types = std::tuple<float, double>;

using numerical_test_types = std::tuple<int,
unsigned int,
long,
unsigned long,
unsigned char,
char,
float,
double,
long long,
unsigned long long,
ldcomplex,
dcomplex,
fcomplex>;
using base_test_types = std::tuple<int,
unsigned int,
long,
unsigned long,
unsigned char,
char,
float,
double,
long long,
unsigned long long,
ldcomplex,
dcomplex,
fcomplex>;

#ifdef H5_USE_HALF_FLOAT
#include <half.hpp>

using float16_t = half_float::half;
using numerical_test_types = decltype(
std::tuple_cat(std::declval<base_test_types>(), std::tuple<float16_t>()));
#else
using numerical_test_types = base_test_types;
#endif

using dataset_test_types =
std::tuple<int, unsigned int, long, unsigned long, unsigned char, char, float, double>;
Expand Down Expand Up @@ -176,4 +185,4 @@ inline HighFive::DataSet readWriteDataset(const DataT& ndvec,

dataset.read(result);
return dataset;
}
}

0 comments on commit b2f49c0

Please sign in to comment.