Better handling of printing results board

This commit is contained in:
saundersp 2024-03-21 00:50:13 +01:00
parent f65c58d95c
commit 211dcad893
8 changed files with 307 additions and 188 deletions

View File

@ -1,6 +1,5 @@
#pragma once #pragma once
#include <filesystem> #include <filesystem>
namespace fs = std::filesystem;
#include "data.hpp" #include "data.hpp"
#include "toolbox.hpp" #include "toolbox.hpp"
//#include "config.hpp" //#include "config.hpp"
@ -53,62 +52,64 @@ bool unit_test_argsort_2d(const np::Array<T>& a, const np::Array<uint16_t>& indi
} }
template <typename T, typename F, typename... Args> template <typename T, typename F, typename... Args>
T benchmark_function(const char* step_name, const F& fnc, Args &&...args) noexcept { T benchmark_function(const char* const step_name, const int32_t& column_width, const F& fnc, Args &&...args) noexcept {
#if __DEBUG == false #if __DEBUG == false
printf("%s...\r", step_name); fprintf(stderr, "%s...\r", step_name);
fflush(stdout); // manual flush is mandatory, otherwise it will not be shown immediately because the output is buffered fflush(stderr); // manual flush is mandatory, otherwise it will not be shown immediately because the output is buffered
#endif #endif
const std::chrono::system_clock::time_point start = perf_counter_ns(); const std::chrono::system_clock::time_point start = perf_counter_ns();
const T res = fnc(std::forward<Args>(args)...); const T res = fnc(std::forward<Args>(args)...);
const long long time_spent = duration_ns(perf_counter_ns() - start); const long long time_spent = duration_ns(perf_counter_ns() - start);
printf("| %-49s | %18s | %-29s |\n", step_name, thousand_sep(time_spent).c_str(), format_time_ns(time_spent).c_str()); formatted_row<3>({ column_width, -18, 29 }, { step_name, thousand_sep(time_spent).c_str(), format_time_ns(time_spent).c_str() });
return res; return res;
} }
template <typename F, typename... Args> template <typename F, typename... Args>
void benchmark_function_void(const char* step_name, const F& fnc, Args &&...args) noexcept { void benchmark_function_void(const char* const step_name, const int32_t& column_width, const F& fnc, Args &&...args) noexcept {
#if __DEBUG == false #if __DEBUG == false
printf("%s...\r", step_name); fprintf(stderr, "%s...\r", step_name);
fflush(stdout); // manual flush is mandatory, otherwise it will not be shown immediately because the output is buffered fflush(stderr); // manual flush is mandatory, otherwise it will not be shown immediately because the output is buffered
#endif #endif
const std::chrono::system_clock::time_point start = perf_counter_ns(); const std::chrono::system_clock::time_point start = perf_counter_ns();
fnc(std::forward<Args>(args)...); fnc(std::forward<Args>(args)...);
const long long time_spent = duration_ns(perf_counter_ns() - start); const long long time_spent = duration_ns(perf_counter_ns() - start);
printf("| %-49s | %18s | %-29s |\n", step_name, thousand_sep(time_spent).c_str(), format_time_ns(time_spent).c_str()); formatted_row<3>({ column_width, -18, 29 }, { step_name, thousand_sep(time_spent).c_str(), format_time_ns(time_spent).c_str() });
} }
template <typename T, typename F, typename... Args> template <typename T, typename F, typename... Args>
np::Array<T> state_saver(const char* step_name, const char* filename, const bool& force_redo, const bool& save_state, const char* out_dir, const F& fnc, Args &&...args) noexcept { np::Array<T> state_saver(const char* const step_name, const int32_t& column_width, const char* const filename, const bool& force_redo, const bool& save_state, const char* const out_dir, const F& fnc, Args &&...args) noexcept {
char filepath[BUFFER_SIZE] = { 0 }; char filepath[BUFFER_SIZE] = { 0 };
sprintf(filepath, "%s/%s.bin", out_dir, filename); snprintf(filepath, BUFFER_SIZE, "%s/%s.bin", out_dir, filename);
np::Array<T> bin; np::Array<T> bin;
if (!fs::exists(filepath) || force_redo) { if (!std::filesystem::exists(filepath) || force_redo) {
bin = std::move(benchmark_function<np::Array<T>>(step_name, fnc, std::forward<Args>(args)...)); //bin = std::move(benchmark_function<np::Array<T>>(step_name, column_width, fnc, std::forward<Args>(args)...));
bin = benchmark_function<np::Array<T>>(step_name, column_width, fnc, std::forward<Args>(args)...);
if(save_state){ if(save_state){
#if __DEBUG == false #if __DEBUG == false
printf("Saving results of %s\r", step_name); fprintf(stderr, "Saving results of %s\r", step_name);
fflush(stdout); fflush(stderr);
#endif #endif
save<T>(bin, filepath); save<T>(bin, filepath);
#if __DEBUG == false #if __DEBUG == false
printf("%*c\r", 100, ' '); fprintf(stderr, "%*c\r", 100, ' '); // Clear previous clear
fflush(stdout); fflush(stderr);
#endif #endif
} }
} else { } else {
#if __DEBUG == false #if __DEBUG == false
printf("Loading results of %s\r", step_name); fprintf(stderr, "Loading results of %s\r", step_name);
fflush(stdout); fflush(stderr);
#endif #endif
bin = std::move(load<T>(filepath)); //bin = std::move(load<T>(filepath));
printf("| %-49s | %18s | %-29s |\n", step_name, "None", "loaded saved state"); bin = load<T>(filepath);
formatted_row<3>({ column_width, -18, 29 }, { step_name, "None", "loaded saved state" });
} }
return bin; return bin;
} }
template <typename T, size_t N, typename F, typename... Args> template <typename T, size_t N, typename F, typename... Args>
std::array<np::Array<T>, N> state_saver(const char* step_name, const std::vector<const char*>& filenames, const bool& force_redo, const bool& save_state, const char* out_dir, const F& fnc, Args &&...args) noexcept { std::array<np::Array<T>, N> state_saver(const char* const step_name, const int32_t& column_width, const std::vector<const char*>& filenames, const bool& force_redo, const bool& save_state, const char* const out_dir, const F& fnc, Args &&...args) noexcept {
char filepath[BUFFER_SIZE] = { 0 }; char filepath[BUFFER_SIZE] = { 0 };
bool abs = false; bool abs = false;
for (const char* filename : filenames){ for (const char* filename : filenames){
@ -121,11 +122,12 @@ std::array<np::Array<T>, N> state_saver(const char* step_name, const std::vector
std::array<np::Array<T>, N> bin; std::array<np::Array<T>, N> bin;
if (abs || force_redo) { if (abs || force_redo) {
bin = std::move(benchmark_function<std::array<np::Array<T>, N>>(step_name, fnc, std::forward<Args>(args)...)); //bin = std::move(benchmark_function<std::array<np::Array<T>, N>>(step_name, column_width, fnc, std::forward<Args>(args)...));
bin = benchmark_function<std::array<np::Array<T>, N>>(step_name, column_width, fnc, std::forward<Args>(args)...);
if (save_state){ if (save_state){
#if __DEBUG == false #if __DEBUG == false
printf("Saving results of %s\r", step_name); fprintf(stderr, "Saving results of %s\r", step_name);
fflush(stdout); fflush(stderr);
#endif #endif
size_t i = 0; size_t i = 0;
for (const char* filename : filenames){ for (const char* filename : filenames){
@ -133,21 +135,21 @@ std::array<np::Array<T>, N> state_saver(const char* step_name, const std::vector
save<T>(bin[i++], filepath); save<T>(bin[i++], filepath);
} }
#if __DEBUG == false #if __DEBUG == false
printf("%*c\r", 100, ' '); fprintf(stderr, "%*c\r", 100, ' '); // Clear previous print
fflush(stdout); fflush(stderr);
#endif #endif
} }
} else { } else {
#if __DEBUG == false #if __DEBUG == false
printf("Loading results of %s\r", step_name); fprintf(stderr, "Loading results of %s\r", step_name);
fflush(stdout); fflush(stderr);
#endif #endif
size_t i = 0; size_t i = 0;
for (const char* filename : filenames){ for (const char* filename : filenames){
sprintf(filepath, "%s/%s.bin", out_dir, filename);
bin[i++] = std::move(load<T>(filepath)); bin[i++] = std::move(load<T>(filepath));
snprintf(filepath, BUFFER_SIZE, "%s/%s.bin", out_dir, filename);
} }
printf("| %-49s | %18s | %-29s |\n", step_name, "None", "loaded saved state"); formatted_row<3>({ column_width, -18, 29 }, { step_name, "None", "loaded saved state" });
} }
return bin; return bin;
} }

View File

@ -1,4 +1,5 @@
#pragma once #pragma once
#include <array>
#define DATA_DIR "../data" #define DATA_DIR "../data"
#define OUT_DIR "./out" #define OUT_DIR "./out"
@ -11,7 +12,7 @@
#define NB_THREADS_3D_X 16 #define NB_THREADS_3D_X 16
#define NB_THREADS_3D_Y 16 #define NB_THREADS_3D_Y 16
#define NB_THREADS_3D_Z 4 #define NB_THREADS_3D_Z 4
__device__ constexpr const size_t M = 5; //log2(NB_THREADS_2D_Y)); #define M static_cast<size_t>(log2f(NB_THREADS_2D_Y))
#endif #endif
// Save state to avoid recalculation on restart // Save state to avoid recalculation on restart
@ -22,17 +23,19 @@ __device__ constexpr const size_t M = 5; //log2(NB_THREADS_2D_Y));
// Use GPU to greatly accelerate runtime // Use GPU to greatly accelerate runtime
#define GPU_BOOSTED true #define GPU_BOOSTED true
// Depending on what you set, the output label will be as follow : // Depending on what you set, the output label will be as follow :
// | GPU_BOOSTED | LABEL | // ┌─────────────┬───────┐
// |-------------|-------| // │ GPU_BOOSTED │ LABEL │
// | true | GPU | // ├─────────────┼───────┤
// | false | CPU | // │ true │ GPU │
// │ false │ CPU │
// └─────────────┴───────┘
// Number of weak classifiers // Number of weak classifiers
// const size_t TS[] = { 1 }; // [[maybe_unused]] constexpr const std::array TS{ 1 };
// const size_t TS[] = { 1, 5, 10 }; // [[maybe_unused]] constexpr const std::array TS{ 1, 5, 10 };
const size_t TS[] = { 1, 5, 10, 25, 50 }; [[maybe_unused]] constexpr const std::array TS{ 1, 5, 10, 25, 50 };
// const size_t TS[] = { 1, 5, 10, 25, 50, 100, 200, 300 }; // [[maybe_unused]] constexpr const std::array TS{ 1, 5, 10, 25, 50, 100, 200, 300 };
// const size_t TS[] = { 1, 5, 10, 25, 50, 100, 200, 300, 400, 500, 1000 }; // [[maybe_unused]] constexpr const std::array TS{ 1, 5, 10, 25, 50, 100, 200, 300, 400, 500, 1000 };
// Enable verbose output (for debugging purposes) // Enable verbose output (for debugging purposes)
#define __DEBUG false #define __DEBUG false

View File

@ -9,7 +9,6 @@
#define BUFFER_SIZE 256 #define BUFFER_SIZE 256
#define STRING_INT_SIZE 8 // Length of a number in log10 (including '-') #define STRING_INT_SIZE 8 // Length of a number in log10 (including '-')
#define S(N) std::string(N, '-').c_str()
#ifndef __CUDACC__ #ifndef __CUDACC__
#define __host__ #define __host__

View File

@ -27,10 +27,11 @@ std::tuple<np::Array<int32_t>, np::Array<uint16_t>, np::Array<uint8_t>, np::Arra
for (const char* const folder_name : { "models", "out" }) for (const char* const folder_name : { "models", "out" })
fs::create_directory(folder_name); fs::create_directory(folder_name);
printf("| %-49s | %-18s | %-29s |\n", "Preprocessing", "Time spent (ns)", "Formatted time spent"); const std::chrono::system_clock::time_point preproc_timestamp = perf_counter_ns();
printf("|%s|%s|%s|\n", S(51), S(20), S(31)); const std::array<int32_t, 3> preproc_gaps = { 49, -18, 29 };
header({ "Preprocessing", "Time spent (ns)", "Formatted time spent" }, preproc_gaps);
const auto [ X_train, y_train, X_test, y_test ] = state_saver<uint8_t, 4>("Loading sets", {"X_train", "y_train", "X_test", "y_test"}, const auto [ X_train, y_train, X_test, y_test ] = state_saver<uint8_t, 4>("Loading sets", preproc_gaps[0], {"X_train", "y_train", "X_test", "y_test"},
FORCE_REDO, SAVE_STATE, OUT_DIR, load_datasets); FORCE_REDO, SAVE_STATE, OUT_DIR, load_datasets);
#if __DEBUG #if __DEBUG
@ -48,7 +49,7 @@ std::tuple<np::Array<int32_t>, np::Array<uint16_t>, np::Array<uint8_t>, np::Arra
print(y_test, { IDX_INSPECT, IDX_INSPECT + IDX_INSPECT_OFFSET }); print(y_test, { IDX_INSPECT, IDX_INSPECT + IDX_INSPECT_OFFSET });
#endif #endif
const np::Array<uint8_t> feats = state_saver<uint8_t>("Building features", "feats", const np::Array<uint8_t> feats = state_saver<uint8_t>("Building features", preproc_gaps[0], "feats",
FORCE_REDO, SAVE_STATE, OUT_DIR, build_features, X_train.shape[1], X_train.shape[2]); FORCE_REDO, SAVE_STATE, OUT_DIR, build_features, X_train.shape[1], X_train.shape[2]);
#if __DEBUG #if __DEBUG
@ -57,9 +58,9 @@ std::tuple<np::Array<int32_t>, np::Array<uint16_t>, np::Array<uint8_t>, np::Arra
print_feat(feats, { IDX_INSPECT }); print_feat(feats, { IDX_INSPECT });
#endif #endif
const np::Array<uint32_t> X_train_ii = state_saver<uint32_t>("Converting training set to integral images (" LABEL ")", "X_train_ii_" LABEL, const np::Array<uint32_t> X_train_ii = state_saver<uint32_t>("Converting training set to integral images (" LABEL ")", preproc_gaps[0], "X_train_ii_" LABEL,
FORCE_REDO, SAVE_STATE, OUT_DIR, set_integral_image, X_train); FORCE_REDO, SAVE_STATE, OUT_DIR, set_integral_image, X_train);
const np::Array<uint32_t> X_test_ii = state_saver<uint32_t>("Converting testing set to integral images (" LABEL ")", "X_test_ii_" LABEL, const np::Array<uint32_t> X_test_ii = state_saver<uint32_t>("Converting testing set to integral images (" LABEL ")", preproc_gaps[0], "X_test_ii_" LABEL,
FORCE_REDO, SAVE_STATE, OUT_DIR, set_integral_image, X_test); FORCE_REDO, SAVE_STATE, OUT_DIR, set_integral_image, X_test);
#if __DEBUG #if __DEBUG
@ -71,9 +72,9 @@ std::tuple<np::Array<int32_t>, np::Array<uint16_t>, np::Array<uint8_t>, np::Arra
print(X_test_ii, { IDX_INSPECT }); print(X_test_ii, { IDX_INSPECT });
#endif #endif
const np::Array<int32_t> X_train_feat = state_saver<int32_t>("Applying features to training set (" LABEL ")", "X_train_feat_" LABEL, const np::Array<int32_t> X_train_feat = state_saver<int32_t>("Applying features to training set (" LABEL ")", preproc_gaps[0], "X_train_feat_" LABEL,
FORCE_REDO, SAVE_STATE, OUT_DIR, apply_features, feats, X_train_ii); FORCE_REDO, SAVE_STATE, OUT_DIR, apply_features, feats, X_train_ii);
const np::Array<int32_t> X_test_feat = state_saver<int32_t>("Applying features to testing set (" LABEL ")", "X_test_feat_" LABEL, const np::Array<int32_t> X_test_feat = state_saver<int32_t>("Applying features to testing set (" LABEL ")", preproc_gaps[0], "X_test_feat_" LABEL,
FORCE_REDO, SAVE_STATE, OUT_DIR, apply_features, feats, X_test_ii); FORCE_REDO, SAVE_STATE, OUT_DIR, apply_features, feats, X_test_ii);
#if __DEBUG #if __DEBUG
@ -92,7 +93,7 @@ std::tuple<np::Array<int32_t>, np::Array<uint16_t>, np::Array<uint8_t>, np::Arra
// print_feature(indices); // print_feature(indices);
#endif #endif
const np::Array<uint16_t> X_train_feat_argsort = state_saver<uint16_t>("Precalculating training set argsort (" LABEL ")", "X_train_feat_argsort_" LABEL, const np::Array<uint16_t> X_train_feat_argsort = state_saver<uint16_t>("Precalculating training set argsort (" LABEL ")", preproc_gaps[0], "X_train_feat_argsort_" LABEL,
FORCE_REDO, SAVE_STATE, OUT_DIR, argsort_2d, X_train_feat); FORCE_REDO, SAVE_STATE, OUT_DIR, argsort_2d, X_train_feat);
#if __DEBUG #if __DEBUG
@ -101,35 +102,38 @@ std::tuple<np::Array<int32_t>, np::Array<uint16_t>, np::Array<uint8_t>, np::Arra
print(X_train_feat_argsort, { IDX_INSPECT, IDX_INSPECT + IDX_INSPECT_OFFSET }); print(X_train_feat_argsort, { IDX_INSPECT, IDX_INSPECT + IDX_INSPECT_OFFSET });
#endif #endif
const np::Array<uint16_t> X_test_feat_argsort = state_saver<uint16_t>("Precalculating testing set argsort (" LABEL ")", "X_test_feat_argsort_" LABEL, // const np::Array<uint16_t> X_test_feat_argsort = state_saver<uint16_t>("Precalculating testing set argsort (" LABEL ")", preproc_gaps[0], "X_test_feat_argsort_" LABEL,
FORCE_REDO, SAVE_STATE, OUT_DIR, argsort_2d, X_test_feat); // FORCE_REDO, SAVE_STATE, OUT_DIR, argsort_2d, X_test_feat);
#if __DEBUG #if __DEBUG
print("X_test_feat_argsort"); // printf("X_test_feat_argsort\n");
print(X_test_feat_argsort.shape); // print(X_test_feat_argsort.shape);
print(X_test_feat_argsort, { IDX_INSPECT, IDX_INSPECT + IDX_INSPECT_OFFSET }); // print(X_test_feat_argsort, { IDX_INSPECT, IDX_INSPECT + IDX_INSPECT_OFFSET });
#endif #endif
const long long time_spent = duration_ns(perf_counter_ns() - preproc_timestamp);
formatted_line(preproc_gaps, "", "", "", "");
formatted_row(preproc_gaps, { "Preprocessing summary", thousand_sep(time_spent).c_str(), format_time_ns(time_spent).c_str() });
footer(preproc_gaps);
return { X_train_feat, X_train_feat_argsort, y_train, X_test_feat, y_test }; return { X_train_feat, X_train_feat_argsort, y_train, X_test_feat, y_test };
} }
void train(const np::Array<int32_t>& X_train_feat, const np::Array<uint16_t>& X_train_feat_argsort, const np::Array<uint8_t>& y_train) { std::array<std::array<np::Array<float64_t>, 2>, TS.size()> train(const np::Array<int32_t>& X_train_feat, const np::Array<uint16_t>& X_train_feat_argsort, const np::Array<uint8_t>& y_train) noexcept {
printf("\n| %-49s | %-18s | %-29s |\n", "Training", "Time spent (ns)", "Formatted time spent"); const std::chrono::system_clock::time_point training_timestamp = perf_counter_ns();
printf("|%s|%s|%s|\n", S(51), S(20), S(31)); const std::array<int32_t, 3> training_gaps = { 26, -18, 29 };
header({ "Training", "Time spent (ns)", "Formatted time spent" }, training_gaps);
std::array<std::array<np::Array<float64_t>, 2>, TS.size()> models;
size_t i = 0;
for (const size_t T : TS) { for (const size_t T : TS) {
char title[BUFFER_SIZE] = { 0 }; char title[BUFFER_SIZE] = { 0 };
char alphas_title[BUFFER_SIZE] = { 0 }; char alphas_title[BUFFER_SIZE] = { 0 };
char final_classifiers_title[BUFFER_SIZE] = { 0 }; char final_classifiers_title[BUFFER_SIZE] = { 0 };
sprintf(title, "ViolaJones T = %-4lu (%s)", T, LABEL); snprintf(title, BUFFER_SIZE, "ViolaJones T = %-4lu (%s)", T, LABEL);
sprintf(alphas_title, "alphas_%lu_%s", T, LABEL); snprintf(alphas_title, BUFFER_SIZE, "alphas_%lu_%s", T, LABEL);
sprintf(final_classifiers_title, "final_classifiers_%lu_%s", T, LABEL); snprintf(final_classifiers_title, BUFFER_SIZE, "final_classifiers_%lu_%s", T, LABEL);
#if __DEBUG const auto [ alphas, final_classifiers ] = state_saver<float64_t, 2>(title, training_gaps[0], { alphas_title, final_classifiers_title },
const auto [ alphas, final_classifiers ] = state_saver<float64_t, 2>(title, { alphas_title, final_classifiers_title },
#else
state_saver<float64_t, 2>(title, { alphas_title, final_classifiers_title },
#endif
FORCE_REDO, SAVE_STATE, MODEL_DIR, train_viola_jones, T, X_train_feat, X_train_feat_argsort, y_train); FORCE_REDO, SAVE_STATE, MODEL_DIR, train_viola_jones, T, X_train_feat, X_train_feat_argsort, y_train);
#if __DEBUG #if __DEBUG
print("alphas"); print("alphas");
@ -137,31 +141,32 @@ void train(const np::Array<int32_t>& X_train_feat, const np::Array<uint16_t>& X_
print("final_classifiers"); print("final_classifiers");
print(final_classifiers); print(final_classifiers);
#endif #endif
models[i++] = { alphas, final_classifiers };
} }
const long long time_spent = duration_ns(perf_counter_ns() - training_timestamp);
formatted_line(training_gaps, "", "", "", "");
formatted_row(training_gaps, { "Training summary", thousand_sep(time_spent).c_str(), format_time_ns(time_spent).c_str() });
footer(training_gaps);
return models;
} }
void testing_and_evaluating(const np::Array<int32_t>& X_train_feat, const np::Array<uint8_t>& y_train, const np::Array<int32_t>& X_test_feat, const np::Array<uint8_t>& y_test) { void testing_and_evaluating(const std::array<std::array<np::Array<float64_t>, 2>, TS.size()>& models, const np::Array<int32_t>& X_train_feat, const np::Array<uint8_t>& y_train, const np::Array<int32_t>& X_test_feat, const np::Array<uint8_t>& y_test) {
printf("\n| %-26s | Time spent (ns) (E) | %-29s | Time spent (ns) (T) | %-29s |\n", "Testing", "Formatted time spent (E)", "Formatted time spent (T)"); const std::array<int32_t, 5> testing_gaps = { 26, -19, 24, -19, 24 };
printf("|%s|%s|%s|%s|%s|\n", S(28), S(21), S(31), S(21), S(31)); header({ "Testing", "Time spent (ns) (E)", "Formatted time spent (E)", "Time spent (ns) (T)", "Formatted time spent (T)" }, testing_gaps);
std::array<std::array<float64_t, 8>, TS.size()> results;
constexpr const size_t NT = sizeof(TS) / sizeof(size_t);
std::array<std::array<float64_t, 8>, NT> results;
size_t i = 0; size_t i = 0;
for (const size_t T : TS) { long long total_train_timestamp = 0;
long long total_test_timestamp = 0;
for (const auto& [ alphas, final_classifiers ] : models) {
char title[BUFFER_SIZE] = { 0 }; char title[BUFFER_SIZE] = { 0 };
char alphas_title[BUFFER_SIZE] = { 0 }; snprintf(title, BUFFER_SIZE, "ViolaJones T = %-4i (%s)", TS[i], LABEL);
char final_classifiers_title[BUFFER_SIZE] = { 0 };
sprintf(title, "ViolaJones T = %-4lu (%s)", T, LABEL);
sprintf(alphas_title, MODEL_DIR "/alphas_%lu_%s.bin", T, LABEL);
sprintf(final_classifiers_title, MODEL_DIR "/final_classifiers_%lu_%s.bin", T, LABEL);
const np::Array<float64_t> alphas = load<float64_t>(alphas_title);
const np::Array<float64_t> final_classifiers = load<float64_t>(final_classifiers_title);
std::chrono::system_clock::time_point start = perf_counter_ns(); std::chrono::system_clock::time_point start = perf_counter_ns();
const np::Array<uint8_t> y_pred_train = classify_viola_jones(alphas, final_classifiers, X_train_feat); const np::Array<uint8_t> y_pred_train = classify_viola_jones(alphas, final_classifiers, X_train_feat);
const long long t_pred_train = duration_ns(perf_counter_ns() - start); const long long t_pred_train = duration_ns(perf_counter_ns() - start);
total_train_timestamp += t_pred_train;
const float64_t e_acc = accuracy_score(y_train, y_pred_train); const float64_t e_acc = accuracy_score(y_train, y_pred_train);
const float64_t e_f1 = f1_score(y_train, y_pred_train); const float64_t e_f1 = f1_score(y_train, y_pred_train);
float64_t e_FN, e_FP; float64_t e_FN, e_FP;
@ -170,48 +175,53 @@ void testing_and_evaluating(const np::Array<int32_t>& X_train_feat, const np::Ar
start = perf_counter_ns(); start = perf_counter_ns();
const np::Array<uint8_t> y_pred_test = classify_viola_jones(alphas, final_classifiers, X_test_feat); const np::Array<uint8_t> y_pred_test = classify_viola_jones(alphas, final_classifiers, X_test_feat);
const long long t_pred_test = duration_ns(perf_counter_ns() - start); const long long t_pred_test = duration_ns(perf_counter_ns() - start);
total_test_timestamp += t_pred_test;
const float64_t t_acc = accuracy_score(y_test, y_pred_test); const float64_t t_acc = accuracy_score(y_test, y_pred_test);
const float64_t t_f1 = f1_score(y_test, y_pred_test); const float64_t t_f1 = f1_score(y_test, y_pred_test);
float64_t t_FN, t_FP; float64_t t_FN, t_FP;
std::tie(std::ignore, t_FN, t_FP, std::ignore) = confusion_matrix(y_test, y_pred_test); std::tie(std::ignore, t_FN, t_FP, std::ignore) = confusion_matrix(y_test, y_pred_test);
results[i++] = { e_acc, e_f1, e_FN, e_FP, t_acc, t_f1, t_FN, t_FP }; results[i++] = { e_acc, e_f1, e_FN, e_FP, t_acc, t_f1, t_FN, t_FP };
printf("| %-26s | %'19lld | %-29s | %'19lld | %-29s |\n", title, t_pred_train, format_time_ns(t_pred_train).c_str(), t_pred_test, format_time_ns(t_pred_test).c_str()); formatted_row(testing_gaps, { title, thousand_sep(t_pred_train).c_str(), format_time_ns(t_pred_train).c_str(), thousand_sep(t_pred_test).c_str(), format_time_ns(t_pred_test).c_str() });
} }
formatted_line(testing_gaps, "", "", "", "");
formatted_row(testing_gaps, { "Testing summary", thousand_sep(total_train_timestamp).c_str(), format_time_ns(total_train_timestamp).c_str(), thousand_sep(total_test_timestamp).c_str(), format_time_ns(total_test_timestamp).c_str() });
footer(testing_gaps);
printf("\n| %-19s | ACC (E) | F1 (E) | FN (E) | FP (E) | ACC (T) | F1 (T) | FN (T) | FP (T) |\n", "Evaluating"); const std::array<int32_t, 9> evaluating_gaps = { 19, -7, -6, -6, -6, -7, -6, -6, -6 };
printf("|%s|%s|%s|%s|%s|%s|%s|%s|%s|\n", S(21), S(9), S(8), S(8), S(8), S(9), S(8), S(8), S(8)); header({ "Evaluating", "ACC (E)", "F1 (E)", "FN (E)", "FP (E)", "ACC (T)", "F1 (T)", "FN (T)", "FP (T)"}, evaluating_gaps);
i = 0; i = 0;
for (const size_t T : TS) { for (const size_t T : TS) {
char title[BUFFER_SIZE] = { 0 }; char title[BUFFER_SIZE] = { 0 };
sprintf(title, "ViolaJones T = %-4lu", T); snprintf(title, BUFFER_SIZE, "ViolaJones T = %-4lu", T);
const auto [e_acc, e_f1, e_FN, e_FP, t_acc, t_f1, t_FN, t_FP] = results[i++]; const auto [e_acc, e_f1, e_FN, e_FP, t_acc, t_f1, t_FN, t_FP] = results[i++];
printf("| %-19s | %'6.2f%% | %'6.2f | %'6.0f | %'6.0f | %6.2f%% | %'6.2f | %'6.0f | %'6.0f |\n", title, e_acc * 100, e_f1, e_FN, e_FP, t_acc * 100, t_f1, t_FN, t_FP); printf("│ %-19s │ %'6.2f%% │ %'6.2f │ %'6.0f │ %'6.0f │ %6.2f%% │ %'6.2f │ %'6.0f │ %'6.0f │\n", title, e_acc * 100, e_f1, e_FN, e_FP, t_acc * 100, t_f1, t_FN, t_FP);
} }
footer(evaluating_gaps);
} }
void unit_test(void) { void unit_test(void) {
printf("\n| %-37s | %-10s | %-18s | %-29s |\n", "Unit testing", "Test state", "Time spent (ns)", "Formatted time spent"); const std::chrono::system_clock::time_point unit_timestamp = perf_counter_ns();
printf("|%s|%s|%s|%s|\n", S(39), S(12), S(20), S(31)); const std::array<int32_t, 4> unit_gaps = { 37, -10, -18, 29};
header({ "Unit testing", "Test state", "Time spent (ns)", "Formatted time spent" }, unit_gaps);
char title[BUFFER_SIZE] = { 0 }; char title[BUFFER_SIZE] = { 0 };
char tmp_title[BUFFER_SIZE / 2] = { 0 }; char tmp_title[BUFFER_SIZE / 2] = { 0 };
char file_cpu[BUFFER_SIZE] = { 0 }; char file_cpu[BUFFER_SIZE] = { 0 };
char file_gpu[BUFFER_SIZE] = { 0 }; char file_gpu[BUFFER_SIZE] = { 0 };
const std::chrono::system_clock::time_point fnc_s = perf_counter_ns();
uint64_t n_total = 0, n_success = 0; uint64_t n_total = 0, n_success = 0;
auto test_fnc = [&n_total, &n_success](const char* title, const auto& fnc) { const auto test_fnc = [&unit_gaps, &n_total, &n_success](const char* const title, const auto& fnc) noexcept {
++n_total; ++n_total;
const std::chrono::system_clock::time_point start = perf_counter_ns(); const std::chrono::system_clock::time_point start = perf_counter_ns();
const bool state = fnc(); const bool state = fnc();
const long long time_spent = duration_ns(perf_counter_ns() - start); const long long time_spent = duration_ns(perf_counter_ns() - start);
if(state){ if(state){
printf("| %-37s | %10s | %18s | %-29s |\n", title, "Passed", thousand_sep(time_spent).c_str(), format_time_ns(time_spent).c_str()); formatted_row(unit_gaps, { title, "Passed", thousand_sep(time_spent).c_str(), format_time_ns(time_spent).c_str() });
++n_success; ++n_success;
} else } else
printf("| %-37s | %10s | %18s | %-29s |\n", title, "Failed", thousand_sep(time_spent).c_str(), format_time_ns(time_spent).c_str()); formatted_row(unit_gaps, { title, "Failed", thousand_sep(time_spent).c_str(), format_time_ns(time_spent).c_str() });
}; };
for (const char* label : { "train", "test" }) { for (const char* label : { "train", "test" }) {
@ -275,32 +285,38 @@ void unit_test(void) {
} }
} }
const long long time_spent = duration_ns(perf_counter_ns() - fnc_s); const long long time_spent = duration_ns(perf_counter_ns() - unit_timestamp);
sprintf(title, "%ld/%ld", n_success, n_total); snprintf(title, BUFFER_SIZE, "%ld/%ld", n_success, n_total);
printf("|%s|%s|%s|%s|\n", S(39), S(12), S(20), S(31)); formatted_line(unit_gaps, "", "", "", "");
printf("| %-37s | %10s | %18s | %-29s |\n", "Unit testing summary", title, thousand_sep(time_spent).c_str(), format_time_ns(time_spent).c_str()); formatted_row(unit_gaps, { "Unit testing summary", title, thousand_sep(time_spent).c_str(), format_time_ns(time_spent).c_str() });
footer(unit_gaps);
} }
int main(){ int main(){
setlocale(LC_NUMERIC, ""); // Allow proper number display setlocale(LC_NUMERIC, ""); // Allow proper number display
printf("| %-49s | %-18s | %-29s |\n", "Unit testing", "Time spent (ns)", "Formatted time spent"); const std::chrono::system_clock::time_point unit_timestamp = perf_counter_ns();
printf("|%s|%s|%s|\n", S(51), S(20), S(31)); const std::array<int32_t, 3> unit_gaps = { 27, -18, 29 };
header({ "Unit testing", "Time spent (ns)", "Formatted time spent" }, unit_gaps);
#if GPU_BOOSTED #if GPU_BOOSTED
benchmark_function_void("Testing GPU capabilities 1D", test_working, 3 + (1<<29)); benchmark_function_void("Testing GPU capabilities 1D", unit_gaps[0], test_working, 50000);
benchmark_function_void("Testing GPU capabilities 2D", test_working_2d, 3 + (1<<15), 2 + (1<<14)); benchmark_function_void("Testing GPU capabilities 2D", unit_gaps[0], test_working_2d, 200, 500);
benchmark_function_void("Testing GPU capabilities 3D", test_working_3d, 9 + (1<<10), 5 + (1<<10), 7 + (1<<9)); benchmark_function_void("Testing GPU capabilities 3D", unit_gaps[0], test_working_3d, 30, 40, 500);
#endif #endif
benchmark_function_void("Testing format_time", format_time_test); benchmark_function_void("Testing format_time", unit_gaps[0], format_time_test);
benchmark_function_void("Testing format_time_ns", format_time_ns_test); benchmark_function_void("Testing format_time_ns", unit_gaps[0], format_time_ns_test);
benchmark_function_void("Testing format_byte_size", format_byte_size_test); benchmark_function_void("Testing format_byte_size", unit_gaps[0], format_byte_size_test);
benchmark_function_void("Testing thousand_sep", thousand_sep_test); benchmark_function_void("Testing thousand_sep", unit_gaps[0], thousand_sep_test);
printf("\n"); const long long time_spent = duration_ns(perf_counter_ns() - unit_timestamp);
formatted_line(unit_gaps, "", "", "", "");
formatted_row(unit_gaps, { "Unit testing summary", thousand_sep(time_spent).c_str(), format_time_ns(time_spent).c_str() });
footer(unit_gaps);
const auto [ X_train_feat, X_train_feat_argsort, y_train, X_test_feat, y_test ] = preprocessing(); const auto [ X_train_feat, X_train_feat_argsort, y_train, X_test_feat, y_test ] = preprocessing();
train(X_train_feat, X_train_feat_argsort, y_train); const std::array<std::array<np::Array<float64_t>, 2>, TS.size()> models = train(X_train_feat, X_train_feat_argsort, y_train);
testing_and_evaluating(X_train_feat, y_train, X_test_feat, y_test); testing_and_evaluating(models, X_train_feat, y_train, X_test_feat, y_test);
unit_test(); unit_test();
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@ -1,7 +1,41 @@
#pragma once #pragma once
#include <array> #include <array>
#include <chrono>
#include <string> #include <string>
#include <stdint.h>
template<size_t N>
constexpr void formatted_row(const std::array<int32_t, N>& gaps, const std::array<const char* const, N>& titles,
const char* const separator = "") noexcept {
for(size_t i = 0; i < N; ++i)
printf("%s %*s ", separator, -gaps[i], titles[i]);
printf("%s\n", separator);
}
template<size_t N>
constexpr void formatted_line(const std::array<int32_t, N>& gaps, const char* const right, const char* const middle,
const char* const separator, const char* const left) noexcept {
printf("%s", right);
for(size_t i = 0; i < N; ++i){
for(int32_t j = std::abs(gaps[i]) + 2; j > 0; --j)
printf("%s", separator);
if(i != N - 1)
printf("%s", middle);
}
printf("%s\n", left);
}
template<size_t N>
constexpr void header(const std::array<const char* const, N>& titles, const std::array<int32_t, N>& gaps) noexcept {
formatted_line(gaps, "", "", "", "");
formatted_row(gaps, titles);
formatted_line(gaps, "", "", "", "");
}
template<size_t N>
constexpr inline void footer(const std::array<int32_t, N>& gaps) noexcept {
formatted_line(gaps, "", "", "", "");
}
#define duration_ns(a) std::chrono::duration_cast<std::chrono::nanoseconds>(a).count() #define duration_ns(a) std::chrono::duration_cast<std::chrono::nanoseconds>(a).count()
#define perf_counter_ns() std::chrono::high_resolution_clock::now() #define perf_counter_ns() std::chrono::high_resolution_clock::now()

View File

@ -1,44 +1,47 @@
from typing import Final
import numpy as np import numpy as np
DATA_DIR = "../data" DATA_DIR: Final = '../data'
OUT_DIR = "./out" OUT_DIR: Final = './out'
MODEL_DIR = "./models" MODEL_DIR: Final = './models'
NB_THREADS = 1024 NB_THREADS: Final = 1024
NB_THREADS_2D = (32, 32) NB_THREADS_2D: Final = (32, 32)
NB_THREADS_3D = (16, 16, 4) NB_THREADS_3D: Final = (16, 16, 4)
M = int(np.log2(NB_THREADS_2D[1])) M: Final = int(np.log2(NB_THREADS_2D[1]))
# Save state to avoid recalculation on restart # Save state to avoid recalculation on restart
SAVE_STATE = True SAVE_STATE: Final = True
# Redo the state even if it's already saved # Redo the state even if it's already saved
FORCE_REDO = False FORCE_REDO: Final = False
# Use NJIT to greatly accelerate runtime # Use NJIT to greatly accelerate runtime
COMPILE_WITH_C = True COMPILE_WITH_C: Final = True
# Use GPU to greatly accelerate runtime (as priority over NJIT) # Use GPU to greatly accelerate runtime (as priority over NJIT)
GPU_BOOSTED = True GPU_BOOSTED: Final = True
# Depending on what you set, the output label will be as follow : # Depending on what you set, the output label will be as follow :
# | COMPILE_WITH_C | GPU_BOOSTED | LABEL | # ┌────────────────┬─────────────┬───────┐
# |----------------|-------------|-------| # │ COMPILE_WITH_C │ GPU_BOOSTED │ LABEL │
# | True | True | GPU | # ├────────────────┼─────────────┼───────┤
# | True | False | CPU | # │ True │ True │ GPU │
# | False | True | PGPU | # │ True │ False │ CPU │
# | False | False | PY | # │ False │ True │ PGPU │
# │ False │ False │ PY │
# └────────────────┴─────────────┴───────┘
# Number of weak classifiers # Number of weak classifiers
# TS = [1] # TS: Final = [1]
# TS = [1, 5, 10] # TS: Final = [1, 5, 10]
TS = [1, 5, 10, 25, 50] TS: Final = [1, 5, 10, 25, 50]
# TS = [1, 5, 10, 25, 50, 100, 200] # TS: Final = [1, 5, 10, 25, 50, 100, 200]
# TS = [1, 5, 10, 25, 50, 100, 200, 300] # TS: Final = [1, 5, 10, 25, 50, 100, 200, 300]
# TS = [1, 5, 10, 25, 50, 100, 200, 300, 400, 500, 1000] # TS: Final = [1, 5, 10, 25, 50, 100, 200, 300, 400, 500, 1000]
# Enable verbose output (for debugging purposes) # Enable verbose output (for debugging purposes)
__DEBUG = False __DEBUG: Final = False
# Debugging options # Debugging options
if __DEBUG: if __DEBUG:
IDX_INSPECT = 4548 IDX_INSPECT: Final = 4548
IDX_INSPECT_OFFSET = 100 IDX_INSPECT_OFFSET: Final = 100
np.seterr(all = 'raise') np.seterr(all = 'raise')
# Debug option (image width * log_10(length) + extra characters) # Debug option (image width * log_10(length) + extra characters)
np.set_printoptions(linewidth = 19 * 6 + 3) np.set_printoptions(linewidth = 19 * 6 + 3)

View File

@ -4,6 +4,7 @@
from ViolaJones import train_viola_jones, classify_viola_jones from ViolaJones import train_viola_jones, classify_viola_jones
from toolbox import state_saver, picke_multi_loader, format_time_ns, benchmark_function, unit_test_argsort_2d from toolbox import state_saver, picke_multi_loader, format_time_ns, benchmark_function, unit_test_argsort_2d
from toolbox_unit_test import format_time_ns_test from toolbox_unit_test import format_time_ns_test
from toolbox import header, footer, formatted_row, formatted_line
from sklearn.metrics import accuracy_score, f1_score, confusion_matrix from sklearn.metrics import accuracy_score, f1_score, confusion_matrix
from sklearn.feature_selection import SelectPercentile, f_classif from sklearn.feature_selection import SelectPercentile, f_classif
from common import load_datasets, unit_test from common import load_datasets, unit_test
@ -38,9 +39,11 @@ def preprocessing() -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
for folder_name in ["models", "out"]: for folder_name in ["models", "out"]:
makedirs(folder_name, exist_ok = True) makedirs(folder_name, exist_ok = True)
print(f"| {'Preprocessing':<49} | {'Time spent (ns)':<18} | {'Formatted time spent':<29} |\n|{'-'*51}|{'-'*20}|{'-'*31}|") preproc_timestamp = perf_counter_ns()
preproc_gaps = [49, -18, 29]
header(['Preprocessing', 'Time spent (ns)', 'Formatted time spent'], preproc_gaps)
X_train, y_train, X_test, y_test = state_saver("Loading sets", ["X_train", "y_train", "X_test", "y_test"], X_train, y_train, X_test, y_test = state_saver('Loading sets', preproc_gaps[0], ['X_train', 'y_train', 'X_test', 'y_test'],
load_datasets, FORCE_REDO, SAVE_STATE) load_datasets, FORCE_REDO, SAVE_STATE)
if __DEBUG: if __DEBUG:
@ -57,16 +60,17 @@ def preprocessing() -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
print(y_test.shape) print(y_test.shape)
print(y_test[IDX_INSPECT: IDX_INSPECT + IDX_INSPECT_OFFSET]) print(y_test[IDX_INSPECT: IDX_INSPECT + IDX_INSPECT_OFFSET])
feats = state_saver("Building features", "feats", lambda: build_features(X_train.shape[1], X_train.shape[2]), FORCE_REDO, SAVE_STATE) feats = state_saver('Building features', preproc_gaps[0], 'feats', lambda: build_features(X_train.shape[1], X_train.shape[2]),
FORCE_REDO, SAVE_STATE)
if __DEBUG: if __DEBUG:
print("feats") print("feats")
print(feats.shape) print(feats.shape)
print(feats[IDX_INSPECT].ravel()) print(feats[IDX_INSPECT].ravel())
X_train_ii = state_saver(f"Converting training set to integral images ({label})", f"X_train_ii_{label}", X_train_ii = state_saver(f'Converting training set to integral images ({label})', preproc_gaps[0], f'X_train_ii_{label}',
lambda: set_integral_image(X_train), FORCE_REDO, SAVE_STATE) lambda: set_integral_image(X_train), FORCE_REDO, SAVE_STATE)
X_test_ii = state_saver(f"Converting testing set to integral images ({label})", f"X_test_ii_{label}", X_test_ii = state_saver(f'Converting testing set to integral images ({label})', preproc_gaps[0], f'X_test_ii_{label}',
lambda: set_integral_image(X_test), FORCE_REDO, SAVE_STATE) lambda: set_integral_image(X_test), FORCE_REDO, SAVE_STATE)
if __DEBUG: if __DEBUG:
@ -77,9 +81,9 @@ def preprocessing() -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
print(X_test_ii.shape) print(X_test_ii.shape)
print(X_test_ii[IDX_INSPECT]) print(X_test_ii[IDX_INSPECT])
X_train_feat = state_saver(f"Applying features to training set ({label})", f"X_train_feat_{label}", X_train_feat = state_saver(f'Applying features to training set ({label})', preproc_gaps[0], f'X_train_feat_{label}',
lambda: apply_features(feats, X_train_ii), FORCE_REDO, SAVE_STATE) lambda: apply_features(feats, X_train_ii), FORCE_REDO, SAVE_STATE)
X_test_feat = state_saver(f"Applying features to testing set ({label})", f"X_test_feat_{label}", X_test_feat = state_saver(f'Applying features to testing set ({label})', preproc_gaps[0], f'X_test_feat_{label}',
lambda: apply_features(feats, X_test_ii), FORCE_REDO, SAVE_STATE) lambda: apply_features(feats, X_test_ii), FORCE_REDO, SAVE_STATE)
del X_train_ii, X_test_ii, feats del X_train_ii, X_test_ii, feats
@ -106,14 +110,14 @@ def preprocessing() -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
# X_train_feat, X_test_feat = X_train_feat[indices], X_test_feat[indices] # X_train_feat, X_test_feat = X_train_feat[indices], X_test_feat[indices]
X_train_feat_argsort = state_saver(f"Precalculating training set argsort ({label})", f"X_train_feat_argsort_{label}", X_train_feat_argsort = state_saver(f'Precalculating training set argsort ({label})', preproc_gaps[0], f'X_train_feat_argsort_{label}',
lambda: argsort(X_train_feat), FORCE_REDO, SAVE_STATE) lambda: argsort(X_train_feat), FORCE_REDO, SAVE_STATE)
if __DEBUG: if __DEBUG:
print("X_train_feat_argsort") print("X_train_feat_argsort")
print(X_train_feat_argsort.shape) print(X_train_feat_argsort.shape)
print(X_train_feat_argsort[IDX_INSPECT, : IDX_INSPECT_OFFSET]) print(X_train_feat_argsort[IDX_INSPECT, : IDX_INSPECT_OFFSET])
benchmark_function("Arg unit test", lambda: unit_test_argsort_2d(X_train_feat, X_train_feat_argsort)) benchmark_function('Arg unit test', preproc_gaps[0], lambda: unit_test_argsort_2d(X_train_feat, X_train_feat_argsort))
X_test_feat_argsort = state_saver(f"Precalculating testing set argsort ({label})", f"X_test_feat_argsort_{label}", X_test_feat_argsort = state_saver(f"Precalculating testing set argsort ({label})", f"X_test_feat_argsort_{label}",
lambda: argsort(X_test_feat), FORCE_REDO, SAVE_STATE) lambda: argsort(X_test_feat), FORCE_REDO, SAVE_STATE)
@ -123,48 +127,70 @@ def preprocessing() -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
print(X_test_feat_argsort.shape) print(X_test_feat_argsort.shape)
print(X_test_feat_argsort[IDX_INSPECT, : IDX_INSPECT_OFFSET]) print(X_test_feat_argsort[IDX_INSPECT, : IDX_INSPECT_OFFSET])
benchmark_function("Arg unit test", lambda: unit_test_argsort_2d(X_test_feat, X_test_feat_argsort)) benchmark_function("Arg unit test", lambda: unit_test_argsort_2d(X_test_feat, X_test_feat_argsort))
time_spent = perf_counter_ns() - preproc_timestamp
formatted_line(preproc_gaps, '', '', '', '')
formatted_row(preproc_gaps, ['Preprocessing summary', f'{time_spent:,}', format_time_ns(time_spent)])
footer(preproc_gaps)
return X_train_feat, X_train_feat_argsort, y_train, X_test_feat, y_test return X_train_feat, X_train_feat_argsort, y_train, X_test_feat, y_test
def train(X_train_feat: np.ndarray, X_train_feat_argsort: np.ndarray, y_train: np.ndarray) -> None: def train(X_train_feat: np.ndarray, X_train_feat_argsort: np.ndarray, y_train: np.ndarray) -> List[np.ndarray]:
"""Train the weak classifiers. """Train the weak classifiers.
Args: Args:
X_train (np.ndarray): Training images. X_train (np.ndarray): Training images.
X_test (np.ndarray): Testing Images. X_train_feat_argsort (np.ndarray): Sorted indexes of the training images features.
y_train (np.ndarray): Training labels. y_train (np.ndarray): Training labels.
Returns: List of trained models
""" """
print(f"\n| {'Training':<49} | {'Time spent (ns)':<18} | {'Formatted time spent':<29} |\n|{'-'*51}|{'-'*20}|{'-'*31}|")
training_timestamp = perf_counter_ns()
training_gaps = [26, -18, 29]
header(['Training', 'Time spent (ns)', 'Formatted time spent'], training_gaps)
models = []
for T in TS: for T in TS:
alphas, final_classifiers = state_saver(f"ViolaJones T = {T:<3} ({label})", [f"alphas_{T}_{label}", f"final_classifiers_{T}_{label}"], alphas, final_classifiers = state_saver(f'ViolaJones T = {T:<4} ({label})', training_gaps[0],
lambda: train_viola_jones(T, X_train_feat, X_train_feat_argsort, y_train), FORCE_REDO, SAVE_STATE, MODEL_DIR) [f'alphas_{T}_{label}', f'final_classifiers_{T}_{label}'],
lambda: train_viola_jones(T, X_train_feat, X_train_feat_argsort, y_train), FORCE_REDO, SAVE_STATE, MODEL_DIR)
models.append([alphas, final_classifiers])
if __DEBUG: if __DEBUG:
print("alphas") print("alphas")
print(alphas) print(alphas)
print("final_classifiers") print("final_classifiers")
print(final_classifiers) print(final_classifiers)
def testing_and_evaluating(X_train_feat: np.ndarray, y_train: np.ndarray, X_test_feat: np.ndarray, y_test: np.ndarray) -> None: time_spent = perf_counter_ns() - training_timestamp
formatted_line(training_gaps, '', '', '', '')
formatted_row(training_gaps, ['Training summary', f'{time_spent:,}', format_time_ns(time_spent)])
footer(training_gaps)
return models
def testing_and_evaluating(models: List[np.ndarray], X_train_feat: np.ndarray, y_train: np.ndarray, X_test_feat: np.ndarray, y_test: np.ndarray) -> None:
"""Benchmark the trained classifiers on the training and testing sets. """Benchmark the trained classifiers on the training and testing sets.
Args: Args:
models (List[np.ndarray]): List of trained models.
X_train_feat (np.ndarray): Training features. X_train_feat (np.ndarray): Training features.
y_train (np.ndarray): Training labels. y_train (np.ndarray): Training labels.
X_test_feat (np.ndarray): Testing features. X_test_feat (np.ndarray): Testing features.
y_test (np.ndarray): Testing labels. y_test (np.ndarray): Testing labels.
""" """
print(f"\n| {'Testing':<26} | Time spent (ns) (E) | {'Formatted time spent (E)':<29}", end = " | ")
print(f"Time spent (ns) (T) | {'Formatted time spent (T)':<29} |")
print(f"|{'-'*28}|{'-'*21}|{'-'*31}|{'-'*21}|{'-'*31}|")
perfs = [] testing_gaps = [26, -19, 24, -19, 24]
for T in TS: header(['Testing', 'Time spent (ns) (E)', 'Formatted time spent (E)', 'Time spent (ns) (T)', 'Formatted time spent (T)'], testing_gaps)
(alphas, final_classifiers) = picke_multi_loader([f"alphas_{T}_{label}", f"final_classifiers_{T}_{label}"])
performances = []
total_train_timestamp = 0
total_test_timestamp = 0
for T, (alphas, final_classifiers) in zip(TS, models):
s = perf_counter_ns() s = perf_counter_ns()
y_pred_train = classify_viola_jones(alphas, final_classifiers, X_train_feat) y_pred_train = classify_viola_jones(alphas, final_classifiers, X_train_feat)
t_pred_train = perf_counter_ns() - s t_pred_train = perf_counter_ns() - s
total_train_timestamp += t_pred_train
e_acc = accuracy_score(y_train, y_pred_train) e_acc = accuracy_score(y_train, y_pred_train)
e_f1 = f1_score(y_train, y_pred_train) e_f1 = f1_score(y_train, y_pred_train)
(_, e_FP), (e_FN, _) = confusion_matrix(y_train, y_pred_train) (_, e_FP), (e_FN, _) = confusion_matrix(y_train, y_pred_train)
@ -172,36 +198,48 @@ def testing_and_evaluating(X_train_feat: np.ndarray, y_train: np.ndarray, X_test
s = perf_counter_ns() s = perf_counter_ns()
y_pred_test = classify_viola_jones(alphas, final_classifiers, X_test_feat) y_pred_test = classify_viola_jones(alphas, final_classifiers, X_test_feat)
t_pred_test = perf_counter_ns() - s t_pred_test = perf_counter_ns() - s
total_test_timestamp += t_pred_test
t_acc = accuracy_score(y_test, y_pred_test) t_acc = accuracy_score(y_test, y_pred_test)
t_f1 = f1_score(y_test, y_pred_test) t_f1 = f1_score(y_test, y_pred_test)
(_, t_FP), (t_FN, _) = confusion_matrix(y_test, y_pred_test) (_, t_FP), (t_FN, _) = confusion_matrix(y_test, y_pred_test)
perfs.append((e_acc, e_f1, e_FN, e_FP, t_acc, t_f1, t_FN, t_FP)) performances.append((e_acc, e_f1, e_FN, e_FP, t_acc, t_f1, t_FN, t_FP))
print(f"| {'ViolaJones T = ' + str(T):<19} {'(' + label + ')':<6}", end = " | ") formatted_row(testing_gaps, [f"{'ViolaJones T = ' + str(T):<19} {'(' + label + ')':<6}", f'{t_pred_train:,}',
print(f"{t_pred_train:>19,} | {format_time_ns(t_pred_train):<29}", end = " | ") format_time_ns(t_pred_train), f'{t_pred_test:,}', format_time_ns(t_pred_test)])
print(f"{t_pred_test:>19,} | {format_time_ns(t_pred_test):<29} |")
print(f"\n| {'Evaluating':<19} | ACC (E) | F1 (E) | FN (E) | FP (E) | ACC (T) | F1 (T) | FN (T) | FP (T) | ") formatted_line(testing_gaps, '', '', '', '')
print(f"|{'-'*21}|{'-'*9}|{'-'*8}|{'-'*8}|{'-'*8}|{'-'*9}|{'-'*8}|{'-'*8}|{'-'*8}|") formatted_row(testing_gaps, ['Testing summary', f'{total_train_timestamp:,}', format_time_ns(total_train_timestamp), f'{total_test_timestamp:,}',
format_time_ns(total_test_timestamp)])
footer(testing_gaps)
for T, (e_acc, e_f1, e_FN, e_FP, t_acc, t_f1, t_FN, t_FP) in zip(TS, perfs): evaluating_gaps = [19, 7, 6, 6, 6, 7, 6, 6, 6]
print(f"| {'ViolaJones T = ' + str(T):<19} | {e_acc:>7.2%} | {e_f1:>6.2f} | {e_FN:>6,} | {e_FP:>6,}", end = " | ") header(['Evaluating', 'ACC (E)', 'F1 (E)', 'FN (E)', 'FP (E)', 'ACC (T)', 'F1 (T)', 'FN (T)', 'FP (T)'], evaluating_gaps)
print(f"{t_acc:>7.2%} | {t_f1:>6.2f} | {t_FN:>6,} | {t_FP:>6,} |")
for T, (e_acc, e_f1, e_FN, e_FP, t_acc, t_f1, t_FN, t_FP) in zip(TS, performances):
print(f'│ ViolaJones T = {T:<4}{e_acc:>7.2%}{e_f1:>6.2f}{e_FN:>6,}{e_FP:>6,}', end = '')
print(f'{t_acc:>7.2%}{t_f1:>6.2f}{t_FN:>6,}{t_FP:>6,}')
footer(evaluating_gaps)
def main() -> None: def main() -> None:
print(f"| {'Unit testing':<49} | {'Time spent (ns)':<18} | {'Formatted time spent':<29} |") unit_timestamp = perf_counter_ns()
print(f"|{'-'*51}|{'-'*20}|{'-'*31}|") unit_gaps = [27, -18, 29]
benchmark_function("Testing format_time_ns", format_time_ns_test) header(['Unit testing', 'Time spent (ns)', 'Formatted time spent'], unit_gaps)
print() benchmark_function('testing format_time', unit_gaps[0], format_time_test)
benchmark_function('testing format_time_ns', unit_gaps[0], format_time_ns_test)
time_spent = perf_counter_ns() - unit_timestamp
formatted_line(unit_gaps, '', '', '', '')
formatted_row(unit_gaps, ['Unit testing summary', f'{time_spent:,}', format_time_ns(time_spent)])
footer(unit_gaps)
X_train_feat, X_train_feat_argsort, y_train, X_test_feat, y_test = preprocessing() X_train_feat, X_train_feat_argsort, y_train, X_test_feat, y_test = preprocessing()
train(X_train_feat, X_train_feat_argsort, y_train) models = train(X_train_feat, X_train_feat_argsort, y_train)
# X_train_feat, X_test_feat = picke_multi_loader([f"X_train_feat_{label}", f"X_test_feat_{label}"], OUT_DIR) # X_train_feat, X_test_feat = picke_multi_loader([f"X_train_feat_{label}", f"X_test_feat_{label}"], OUT_DIR)
# indices = picke_multi_loader(["indices"], OUT_DIR)[0] # indices = picke_multi_loader(["indices"], OUT_DIR)[0]
# X_train_feat, X_test_feat = X_train_feat[indices], X_test_feat[indices] # X_train_feat, X_test_feat = X_train_feat[indices], X_test_feat[indices]
testing_and_evaluating(X_train_feat, y_train, X_test_feat, y_test) testing_and_evaluating(models, X_train_feat, y_train, X_test_feat, y_test)
unit_test(TS) unit_test(TS)
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -2,12 +2,35 @@ from typing import Any, Callable, List, Union, Final
from time import perf_counter_ns from time import perf_counter_ns
from numba import njit from numba import njit
import numpy as np import numpy as np
from sys import stderr
import pickle import pickle
import os import os
from config import MODEL_DIR, OUT_DIR from config import MODEL_DIR, OUT_DIR
from decorators import njit from decorators import njit
time_formats: Final = ["ns", "µs", "ms", "s", "m", "h", "j", "w", "M", "y", "c"] time_formats: Final = ["ns", "µs", "ms", "s", "m", "h", "j", "w", "M", "y", "c"]
def formatted_row(gaps: list[int], titles: list[str], separator: str = '') -> None:
for gap, title in zip(gaps, titles):
print(f"{separator} {title:{'>' if gap < 0 else '<'}{abs(gap)}} ", end = '')
print(separator)
def formatted_line(gaps: list[int], right: str, middle: str, separator: str, left: str) -> None:
print(right, end = '')
last_gap = len(gaps) - 1
for i, gap in enumerate(gaps):
print(f'{separator * (abs(gap) + 2)}', end = '')
if i != last_gap:
print(middle, end = '')
print(left)
def header(titles: list[str], gaps: list[int]) -> None:
formatted_line(gaps, '', '', '', '')
formatted_row(gaps, titles)
formatted_line(gaps, '', '', '', '')
def footer(gaps: list[int]) -> None:
formatted_line(gaps, '', '', '', '')
time_numbers: Final = np.array([1, 1e3, 1e6, 1e9, 6e10, 36e11, 864e11, 6048e11, 26784e11, 31536e12, 31536e14], dtype = np.uint64) time_numbers: Final = np.array([1, 1e3, 1e6, 1e9, 6e10, 36e11, 864e11, 6048e11, 26784e11, 31536e12, 31536e14], dtype = np.uint64)
@njit('str(uint64)') @njit('str(uint64)')
def format_time_ns(time: int) -> str: def format_time_ns(time: int) -> str:
@ -53,7 +76,7 @@ def picke_multi_loader(filenames: List[str], save_dir: str = MODEL_DIR) -> List[
b.append(None) b.append(None)
return b return b
def benchmark_function(step_name: str, fnc: Callable) -> Any: def benchmark_function(step_name: str, column_width: int, fnc: Callable) -> Any:
"""Benchmark a function and display the result of stdout. """Benchmark a function and display the result of stdout.
Args: Args:
@ -63,14 +86,15 @@ def benchmark_function(step_name: str, fnc: Callable) -> Any:
Returns: Returns:
Any: Result of the function. Any: Result of the function.
""" """
print(f"{step_name}...", end = "\r") print(f'{step_name}...', file = stderr, end = '\r')
s = perf_counter_ns() s = perf_counter_ns()
b = fnc() b = fnc()
e = perf_counter_ns() - s e = perf_counter_ns() - s
print(f"| {step_name:<49} | {e:>18,} | {format_time_ns(e):<29} |") print(f'{step_name:<{column_width}}{e:>18,}{format_time_ns(e):<29}')
return b return b
def state_saver(step_name: str, filename: Union[str, List[str]], fnc, force_redo: bool = False, save_state: bool = True, save_dir: str = OUT_DIR) -> Any: def state_saver(step_name: str, column_width: int, filename: Union[str, List[str]], fnc, force_redo: bool = False,
save_state: bool = True, save_dir: str = OUT_DIR) -> Any:
"""Either execute a function then saves the result or load the already existing result. """Either execute a function then saves the result or load the already existing result.
Args: Args:
@ -85,18 +109,18 @@ def state_saver(step_name: str, filename: Union[str, List[str]], fnc, force_redo
""" """
if isinstance(filename, str): if isinstance(filename, str):
if not os.path.exists(f"{save_dir}/{filename}.pkl") or force_redo: if not os.path.exists(f"{save_dir}/{filename}.pkl") or force_redo:
b = benchmark_function(step_name, fnc) b = benchmark_function(step_name, column_width, fnc)
if save_state: if save_state:
print(f"Saving results of {step_name}", end = '\r')
with open(f"{save_dir}/{filename}.pkl", 'wb') as f: with open(f"{save_dir}/{filename}.pkl", 'wb') as f:
print(f'Saving results of {step_name}', file = stderr, end = '\r')
pickle.dump(b, f) pickle.dump(b, f)
print(' ' * 100, end = '\r') print(' ' * 100, file = stderr, end = '\r')
return b return b
else: else:
print(f"Loading results of {step_name}", end = '\r')
with open(f"{save_dir}/{filename}.pkl", "rb") as f: with open(f"{save_dir}/{filename}.pkl", "rb") as f:
print(f'Loading results of {step_name}', file = stderr, end = '\r')
res = pickle.load(f) res = pickle.load(f)
print(f"| {step_name:<49} | {'None':>18} | {'loaded saved state':<29} |") print(f"{step_name:<{column_width}}{'None':>18} {'loaded saved state':<29} ")
return res return res
elif isinstance(filename, list): elif isinstance(filename, list):
abs = False abs = False
@ -105,22 +129,22 @@ def state_saver(step_name: str, filename: Union[str, List[str]], fnc, force_redo
abs = True abs = True
break break
if abs or force_redo: if abs or force_redo:
b = benchmark_function(step_name, fnc) b = benchmark_function(step_name, column_width, fnc)
if save_state: if save_state:
print(f"Saving results of {step_name}", end = '\r') print(f'Saving results of {step_name}', file = stderr, end = '\r')
for bi, fnI in zip(b, filename): for bi, fnI in zip(b, filename):
with open(f"{save_dir}/{fnI}.pkl", 'wb') as f: with open(f"{save_dir}/{fnI}.pkl", 'wb') as f:
pickle.dump(bi, f) pickle.dump(bi, f)
print(' ' * 100, end = '\r') print(' ' * 100, file = stderr, end = '\r')
return b return b
print(f"| {step_name:<49} | {'None':>18} | {'loaded saved state':<29} |") print(f"{step_name:<{column_width}}{'None':>18} {'loaded saved state':<29} ")
b = [] b = []
print(f"Loading results of {step_name}", end = '\r') print(f'Loading results of {step_name}', file = stderr, end = '\r')
for fn in filename: for fn in filename:
with open(f"{save_dir}/{fn}.pkl", "rb") as f: with open(f"{save_dir}/{fn}.pkl", "rb") as f:
b.append(pickle.load(f)) b.append(pickle.load(f))
print(' ' * 100, end = '\r') print(' ' * 100, file = stderr, end = '\r')
return b return b
else: else:
assert False, f"Incompatible filename type = {type(filename)}" assert False, f"Incompatible filename type = {type(filename)}"