Commit 1ae64fb4 authored by Joe Grimes's avatar Joe Grimes
Browse files

Test loss for calinski harabasz

parent ce0fbd2f
Loading
Loading
Loading
Loading
Loading
+70 −3
Original line number Diff line number Diff line
@@ -23,12 +23,79 @@ LossFunctionCalinskiHarabasz::LossFunctionCalinskiHarabasz(const std::shared_ptr
}

double LossFunctionCalinskiHarabasz::test_loss(const std::vector<model_node_ptr>& feats) {
    //get the centroids first
    if (_label_mask.size() == 0){
    if (_label_mask.empty()) {
        init_mask("train");
    }
    populate_from_feats(feats);
    //now get the goods

    std::vector<std::vector<double>> train_centroids(_n_class, std::vector<double>(_n_feat, 0.0));
    for (int cc = 0; cc < _n_class; ++cc) {
        const double* mask = &_label_mask[cc * _n_samp];
        int n_points = std::accumulate(mask, mask + _n_samp, 0);
        if (n_points == 0) continue;

        int inc_mask = 1;
        for (int f = 0; f < _n_feat; ++f) {
            train_centroids[cc][f] = ddot_(&_n_samp, &_a[f], &_n_feat, mask, &inc_mask);
            train_centroids[cc][f] /= static_cast<double>(n_points);
        }
    }

    init_mask("test");


    std::vector<double> global_centroid(_n_feat, 0.0);
    for (int f = 0; f < _n_feat; f++) {
        global_centroid[f] = cblas_ddot(
                                 static_cast<int>(_n_samp),
                                 &_a[f],
                                 _n_feat,
                                 _ones.data(),
                                 1
                                 ) / static_cast<double>(_n_samp);
    }

    double W = 0.0;
    double B = 0.0;
    int total_test_points = 0;

    for (int cc = 0; cc < _n_class; ++cc) {
        const double* mask = &_label_mask[cc * _n_samp];
        int n_points = std::accumulate(mask, mask + _n_samp, 0);
        if (n_points == 0) continue;
        total_test_points += n_points;

        for (int s = 0; s < _n_samp; ++s) {
            if (mask[s] == 0) continue;
            W += std::inner_product(
                &_a[s * _n_feat],
                &_a[s * _n_feat] + _n_feat,
                train_centroids[cc].begin(),
                0.0,
                std::plus<>(),
                [](double a, double b) { return (a - b) * (a - b); }
            );
        }

        double dist2 = std::inner_product(
            train_centroids[cc].begin(),
            train_centroids[cc].end(),
            global_centroid.begin(),
            0.0,
            std::plus<>(),
            [](double a, double b) { return (a - b) * (a - b); }
        );
        B += n_points * dist2;
    }

    if (_n_class <= 1 || total_test_points <= _n_class) {
        return 0.0;
    }

    double CH = (B / static_cast<double>(_n_class - 1)) /
                (W / static_cast<double>(total_test_points - _n_class));

    return CH;
}


+3 −1
Original line number Diff line number Diff line
@@ -178,12 +178,14 @@ TEST_F(LossFunctionCalinskiHarabaszTests, MultiClassTest)

    // 4 classes
    _prop_train = {0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3};
    _prop_test = _prop_train;
    _prop_test =  {0, 1, 0, 1, 0, 1, 2, 3, 2, 3, 2, 3};

    LossFunctionCalinskiHarabasz loss(
        _prop_train, _prop_test, _task_sizes_train, _task_sizes_test, false, 2);

    double CH_score = loss(_model_phi);
    EXPECT_NEAR(CH_score, 1556.2937293418609, 1e-10);
    std::cout << "value from regular pipeline " << CH_score << std::endl;
    std::cout << "Value from test loss " << loss.test_loss(_model_phi) << std::endl;
}
}