From 211dcad893a4f5d64601923a2faafc163eac7a63 Mon Sep 17 00:00:00 2001 From: saundersp Date: Thu, 21 Mar 2024 00:50:13 +0100 Subject: [PATCH] Better handling of printing results board --- cpp/ViolaJones.hpp | 64 ++++++++++--------- cpp/config.hpp | 23 ++++--- cpp/data.hpp | 1 - cpp/projet.cpp | 152 +++++++++++++++++++++++++-------------------- cpp/toolbox.hpp | 36 ++++++++++- python/config.py | 55 ++++++++-------- python/projet.py | 110 +++++++++++++++++++++----------- python/toolbox.py | 54 +++++++++++----- 8 files changed, 307 insertions(+), 188 deletions(-) diff --git a/cpp/ViolaJones.hpp b/cpp/ViolaJones.hpp index b525fa9..7a2e387 100644 --- a/cpp/ViolaJones.hpp +++ b/cpp/ViolaJones.hpp @@ -1,6 +1,5 @@ #pragma once #include -namespace fs = std::filesystem; #include "data.hpp" #include "toolbox.hpp" //#include "config.hpp" @@ -53,62 +52,64 @@ bool unit_test_argsort_2d(const np::Array& a, const np::Array& indi } template -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 - printf("%s...\r", step_name); - fflush(stdout); // manual flush is mandatory, otherwise it will not be shown immediately because the output is buffered + fprintf(stderr, "%s...\r", step_name); + fflush(stderr); // manual flush is mandatory, otherwise it will not be shown immediately because the output is buffered #endif const std::chrono::system_clock::time_point start = perf_counter_ns(); const T res = fnc(std::forward(args)...); 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; } template -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 - printf("%s...\r", step_name); - fflush(stdout); // manual flush is mandatory, otherwise it will not be shown immediately because the output is buffered + fprintf(stderr, "%s...\r", step_name); + fflush(stderr); // manual flush is mandatory, otherwise it will not be shown immediately because the output is buffered #endif const std::chrono::system_clock::time_point start = perf_counter_ns(); fnc(std::forward(args)...); 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 -np::Array 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 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 }; - sprintf(filepath, "%s/%s.bin", out_dir, filename); + snprintf(filepath, BUFFER_SIZE, "%s/%s.bin", out_dir, filename); np::Array bin; - if (!fs::exists(filepath) || force_redo) { - bin = std::move(benchmark_function>(step_name, fnc, std::forward(args)...)); + if (!std::filesystem::exists(filepath) || force_redo) { + //bin = std::move(benchmark_function>(step_name, column_width, fnc, std::forward(args)...)); + bin = benchmark_function>(step_name, column_width, fnc, std::forward(args)...); if(save_state){ #if __DEBUG == false - printf("Saving results of %s\r", step_name); - fflush(stdout); + fprintf(stderr, "Saving results of %s\r", step_name); + fflush(stderr); #endif save(bin, filepath); #if __DEBUG == false - printf("%*c\r", 100, ' '); - fflush(stdout); + fprintf(stderr, "%*c\r", 100, ' '); // Clear previous clear + fflush(stderr); #endif } } else { #if __DEBUG == false - printf("Loading results of %s\r", step_name); - fflush(stdout); + fprintf(stderr, "Loading results of %s\r", step_name); + fflush(stderr); #endif - bin = std::move(load(filepath)); - printf("| %-49s | %18s | %-29s |\n", step_name, "None", "loaded saved state"); + //bin = std::move(load(filepath)); + bin = load(filepath); + formatted_row<3>({ column_width, -18, 29 }, { step_name, "None", "loaded saved state" }); } return bin; } template -std::array, N> state_saver(const char* step_name, const std::vector& filenames, const bool& force_redo, const bool& save_state, const char* out_dir, const F& fnc, Args &&...args) noexcept { +std::array, N> state_saver(const char* const step_name, const int32_t& column_width, const std::vector& 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 }; bool abs = false; for (const char* filename : filenames){ @@ -121,11 +122,12 @@ std::array, N> state_saver(const char* step_name, const std::vector std::array, N> bin; if (abs || force_redo) { - bin = std::move(benchmark_function, N>>(step_name, fnc, std::forward(args)...)); + //bin = std::move(benchmark_function, N>>(step_name, column_width, fnc, std::forward(args)...)); + bin = benchmark_function, N>>(step_name, column_width, fnc, std::forward(args)...); if (save_state){ #if __DEBUG == false - printf("Saving results of %s\r", step_name); - fflush(stdout); + fprintf(stderr, "Saving results of %s\r", step_name); + fflush(stderr); #endif size_t i = 0; for (const char* filename : filenames){ @@ -133,21 +135,21 @@ std::array, N> state_saver(const char* step_name, const std::vector save(bin[i++], filepath); } #if __DEBUG == false - printf("%*c\r", 100, ' '); - fflush(stdout); + fprintf(stderr, "%*c\r", 100, ' '); // Clear previous print + fflush(stderr); #endif } } else { #if __DEBUG == false - printf("Loading results of %s\r", step_name); - fflush(stdout); + fprintf(stderr, "Loading results of %s\r", step_name); + fflush(stderr); #endif size_t i = 0; for (const char* filename : filenames){ - sprintf(filepath, "%s/%s.bin", out_dir, filename); bin[i++] = std::move(load(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; } diff --git a/cpp/config.hpp b/cpp/config.hpp index 7ca32f2..833e9d2 100644 --- a/cpp/config.hpp +++ b/cpp/config.hpp @@ -1,4 +1,5 @@ #pragma once +#include #define DATA_DIR "../data" #define OUT_DIR "./out" @@ -11,7 +12,7 @@ #define NB_THREADS_3D_X 16 #define NB_THREADS_3D_Y 16 #define NB_THREADS_3D_Z 4 -__device__ constexpr const size_t M = 5; //log2(NB_THREADS_2D_Y)); +#define M static_cast(log2f(NB_THREADS_2D_Y)) #endif // 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 #define GPU_BOOSTED true // Depending on what you set, the output label will be as follow : -// | GPU_BOOSTED | LABEL | -// |-------------|-------| -// | true | GPU | -// | false | CPU | +// ┌─────────────┬───────┐ +// │ GPU_BOOSTED │ LABEL │ +// ├─────────────┼───────┤ +// │ true │ GPU │ +// │ false │ CPU │ +// └─────────────┴───────┘ // Number of weak classifiers -// const size_t TS[] = { 1 }; -// const size_t TS[] = { 1, 5, 10 }; -const size_t TS[] = { 1, 5, 10, 25, 50 }; -// const size_t 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 }; +// [[maybe_unused]] constexpr const std::array TS{ 1, 5, 10 }; +[[maybe_unused]] constexpr const std::array TS{ 1, 5, 10, 25, 50 }; +// [[maybe_unused]] constexpr const std::array TS{ 1, 5, 10, 25, 50, 100, 200, 300 }; +// [[maybe_unused]] constexpr const std::array TS{ 1, 5, 10, 25, 50, 100, 200, 300, 400, 500, 1000 }; // Enable verbose output (for debugging purposes) #define __DEBUG false diff --git a/cpp/data.hpp b/cpp/data.hpp index 464e43a..6154eff 100644 --- a/cpp/data.hpp +++ b/cpp/data.hpp @@ -9,7 +9,6 @@ #define BUFFER_SIZE 256 #define STRING_INT_SIZE 8 // Length of a number in log10 (including '-') -#define S(N) std::string(N, '-').c_str() #ifndef __CUDACC__ #define __host__ diff --git a/cpp/projet.cpp b/cpp/projet.cpp index c08a83f..48d6730 100644 --- a/cpp/projet.cpp +++ b/cpp/projet.cpp @@ -27,10 +27,11 @@ std::tuple, np::Array, np::Array, np::Arra for (const char* const folder_name : { "models", "out" }) fs::create_directory(folder_name); - printf("| %-49s | %-18s | %-29s |\n", "Preprocessing", "Time spent (ns)", "Formatted time spent"); - printf("|%s|%s|%s|\n", S(51), S(20), S(31)); + const std::chrono::system_clock::time_point preproc_timestamp = perf_counter_ns(); + const std::array 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("Loading sets", {"X_train", "y_train", "X_test", "y_test"}, + const auto [ X_train, y_train, X_test, y_test ] = state_saver("Loading sets", preproc_gaps[0], {"X_train", "y_train", "X_test", "y_test"}, FORCE_REDO, SAVE_STATE, OUT_DIR, load_datasets); #if __DEBUG @@ -48,7 +49,7 @@ std::tuple, np::Array, np::Array, np::Arra print(y_test, { IDX_INSPECT, IDX_INSPECT + IDX_INSPECT_OFFSET }); #endif - const np::Array feats = state_saver("Building features", "feats", + const np::Array feats = state_saver("Building features", preproc_gaps[0], "feats", FORCE_REDO, SAVE_STATE, OUT_DIR, build_features, X_train.shape[1], X_train.shape[2]); #if __DEBUG @@ -57,9 +58,9 @@ std::tuple, np::Array, np::Array, np::Arra print_feat(feats, { IDX_INSPECT }); #endif - const np::Array X_train_ii = state_saver("Converting training set to integral images (" LABEL ")", "X_train_ii_" LABEL, + const np::Array X_train_ii = state_saver("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); - const np::Array X_test_ii = state_saver("Converting testing set to integral images (" LABEL ")", "X_test_ii_" LABEL, + const np::Array X_test_ii = state_saver("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); #if __DEBUG @@ -71,9 +72,9 @@ std::tuple, np::Array, np::Array, np::Arra print(X_test_ii, { IDX_INSPECT }); #endif - const np::Array X_train_feat = state_saver("Applying features to training set (" LABEL ")", "X_train_feat_" LABEL, + const np::Array X_train_feat = state_saver("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); - const np::Array X_test_feat = state_saver("Applying features to testing set (" LABEL ")", "X_test_feat_" LABEL, + const np::Array X_test_feat = state_saver("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); #if __DEBUG @@ -92,7 +93,7 @@ std::tuple, np::Array, np::Array, np::Arra // print_feature(indices); #endif - const np::Array X_train_feat_argsort = state_saver("Precalculating training set argsort (" LABEL ")", "X_train_feat_argsort_" LABEL, + const np::Array X_train_feat_argsort = state_saver("Precalculating training set argsort (" LABEL ")", preproc_gaps[0], "X_train_feat_argsort_" LABEL, FORCE_REDO, SAVE_STATE, OUT_DIR, argsort_2d, X_train_feat); #if __DEBUG @@ -101,35 +102,38 @@ std::tuple, np::Array, np::Array, np::Arra print(X_train_feat_argsort, { IDX_INSPECT, IDX_INSPECT + IDX_INSPECT_OFFSET }); #endif - const np::Array X_test_feat_argsort = state_saver("Precalculating testing set argsort (" LABEL ")", "X_test_feat_argsort_" LABEL, - FORCE_REDO, SAVE_STATE, OUT_DIR, argsort_2d, X_test_feat); + // const np::Array X_test_feat_argsort = state_saver("Precalculating testing set argsort (" LABEL ")", preproc_gaps[0], "X_test_feat_argsort_" LABEL, + // FORCE_REDO, SAVE_STATE, OUT_DIR, argsort_2d, X_test_feat); #if __DEBUG - print("X_test_feat_argsort"); - print(X_test_feat_argsort.shape); - print(X_test_feat_argsort, { IDX_INSPECT, IDX_INSPECT + IDX_INSPECT_OFFSET }); + // printf("X_test_feat_argsort\n"); + // print(X_test_feat_argsort.shape); + // print(X_test_feat_argsort, { IDX_INSPECT, IDX_INSPECT + IDX_INSPECT_OFFSET }); #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 }; } -void train(const np::Array& X_train_feat, const np::Array& X_train_feat_argsort, const np::Array& y_train) { - printf("\n| %-49s | %-18s | %-29s |\n", "Training", "Time spent (ns)", "Formatted time spent"); - printf("|%s|%s|%s|\n", S(51), S(20), S(31)); +std::array, 2>, TS.size()> train(const np::Array& X_train_feat, const np::Array& X_train_feat_argsort, const np::Array& y_train) noexcept { + const std::chrono::system_clock::time_point training_timestamp = perf_counter_ns(); + const std::array training_gaps = { 26, -18, 29 }; + header({ "Training", "Time spent (ns)", "Formatted time spent" }, training_gaps); + std::array, 2>, TS.size()> models; + + size_t i = 0; for (const size_t T : TS) { char title[BUFFER_SIZE] = { 0 }; char alphas_title[BUFFER_SIZE] = { 0 }; char final_classifiers_title[BUFFER_SIZE] = { 0 }; - sprintf(title, "ViolaJones T = %-4lu (%s)", T, LABEL); - sprintf(alphas_title, "alphas_%lu_%s", T, LABEL); - sprintf(final_classifiers_title, "final_classifiers_%lu_%s", T, LABEL); + snprintf(title, BUFFER_SIZE, "ViolaJones T = %-4lu (%s)", T, LABEL); + snprintf(alphas_title, BUFFER_SIZE, "alphas_%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(title, { alphas_title, final_classifiers_title }, -#else - state_saver(title, { alphas_title, final_classifiers_title }, -#endif + const auto [ alphas, final_classifiers ] = state_saver(title, training_gaps[0], { alphas_title, final_classifiers_title }, FORCE_REDO, SAVE_STATE, MODEL_DIR, train_viola_jones, T, X_train_feat, X_train_feat_argsort, y_train); #if __DEBUG print("alphas"); @@ -137,31 +141,32 @@ void train(const np::Array& X_train_feat, const np::Array& X_ print("final_classifiers"); print(final_classifiers); #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& X_train_feat, const np::Array& y_train, const np::Array& X_test_feat, const np::Array& 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)"); - printf("|%s|%s|%s|%s|%s|\n", S(28), S(21), S(31), S(21), S(31)); - - constexpr const size_t NT = sizeof(TS) / sizeof(size_t); - std::array, NT> results; +void testing_and_evaluating(const std::array, 2>, TS.size()>& models, const np::Array& X_train_feat, const np::Array& y_train, const np::Array& X_test_feat, const np::Array& y_test) { + const std::array testing_gaps = { 26, -19, 24, -19, 24 }; + header({ "Testing", "Time spent (ns) (E)", "Formatted time spent (E)", "Time spent (ns) (T)", "Formatted time spent (T)" }, testing_gaps); + std::array, TS.size()> results; 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 alphas_title[BUFFER_SIZE] = { 0 }; - 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 alphas = load(alphas_title); - const np::Array final_classifiers = load(final_classifiers_title); + snprintf(title, BUFFER_SIZE, "ViolaJones T = %-4i (%s)", TS[i], LABEL); std::chrono::system_clock::time_point start = perf_counter_ns(); const np::Array y_pred_train = classify_viola_jones(alphas, final_classifiers, X_train_feat); 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_f1 = f1_score(y_train, y_pred_train); float64_t e_FN, e_FP; @@ -170,48 +175,53 @@ void testing_and_evaluating(const np::Array& X_train_feat, const np::Ar start = perf_counter_ns(); const np::Array y_pred_test = classify_viola_jones(alphas, final_classifiers, X_test_feat); 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_f1 = f1_score(y_test, y_pred_test); float64_t t_FN, t_FP; 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 }; - 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"); - 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)); + const std::array evaluating_gaps = { 19, -7, -6, -6, -6, -7, -6, -6, -6 }; + header({ "Evaluating", "ACC (E)", "F1 (E)", "FN (E)", "FP (E)", "ACC (T)", "F1 (T)", "FN (T)", "FP (T)"}, evaluating_gaps); i = 0; for (const size_t T : TS) { 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++]; - 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) { - printf("\n| %-37s | %-10s | %-18s | %-29s |\n", "Unit testing", "Test state", "Time spent (ns)", "Formatted time spent"); - printf("|%s|%s|%s|%s|\n", S(39), S(12), S(20), S(31)); + const std::chrono::system_clock::time_point unit_timestamp = perf_counter_ns(); + const std::array 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 tmp_title[BUFFER_SIZE / 2] = { 0 }; char file_cpu[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; - 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; const std::chrono::system_clock::time_point start = perf_counter_ns(); const bool state = fnc(); const long long time_spent = duration_ns(perf_counter_ns() - start); 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; } 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" }) { @@ -275,32 +285,38 @@ void unit_test(void) { } } - const long long time_spent = duration_ns(perf_counter_ns() - fnc_s); - sprintf(title, "%ld/%ld", n_success, n_total); + const long long time_spent = duration_ns(perf_counter_ns() - unit_timestamp); + snprintf(title, BUFFER_SIZE, "%ld/%ld", n_success, n_total); - printf("|%s|%s|%s|%s|\n", S(39), S(12), S(20), S(31)); - printf("| %-37s | %10s | %18s | %-29s |\n", "Unit testing summary", title, thousand_sep(time_spent).c_str(), format_time_ns(time_spent).c_str()); + formatted_line(unit_gaps, "├", "┼", "─", "┤"); + 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(){ setlocale(LC_NUMERIC, ""); // Allow proper number display - printf("| %-49s | %-18s | %-29s |\n", "Unit testing", "Time spent (ns)", "Formatted time spent"); - printf("|%s|%s|%s|\n", S(51), S(20), S(31)); + const std::chrono::system_clock::time_point unit_timestamp = perf_counter_ns(); + const std::array unit_gaps = { 27, -18, 29 }; + header({ "Unit testing", "Time spent (ns)", "Formatted time spent" }, unit_gaps); #if GPU_BOOSTED - benchmark_function_void("Testing GPU capabilities 1D", test_working, 3 + (1<<29)); - benchmark_function_void("Testing GPU capabilities 2D", test_working_2d, 3 + (1<<15), 2 + (1<<14)); - 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 1D", unit_gaps[0], test_working, 50000); + benchmark_function_void("Testing GPU capabilities 2D", unit_gaps[0], test_working_2d, 200, 500); + benchmark_function_void("Testing GPU capabilities 3D", unit_gaps[0], test_working_3d, 30, 40, 500); #endif - benchmark_function_void("Testing format_time", format_time_test); - benchmark_function_void("Testing format_time_ns", format_time_ns_test); - benchmark_function_void("Testing format_byte_size", format_byte_size_test); - benchmark_function_void("Testing thousand_sep", thousand_sep_test); - printf("\n"); + benchmark_function_void("Testing format_time", unit_gaps[0], format_time_test); + benchmark_function_void("Testing format_time_ns", unit_gaps[0], format_time_ns_test); + benchmark_function_void("Testing format_byte_size", unit_gaps[0], format_byte_size_test); + benchmark_function_void("Testing thousand_sep", unit_gaps[0], thousand_sep_test); + 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(); - train(X_train_feat, X_train_feat_argsort, y_train); - testing_and_evaluating(X_train_feat, y_train, X_test_feat, y_test); + const std::array, 2>, TS.size()> models = train(X_train_feat, X_train_feat_argsort, y_train); + testing_and_evaluating(models, X_train_feat, y_train, X_test_feat, y_test); unit_test(); + return EXIT_SUCCESS; } diff --git a/cpp/toolbox.hpp b/cpp/toolbox.hpp index 7b12041..004d7ad 100644 --- a/cpp/toolbox.hpp +++ b/cpp/toolbox.hpp @@ -1,7 +1,41 @@ #pragma once #include -#include #include +#include + +template +constexpr void formatted_row(const std::array& gaps, const std::array& 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 +constexpr void formatted_line(const std::array& 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 +constexpr void header(const std::array& titles, const std::array& gaps) noexcept { + formatted_line(gaps, "┌", "┬", "─", "┐"); + formatted_row(gaps, titles); + formatted_line(gaps, "├", "┼", "─", "┤"); +} + +template +constexpr inline void footer(const std::array& gaps) noexcept { + formatted_line(gaps, "└", "┴", "─", "┘"); +} #define duration_ns(a) std::chrono::duration_cast(a).count() #define perf_counter_ns() std::chrono::high_resolution_clock::now() diff --git a/python/config.py b/python/config.py index 2f8b871..5c0f9a2 100644 --- a/python/config.py +++ b/python/config.py @@ -1,44 +1,47 @@ +from typing import Final import numpy as np -DATA_DIR = "../data" -OUT_DIR = "./out" -MODEL_DIR = "./models" +DATA_DIR: Final = '../data' +OUT_DIR: Final = './out' +MODEL_DIR: Final = './models' -NB_THREADS = 1024 -NB_THREADS_2D = (32, 32) -NB_THREADS_3D = (16, 16, 4) -M = int(np.log2(NB_THREADS_2D[1])) +NB_THREADS: Final = 1024 +NB_THREADS_2D: Final = (32, 32) +NB_THREADS_3D: Final = (16, 16, 4) +M: Final = int(np.log2(NB_THREADS_2D[1])) # Save state to avoid recalculation on restart -SAVE_STATE = True +SAVE_STATE: Final = True # Redo the state even if it's already saved -FORCE_REDO = False +FORCE_REDO: Final = False # 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) -GPU_BOOSTED = True +GPU_BOOSTED: Final = True # Depending on what you set, the output label will be as follow : -# | COMPILE_WITH_C | GPU_BOOSTED | LABEL | -# |----------------|-------------|-------| -# | True | True | GPU | -# | True | False | CPU | -# | False | True | PGPU | -# | False | False | PY | +# ┌────────────────┬─────────────┬───────┐ +# │ COMPILE_WITH_C │ GPU_BOOSTED │ LABEL │ +# ├────────────────┼─────────────┼───────┤ +# │ True │ True │ GPU │ +# │ True │ False │ CPU │ +# │ False │ True │ PGPU │ +# │ False │ False │ PY │ +# └────────────────┴─────────────┴───────┘ # Number of weak classifiers -# TS = [1] -# TS = [1, 5, 10] -TS = [1, 5, 10, 25, 50] -# TS = [1, 5, 10, 25, 50, 100, 200] -# TS = [1, 5, 10, 25, 50, 100, 200, 300] -# TS = [1, 5, 10, 25, 50, 100, 200, 300, 400, 500, 1000] +# TS: Final = [1] +# TS: Final = [1, 5, 10] +TS: Final = [1, 5, 10, 25, 50] +# TS: Final = [1, 5, 10, 25, 50, 100, 200] +# TS: Final = [1, 5, 10, 25, 50, 100, 200, 300] +# TS: Final = [1, 5, 10, 25, 50, 100, 200, 300, 400, 500, 1000] # Enable verbose output (for debugging purposes) -__DEBUG = False +__DEBUG: Final = False # Debugging options if __DEBUG: - IDX_INSPECT = 4548 - IDX_INSPECT_OFFSET = 100 + IDX_INSPECT: Final = 4548 + IDX_INSPECT_OFFSET: Final = 100 np.seterr(all = 'raise') # Debug option (image width * log_10(length) + extra characters) np.set_printoptions(linewidth = 19 * 6 + 3) diff --git a/python/projet.py b/python/projet.py index 33d96a3..ffb07c2 100644 --- a/python/projet.py +++ b/python/projet.py @@ -4,6 +4,7 @@ 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_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.feature_selection import SelectPercentile, f_classif 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"]: 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) if __DEBUG: @@ -57,16 +60,17 @@ def preprocessing() -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]: print(y_test.shape) 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: print("feats") print(feats.shape) 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) - 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) 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[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) - 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) 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_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) if __DEBUG: print("X_train_feat_argsort") print(X_train_feat_argsort.shape) 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}", 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[IDX_INSPECT, : IDX_INSPECT_OFFSET]) 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 -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. Args: 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. + + 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: - alphas, final_classifiers = state_saver(f"ViolaJones T = {T:<3} ({label})", [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) + alphas, final_classifiers = state_saver(f'ViolaJones T = {T:<4} ({label})', training_gaps[0], + [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: print("alphas") print(alphas) 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. Args: + models (List[np.ndarray]): List of trained models. X_train_feat (np.ndarray): Training features. y_train (np.ndarray): Training labels. X_test_feat (np.ndarray): Testing features. 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 = [] - for T in TS: - (alphas, final_classifiers) = picke_multi_loader([f"alphas_{T}_{label}", f"final_classifiers_{T}_{label}"]) + testing_gaps = [26, -19, 24, -19, 24] + header(['Testing', 'Time spent (ns) (E)', 'Formatted time spent (E)', 'Time spent (ns) (T)', 'Formatted time spent (T)'], testing_gaps) + performances = [] + total_train_timestamp = 0 + total_test_timestamp = 0 + for T, (alphas, final_classifiers) in zip(TS, models): s = perf_counter_ns() y_pred_train = classify_viola_jones(alphas, final_classifiers, X_train_feat) t_pred_train = perf_counter_ns() - s + total_train_timestamp += t_pred_train e_acc = accuracy_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) @@ -172,36 +198,48 @@ def testing_and_evaluating(X_train_feat: np.ndarray, y_train: np.ndarray, X_test s = perf_counter_ns() y_pred_test = classify_viola_jones(alphas, final_classifiers, X_test_feat) t_pred_test = perf_counter_ns() - s + total_test_timestamp += t_pred_test t_acc = accuracy_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) - 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 = " | ") - print(f"{t_pred_train:>19,} | {format_time_ns(t_pred_train):<29}", end = " | ") - print(f"{t_pred_test:>19,} | {format_time_ns(t_pred_test):<29} |") + formatted_row(testing_gaps, [f"{'ViolaJones T = ' + str(T):<19} {'(' + label + ')':<6}", f'{t_pred_train:,}', + format_time_ns(t_pred_train), f'{t_pred_test:,}', format_time_ns(t_pred_test)]) - print(f"\n| {'Evaluating':<19} | ACC (E) | F1 (E) | FN (E) | FP (E) | ACC (T) | F1 (T) | FN (T) | FP (T) | ") - print(f"|{'-'*21}|{'-'*9}|{'-'*8}|{'-'*8}|{'-'*8}|{'-'*9}|{'-'*8}|{'-'*8}|{'-'*8}|") + formatted_line(testing_gaps, '├', '┼', '─', '┤') + 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): - print(f"| {'ViolaJones T = ' + str(T):<19} | {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,} |") + evaluating_gaps = [19, 7, 6, 6, 6, 7, 6, 6, 6] + header(['Evaluating', 'ACC (E)', 'F1 (E)', 'FN (E)', 'FP (E)', 'ACC (T)', 'F1 (T)', 'FN (T)', 'FP (T)'], evaluating_gaps) + + 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: - print(f"| {'Unit testing':<49} | {'Time spent (ns)':<18} | {'Formatted time spent':<29} |") - print(f"|{'-'*51}|{'-'*20}|{'-'*31}|") - benchmark_function("Testing format_time_ns", format_time_ns_test) - print() + unit_timestamp = perf_counter_ns() + unit_gaps = [27, -18, 29] + header(['Unit testing', 'Time spent (ns)', 'Formatted time spent'], unit_gaps) + 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() - 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) # indices = picke_multi_loader(["indices"], OUT_DIR)[0] # 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) if __name__ == "__main__": diff --git a/python/toolbox.py b/python/toolbox.py index be60e3f..79c2b9e 100644 --- a/python/toolbox.py +++ b/python/toolbox.py @@ -2,12 +2,35 @@ from typing import Any, Callable, List, Union, Final from time import perf_counter_ns from numba import njit import numpy as np +from sys import stderr import pickle import os from config import MODEL_DIR, OUT_DIR from decorators import njit 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) @njit('str(uint64)') 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) 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. Args: @@ -63,14 +86,15 @@ def benchmark_function(step_name: str, fnc: Callable) -> Any: Returns: Any: Result of the function. """ - print(f"{step_name}...", end = "\r") + print(f'{step_name}...', file = stderr, end = '\r') s = perf_counter_ns() b = fnc() 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 -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. Args: @@ -85,18 +109,18 @@ def state_saver(step_name: str, filename: Union[str, List[str]], fnc, force_redo """ if isinstance(filename, str): 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: - print(f"Saving results of {step_name}", end = '\r') 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) - print(' ' * 100, end = '\r') + print(' ' * 100, file = stderr, end = '\r') return b else: - print(f"Loading results of {step_name}", end = '\r') 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) - 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 elif isinstance(filename, list): abs = False @@ -105,22 +129,22 @@ def state_saver(step_name: str, filename: Union[str, List[str]], fnc, force_redo abs = True break if abs or force_redo: - b = benchmark_function(step_name, fnc) + b = benchmark_function(step_name, column_width, fnc) 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): with open(f"{save_dir}/{fnI}.pkl", 'wb') as f: pickle.dump(bi, f) - print(' ' * 100, end = '\r') + print(' ' * 100, file = stderr, end = '\r') 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 = [] - print(f"Loading results of {step_name}", end = '\r') + print(f'Loading results of {step_name}', file = stderr, end = '\r') for fn in filename: with open(f"{save_dir}/{fn}.pkl", "rb") as f: b.append(pickle.load(f)) - print(' ' * 100, end = '\r') + print(' ' * 100, file = stderr, end = '\r') return b else: assert False, f"Incompatible filename type = {type(filename)}"