fix(kmeans): correct spherical centroid normalization (#654)

This commit is contained in:
egolearner 2026-08-05 12:48:51 +08:00 committed by GitHub
parent 9ff5db33db
commit d7a95d02be
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 50 additions and 19 deletions

View File

@ -492,16 +492,15 @@ class NumericalKmeansContext {
MatrixHelper::ReverseTranspose<uint32_t, BatchCount>(src, dim >> 2, dst);
}
//! Compute Norm2
template <typename ValueType, typename = typename std::enable_if<
IsFloatingPoint<ValueType>::value>::type>
//! Normalize with L2 norm for floating-point values, otherwise do nothing
static void Norm2(ValueType *data, size_t dim, float *norm) {
Normalizer<ValueType>::L2(data, dim, norm);
}
//! Compute Norm2, for non-float do nothing
static void Norm2(ValueType * /*data*/, size_t /*dim*/, float *norm) {
*norm = 0.0f;
if constexpr (IsFloatingPoint<ValueType>::value) {
Normalizer<ValueType>::L2(data, dim, norm);
} else {
(void)data;
(void)dim;
*norm = 0.0f;
}
}
private:
@ -843,16 +842,15 @@ class NumericalInnerProductKmeansContext {
MatrixHelper::ReverseTranspose<uint32_t, BatchCount>(src, dim >> 2, dst);
}
//! Compute Norm2
template <typename ValueType, typename = typename std::enable_if<
IsFloatingPoint<ValueType>::value>::type>
//! Normalize with L2 norm for floating-point values, otherwise do nothing
static void Norm2(ValueType *data, size_t dim, float *norm) {
Normalizer<ValueType>::L2(data, dim, norm);
}
//! Compute Norm2, for non-float do nothing
static void Norm2(ValueType * /*data*/, size_t /*dim*/, float *norm) {
*norm = 0.0f;
if constexpr (IsFloatingPoint<ValueType>::value) {
Normalizer<ValueType>::L2(data, dim, norm);
} else {
(void)data;
(void)dim;
*norm = 0.0f;
}
}
private:

View File

@ -202,7 +202,7 @@ class LloydCluster {
if (spherical_) {
for (size_t i = 0, n = centroids_.count(); i != n; ++i) {
float norm;
float norm = 0.0f;
ContextType::Norm2(centroids_[i], centroids_.dimension(), &norm);
}
}

View File

@ -239,6 +239,39 @@ TEST(NumericalKmeans, FP32_General_InnerProduct) {
}
}
TEST(NumericalInnerProductKmeansContext, NormalizeFloatingPointCentroid) {
float centroid[] = {3.0f, 4.0f};
float norm = 0.0f;
ailego::NumericalInnerProductKmeansContext<float>::Norm2(centroid, 2, &norm);
EXPECT_FLOAT_EQ(norm, 5.0f);
EXPECT_FLOAT_EQ(centroid[0], 0.6f);
EXPECT_FLOAT_EQ(centroid[1], 0.8f);
}
TEST(NumericalKmeansContext, NormalizeFloatingPointCentroid) {
float centroid[] = {3.0f, 4.0f};
float norm = 0.0f;
ailego::NumericalKmeansContext<float>::Norm2(centroid, 2, &norm);
EXPECT_FLOAT_EQ(norm, 5.0f);
EXPECT_FLOAT_EQ(centroid[0], 0.6f);
EXPECT_FLOAT_EQ(centroid[1], 0.8f);
}
TEST(NumericalKmeansContext, KeepIntegerCentroidUnchanged) {
int8_t centroid[] = {3, 4};
float norm = 1.0f;
ailego::NumericalKmeansContext<int8_t>::Norm2(centroid, 2, &norm);
EXPECT_FLOAT_EQ(norm, 0.0f);
EXPECT_EQ(centroid[0], 3);
EXPECT_EQ(centroid[1], 4);
}
TEST(NumericalKmeans, FP16_General_InnerProduct) {
const size_t DIMENSION = 20;
const size_t K_VALUE = 20;