Skip to content

[MOD-6775] introduce fp16 type! #462

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

Merged
merged 16 commits into from
May 12, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 0 additions & 16 deletions .github/workflows/flow-temp
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👀

This file was deleted.

4 changes: 2 additions & 2 deletions .github/workflows/flow-temp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ on:
jobs:
check-if-docs-only:
uses: ./.github/workflows/task-check-docs.yml
bionic:
focal:
needs: [check-if-docs-only]
if: ${{ needs.check-if-docs-only.outputs.only-docs-changed == 'false' }}
uses: ./.github/workflows/task-unit-test.yml
with:
container: ubuntu:bionic
container: ubuntu:focal
2 changes: 2 additions & 0 deletions src/VecSim/algorithms/hnsw/hnsw_single_tests_friends.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ INDEX_TEST_FRIEND_CLASS(HNSWTieredIndexTest_testSizeEstimation_Test)
INDEX_TEST_FRIEND_CLASS(HNSWTieredIndexTest_swapJobBasic_Test)
friend class BF16HNSWTest_testSizeEstimation_Test;
friend class BF16TieredTest_testSizeEstimation_Test;
friend class FP16HNSWTest_testSizeEstimation_Test;
friend class FP16TieredTest_testSizeEstimation_Test;
1 change: 1 addition & 0 deletions src/VecSim/algorithms/hnsw/hnsw_tiered_tests_friends.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ INDEX_TEST_FRIEND_CLASS(HNSWTieredIndexTestBasic_runGCAPI_Test)
INDEX_TEST_FRIEND_CLASS(HNSWTieredIndexTestBasic_FitMemoryTest_Test)

friend class BF16TieredTest;
friend class FP16TieredTest;

INDEX_TEST_FRIEND_CLASS(BM_VecSimBasics)
INDEX_TEST_FRIEND_CLASS(BM_VecSimCommon)
6 changes: 6 additions & 0 deletions src/VecSim/index_factories/brute_force_factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
#include "VecSim/algorithms/brute_force/brute_force_single.h"
#include "VecSim/algorithms/brute_force/brute_force_multi.h"
#include "VecSim/types/bfloat16.h"
#include "VecSim/types/float16.h"

using bfloat16 = vecsim_types::bfloat16;
using float16 = vecsim_types::float16;

