Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for half-precision (16-bit) floating-point datasets #587

Merged
merged 5 commits into from
Jun 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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);
alkino marked this conversation as resolved.
Show resolved Hide resolved
alkino marked this conversation as resolved.
Show resolved Hide resolved
// 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;
}
}