#pragma once #include <filesystem> namespace fs = std::filesystem; #include "data.hpp" #include "toolbox.hpp" //#include "config.hpp" template <typename T> bool unit_test_cpu_vs_gpu(const np::Array<T>& cpu, const np::Array<T>& gpu) noexcept { if (cpu.shape != gpu.shape) { #if __DEBUG fprintf(stderr, "Inequal shape !\n"); #endif return false; } size_t eq = 0; const size_t length = np::prod(cpu.shape); for (size_t i = 0; i < length; ++i) if (cpu[i] == gpu[i]) ++eq; #if __DEBUG if (eq != length) printf("Incorrect results, Number of equalities : %s/%s <=> %.2f%% !\n", thousand_sep(eq).c_str(), thousand_sep(length).c_str(), static_cast<float64_t>(eq) / static_cast<float64_t>(length) * 100.0); #endif return eq == length; } template <typename T> bool unit_test_argsort_2d(const np::Array<T>& a, const np::Array<uint16_t>& indices) noexcept { if (a.shape != indices.shape) { #if __DEBUG fprintf(stderr, "Inequal shape !\n"); #endif return false; } size_t correct = a.shape[0]; // First elements are always correctly sorted const size_t total = np::prod(a.shape); for(size_t i = 0; i < total; i += a.shape[1]) for(size_t j = 0; j < a.shape[1] - 1; ++j){ const size_t k = i + j; if(a[i + indices[k]] <= a[i + indices[k + 1]]) ++correct; } #if __DEBUG if (correct != total) printf("Incorrect results, Number of equalities : %s/%s <=> %.2f%% !\n", thousand_sep(correct).c_str(), thousand_sep(total).c_str(), static_cast<float64_t>(correct) / static_cast<float64_t>(total) * 100.0); #endif return correct == total; } template <typename T, typename F, typename... Args> T benchmark_function(const char* step_name, 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 #endif const std::chrono::system_clock::time_point start = perf_counter_ns(); const T res = fnc(std::forward<Args>(args)...); const long long timespent = duration_ns(perf_counter_ns() - start); printf("| %-49s | %18s | %-29s |\n", step_name, thousand_sep(timespent).c_str(), format_time_ns(timespent).c_str()); return res; } template <typename F, typename... Args> void benchmark_function_void(const char* step_name, 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 #endif const std::chrono::system_clock::time_point start = perf_counter_ns(); fnc(std::forward<Args>(args)...); const long long timespent = duration_ns(perf_counter_ns() - start); printf("| %-49s | %18s | %-29s |\n", step_name, thousand_sep(timespent).c_str(), format_time_ns(timespent).c_str()); } 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 { char filepath[BUFFER_SIZE] = { 0 }; sprintf(filepath, "%s/%s.bin", out_dir, filename); np::Array<T> bin; if (!fs::exists(filepath) || force_redo) { bin = std::move(benchmark_function<np::Array<T>>(step_name, fnc, std::forward<Args>(args)...)); if(save_state){ #if __DEBUG == false printf("Saving results of %s\r", step_name); fflush(stdout); #endif save<T>(bin, filepath); #if __DEBUG == false printf("%*c\r", 100, ' '); fflush(stdout); #endif } } else { #if __DEBUG == false printf("Loading results of %s\r", step_name); fflush(stdout); #endif bin = std::move(load<T>(filepath)); printf("| %-49s | %18s | %-29s |\n", step_name, "None", "loaded saved state"); } return bin; } 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 { char filepath[BUFFER_SIZE] = { 0 }; bool abs = false; for (const char* filename : filenames){ sprintf(filepath, "%s/%s.bin", out_dir, filename); if (!fs::exists(filepath)) { abs = true; break; } } std::array<np::Array<T>, N> bin; if (abs || force_redo) { bin = std::move(benchmark_function<std::array<np::Array<T>, N>>(step_name, fnc, std::forward<Args>(args)...)); if (save_state){ #if __DEBUG == false printf("Saving results of %s\r", step_name); fflush(stdout); #endif size_t i = 0; for (const char* filename : filenames){ sprintf(filepath, "%s/%s.bin", out_dir, filename); save<T>(bin[i++], filepath); } #if __DEBUG == false printf("%*c\r", 100, ' '); fflush(stdout); #endif } } else { #if __DEBUG == false printf("Loading results of %s\r", step_name); fflush(stdout); #endif size_t i = 0; for (const char* filename : filenames){ sprintf(filepath, "%s/%s.bin", out_dir, filename); bin[i++] = std::move(load<T>(filepath)); } printf("| %-49s | %18s | %-29s |\n", step_name, "None", "loaded saved state"); } return bin; } np::Array<uint16_t> argsort_2d_cpu(const np::Array<int32_t>&) noexcept; np::Array<uint8_t> build_features(const uint16_t&, const uint16_t&) noexcept; np::Array<int> select_percentile(const np::Array<uint8_t>&, const np::Array<uint8_t>&) noexcept; np::Array<uint8_t> classify_viola_jones(const np::Array<float64_t>&, const np::Array<float64_t>&, const np::Array<int32_t>&) noexcept; np::Array<float64_t> init_weights(const np::Array<uint8_t>&) noexcept; std::tuple<int32_t, float64_t, np::Array<float64_t>> select_best(const np::Array<float64_t>&, const np::Array<float64_t>&, const np::Array<int32_t>&, const np::Array<uint8_t>&) noexcept; std::array<np::Array<float64_t>, 2> train_viola_jones(const size_t&, const np::Array<int32_t>&, const np::Array<uint16_t>&, const np::Array<uint8_t>&) noexcept; float64_t accuracy_score(const np::Array<uint8_t>&, const np::Array<uint8_t>&) noexcept; float64_t precision_score(const np::Array<uint8_t>&, const np::Array<uint8_t>&) noexcept; float64_t recall_score(const np::Array<uint8_t>&, const np::Array<uint8_t>&) noexcept; float64_t f1_score(const np::Array<uint8_t>&, const np::Array<uint8_t>&) noexcept; std::tuple<uint16_t, uint16_t, uint16_t, uint16_t> confusion_matrix(const np::Array<uint8_t>&, const np::Array<uint8_t>&) noexcept;