namespace BruteForceFactory {
template <typename DataType, typename DistType = DataType>
Expand Down Expand Up @@ -54,6 +56,8 @@ VecSimIndex *NewIndex(const BFParams *bfparams, const AbstractIndexInitParams &a
return NewIndex_ChooseMultiOrSingle<double>(bfparams, abstractInitParams);
} else if (bfparams->type == VecSimType_BFLOAT16) {
return NewIndex_ChooseMultiOrSingle<bfloat16, float>(bfparams, abstractInitParams);
} else if (bfparams->type == VecSimType_FLOAT16) {
return NewIndex_ChooseMultiOrSingle<float16, float>(bfparams, abstractInitParams);
}

// If we got here something is wrong.
Expand Down Expand Up @@ -87,6 +91,8 @@ size_t EstimateInitialSize(const BFParams *params) {
est += EstimateInitialSize_ChooseMultiOrSingle<double>(params->multi);
} else if (params->type == VecSimType_BFLOAT16) {
est += EstimateInitialSize_ChooseMultiOrSingle<bfloat16, float>(params->multi);
} else if (params->type == VecSimType_FLOAT16) {
est += EstimateInitialSize_ChooseMultiOrSingle<float16, float>(params->multi);
}
// Parameters related part.

Expand Down
9 changes: 9 additions & 0 deletions src/VecSim/index_factories/hnsw_factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
#include "VecSim/index_factories/hnsw_factory.h"
#include "VecSim/algorithms/hnsw/hnsw.h"
#include "VecSim/types/bfloat16.h"
#include "VecSim/types/float16.h"

using bfloat16 = vecsim_types::bfloat16;
using float16 = vecsim_types::float16;

namespace HNSWFactory {

Expand Down Expand Up @@ -49,6 +51,8 @@ VecSimIndex *NewIndex(const VecSimParams *params) {
return NewIndex_ChooseMultiOrSingle<double>(hnswParams, abstractInitParams);
} else if (hnswParams->type == VecSimType_BFLOAT16) {
return NewIndex_ChooseMultiOrSingle<bfloat16, float>(hnswParams, abstractInitParams);
} else if (hnswParams->type == VecSimType_FLOAT16) {
return NewIndex_ChooseMultiOrSingle<float16, float>(hnswParams, abstractInitParams);
}

// If we got here something is wrong.
Expand Down Expand Up @@ -82,6 +86,8 @@ size_t EstimateInitialSize(const HNSWParams *params) {
est += EstimateInitialSize_ChooseMultiOrSingle<double>(params->multi);
} else if (params->type == VecSimType_BFLOAT16) {
est += EstimateInitialSize_ChooseMultiOrSingle<bfloat16, float>(params->multi);
} else if (params->type == VecSimType_FLOAT16) {
est += EstimateInitialSize_ChooseMultiOrSingle<float16, float>(params->multi);
}

// Account for the visited nodes pool (assume that it holds one pointer to a handler).
Expand Down Expand Up @@ -194,6 +200,9 @@ VecSimIndex *NewIndex(const std::string &location) {
} else if (params.type == VecSimType_BFLOAT16) {
return NewIndex_ChooseMultiOrSingle<bfloat16, float>(input, &params, abstractInitParams,
version);
} else if (params.type == VecSimType_FLOAT16) {
return NewIndex_ChooseMultiOrSingle<float16, float>(input, &params, abstractInitParams,
version);
} else {
auto bad_name = VecSimType_ToString(params.type);
if (bad_name == nullptr) {
Expand Down
6 changes: 6 additions & 0 deletions src/VecSim/index_factories/tiered_factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@

#include "VecSim/algorithms/hnsw/hnsw_tiered.h"
#include "VecSim/types/bfloat16.h"
#include "VecSim/types/float16.h"

using bfloat16 = vecsim_types::bfloat16;
using float16 = vecsim_types::float16;

namespace TieredFactory {

Expand Down Expand Up @@ -66,6 +68,8 @@ inline size_t EstimateInitialSize(const TieredIndexParams *params, BFParams &bf_
est += sizeof(TieredHNSWIndex<double, double>);
} else if (hnsw_params.type == VecSimType_BFLOAT16) {
est += sizeof(TieredHNSWIndex<bfloat16, float>);
} else if (hnsw_params.type == VecSimType_FLOAT16) {
est += sizeof(TieredHNSWIndex<float16, float>);
}
bf_params_output.type = hnsw_params.type;
bf_params_output.multi = hnsw_params.multi;
Expand All @@ -82,6 +86,8 @@ VecSimIndex *NewIndex(const TieredIndexParams *params) {
return TieredHNSWFactory::NewIndex<double>(params);
} else if (type == VecSimType_BFLOAT16) {
return TieredHNSWFactory::NewIndex<bfloat16, float>(params);
} else if (type == VecSimType_FLOAT16) {
return TieredHNSWFactory::NewIndex<float16, float>(params);
}
return nullptr; // Invalid type.
}
Expand Down
6 changes: 3 additions & 3 deletions src/VecSim/spaces/IP/IP_AVX512_FP16.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ static void InnerProductStep(float16 *&pVect1, float16 *&pVect2, __m512 &sum) {

template <unsigned short residual> // 0..31
float FP16_InnerProductSIMD32_AVX512(const void *pVect1v, const void *pVect2v, size_t dimension) {
auto *pVect1 = (uint16_t *)pVect1v;
auto *pVect2 = (uint16_t *)pVect2v;
auto *pVect1 = (float16 *)pVect1v;
auto *pVect2 = (float16 *)pVect2v;

const uint16_t *pEnd1 = pVect1 + dimension;
const float16 *pEnd1 = pVect1 + dimension;

auto sum = _mm512_setzero_ps();

Expand Down
2 changes: 1 addition & 1 deletion src/VecSim/spaces/IP/IP_F16C_FP16.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ float FP16_InnerProductSIMD32_F16C(const void *pVect1v, const void *pVect2v, siz
auto *pVect1 = (float16 *)pVect1v;
auto *pVect2 = (float16 *)pVect2v;

const uint16_t *pEnd1 = pVect1 + dimension;
const float16 *pEnd1 = pVect1 + dimension;

auto sum = _mm256_setzero_ps();

Expand Down
4 changes: 2 additions & 2 deletions src/VecSim/spaces/L2/L2_F16C_FP16.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

using float16 = vecsim_types::float16;

static void L2SqrStep(uint16_t *&pVect1, uint16_t *&pVect2, __m256 &sum) {
static void L2SqrStep(float16 *&pVect1, float16 *&pVect2, __m256 &sum) {
// Convert 8 half-floats into floats and store them in 256 bits register.
auto v1 = _mm256_cvtph_ps(_mm_loadu_si128((__m128i_u const *)(pVect1)));
auto v2 = _mm256_cvtph_ps(_mm_loadu_si128((__m128i_u const *)(pVect2)));
Expand All @@ -28,7 +28,7 @@ float FP16_L2SqrSIMD32_F16C(const void *pVect1v, const void *pVect2v, size_t dim
auto *pVect1 = (float16 *)pVect1v;
auto *pVect2 = (float16 *)pVect2v;

const uint16_t *pEnd1 = pVect1 + dimension;
const float16 *pEnd1 = pVect1 + dimension;

auto sum = _mm256_setzero_ps();

Expand Down
22 changes: 22 additions & 0 deletions src/VecSim/spaces/normalize/normalize_naive.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
#pragma once

#include "VecSim/types/bfloat16.h"
#include "VecSim/types/float16.h"
#include <cmath>

using bfloat16 = vecsim_types::bfloat16;
using float16 = vecsim_types::float16;

namespace spaces {

Expand Down Expand Up @@ -50,4 +52,24 @@ static inline void bfloat16_normalizeVector(void *vec, const size_t dim) {
}
}

static inline void float16_normalizeVector(void *vec, const size_t dim) {
float16 *input_vector = (float16 *)vec;

float f32_tmp[dim];

float sum = 0;

for (size_t i = 0; i < dim; i++) {
float val = vecsim_types::FP16_to_FP32(input_vector[i]);
f32_tmp[i] = val;
sum += val * val;
}

float norm = sqrt(sum);

for (size_t i = 0; i < dim; i++) {
input_vector[i] = vecsim_types::FP32_to_FP16(f32_tmp[i] / norm);
}
}

} // namespace spaces
20 changes: 20 additions & 0 deletions src/VecSim/spaces/spaces.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/

#include "VecSim/types/bfloat16.h"
#include "VecSim/types/float16.h"
#include "VecSim/spaces/space_includes.h"
#include "VecSim/spaces/spaces.h"
#include "VecSim/spaces/IP_space.h"
Expand All @@ -30,6 +31,19 @@ dist_func_t<float> GetDistFunc<vecsim_types::bfloat16, float>(VecSimMetric metri
throw std::invalid_argument("Invalid metric");
}

template <>
dist_func_t<float> GetDistFunc<vecsim_types::float16, float>(VecSimMetric metric, size_t dim,
unsigned char *alignment) {
switch (metric) {
case VecSimMetric_Cosine:
case VecSimMetric_IP:
return IP_FP16_GetDistFunc(dim, nullptr, alignment);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why does this function get a void pointer that is always null? can we just not pass it?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was part of the optimization bit map refactor
It was left mainly for testing purposes

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider cleaning it now? I don't think it is needed for the test either (unless we suspect the hardware will change between calls)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we pass a specific optimization in the tests to enforce lower optimization
see test_spaces.cpp

case VecSimMetric_L2:
return L2_FP16_GetDistFunc(dim, nullptr, alignment);
}
throw std::invalid_argument("Invalid metric");
}

template <>
dist_func_t<float> GetDistFunc<float, float>(VecSimMetric metric, size_t dim,
unsigned char *alignment) {
Expand Down Expand Up @@ -74,4 +88,10 @@ normalizeVector_f<vecsim_types::bfloat16> GetNormalizeFunc<vecsim_types::bfloat1
return bfloat16_normalizeVector<false>;
}
}

template <>
normalizeVector_f<vecsim_types::float16> GetNormalizeFunc<vecsim_types::float16>(void) {
return float16_normalizeVector;
}

} // namespace spaces
8 changes: 6 additions & 2 deletions src/VecSim/types/bfloat16.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@
#include <cmath>

namespace vecsim_types {

using bfloat16 = unsigned short;
struct bfloat16 {
uint16_t val;
bfloat16() = default;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a compiler version issue? How come it works with fp16? Can we try this option?

Suggested change
bfloat16() = default;
constexpr bfloat16() noexcept {}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

declaring a default ctor as constexpr is allowed as of c++20, and this feature in particular is supported as of gcc10
fp16 worked because it didn't have constexpr at first place.
Anyway, since we have another ctor that is constexpr, it doesn't matter.

constexpr bfloat16(uint16_t val) : val(val) {}
operator uint16_t() const { return val; }
};

static inline bfloat16 float_to_bf16(const float ff) {
uint32_t *p_f32 = (uint32_t *)&ff;
Expand Down
8 changes: 6 additions & 2 deletions src/VecSim/types/float16.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,12 @@
#include <cstring>
#include <algorithm>
namespace vecsim_types {

using float16 = uint16_t;
struct float16 {
uint16_t val;
float16() = default;
constexpr float16(uint16_t val) : val(val) {}
operator uint16_t() const { return val; }
};

inline float _interpret_as_float(uint32_t num) {
void *num_ptr = &num;
Expand Down
7 changes: 7 additions & 0 deletions src/VecSim/utils/vec_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@
#include "vec_utils.h"
#include "VecSim/query_result_definitions.h"
#include "VecSim/types/bfloat16.h"
#include "VecSim/types/float16.h"
#include <cmath>
#include <cerrno>
#include <climits>
#include <float.h>
#include <algorithm>

using bfloat16 = vecsim_types::bfloat16;
using float16 = vecsim_types::float16;

const char *VecSimCommonStrings::ALGORITHM_STRING = "ALGORITHM";
const char *VecSimCommonStrings::FLAT_STRING = "FLAT";
Expand All @@ -24,6 +26,7 @@ const char *VecSimCommonStrings::TYPE_STRING = "TYPE";
const char *VecSimCommonStrings::FLOAT32_STRING = "FLOAT32";
const char *VecSimCommonStrings::FLOAT64_STRING = "FLOAT64";
const char *VecSimCommonStrings::BFLOAT16_STRING = "BFLOAT16";
const char *VecSimCommonStrings::FLOAT16_STRING = "FLOAT16";
const char *VecSimCommonStrings::INT32_STRING = "INT32";
const char *VecSimCommonStrings::INT64_STRING = "INT64";

Expand Down Expand Up @@ -142,6 +145,8 @@ const char *VecSimType_ToString(VecSimType vecsimType) {
return VecSimCommonStrings::FLOAT64_STRING;
case VecSimType_BFLOAT16:
return VecSimCommonStrings::BFLOAT16_STRING;
case VecSimType_FLOAT16:
return VecSimCommonStrings::FLOAT16_STRING;
case VecSimType_INT32:
return VecSimCommonStrings::INT32_STRING;
case VecSimType_INT64:
Expand Down Expand Up @@ -188,6 +193,8 @@ size_t VecSimType_sizeof(VecSimType type) {
return sizeof(double);
case VecSimType_BFLOAT16:
return sizeof(bfloat16);
case VecSimType_FLOAT16:
return sizeof(float16);
case VecSimType_INT32:
return sizeof(int32_t);
case VecSimType_INT64:
Expand Down
2 changes: 2 additions & 0 deletions src/VecSim/utils/vec_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <stdlib.h>
#include "VecSim/vec_sim_common.h"
#include "VecSim/types/bfloat16.h"
#include "VecSim/types/float16.h"
#include <VecSim/query_results.h>
#include <utility>
#include <cassert>
Expand All @@ -24,6 +25,7 @@ struct VecSimCommonStrings {
static const char *FLOAT32_STRING;
static const char *FLOAT64_STRING;
static const char *BFLOAT16_STRING;
static const char *FLOAT16_STRING;
static const char *INT32_STRING;
static const char *INT64_STRING;

Expand Down
2 changes: 2 additions & 0 deletions src/VecSim/vec_sim.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ extern "C" void VecSim_Normalize(void *blob, size_t dim, VecSimType type) {
spaces::GetNormalizeFunc<double>()(blob, dim);
} else if (type == VecSimType_BFLOAT16) {
spaces::GetNormalizeFunc<vecsim_types::bfloat16>()(blob, dim);
} else if (type == VecSimType_FLOAT16) {
spaces::GetNormalizeFunc<vecsim_types::float16>()(blob, dim);
}
}

Expand Down
1 change: 1 addition & 0 deletions src/VecSim/vec_sim_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ typedef enum {
VecSimType_FLOAT32,
VecSimType_FLOAT64,
VecSimType_BFLOAT16,
VecSimType_FLOAT16,
VecSimType_INT32,
VecSimType_INT64
} VecSimType;
Expand Down
6 changes: 6 additions & 0 deletions src/VecSim/vec_sim_debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ extern "C" int VecSimDebug_GetElementNeighborsInHNSWGraph(VecSimIndex *index, si
} else if (info.type == VecSimType_BFLOAT16) {
return dynamic_cast<HNSWIndex<vecsim_types::bfloat16, float> *>(index)
->getHNSWElementNeighbors(label, neighborsData);
} else if (info.type == VecSimType_FLOAT16) {
return dynamic_cast<HNSWIndex<vecsim_types::float16, float> *>(index)
->getHNSWElementNeighbors(label, neighborsData);
} else {
assert(false && "Invalid data type");
}
Expand All @@ -42,6 +45,9 @@ extern "C" int VecSimDebug_GetElementNeighborsInHNSWGraph(VecSimIndex *index, si
} else if (info.type == VecSimType_BFLOAT16) {
return dynamic_cast<TieredHNSWIndex<vecsim_types::bfloat16, float> *>(index)
->getHNSWElementNeighbors(label, neighborsData);
} else if (info.type == VecSimType_FLOAT16) {
return dynamic_cast<TieredHNSWIndex<vecsim_types::float16, float> *>(index)
->getHNSWElementNeighbors(label, neighborsData);
} else {
assert(false && "Invalid data type");
}
Expand Down
Loading
Loading