1- #include < algorithm>
1+
2+ #ifndef WIN32_LEAN_AND_MEAN
3+ #define WIN32_LEAN_AND_MEAN
4+ #endif
5+ #include < windows.h>
6+ #include < psapi.h>
7+ #pragma comment(lib, "psapi.lib")
8+ #include < crtdbg.h>
9+ #include < algorithm>
10+ #include < chrono>
11+ #include < cmath>
212#include < filesystem>
313#include < iomanip>
414#include < numeric>
717
818#include " build.hpp"
919
20+ class MemoryLogger {
21+ private:
22+ std::chrono::steady_clock::time_point start_time;
23+ size_t peak_memory = 0 ;
24+ size_t initial_memory = 0 ;
25+
26+ size_t getProcessMemory () {
27+ HANDLE hProcess = GetCurrentProcess ();
28+ PROCESS_MEMORY_COUNTERS pmc;
29+ pmc.cb = sizeof (PROCESS_MEMORY_COUNTERS );
30+
31+ if (GetProcessMemoryInfo (hProcess, &pmc, sizeof (pmc))) {
32+ return pmc.WorkingSetSize / (1024 * 1024 );
33+ }
34+ return 0 ;
35+ }
36+
37+ public:
38+ MemoryLogger () {
39+ start_time = std::chrono::steady_clock::now ();
40+ initial_memory = getProcessMemory ();
41+ log (" START" );
42+ }
43+
44+ void log (const char * stage) {
45+ auto now = std::chrono::steady_clock::now ();
46+ auto elapsed =
47+ std::chrono::duration_cast<std::chrono::seconds>(now - start_time)
48+ .count ();
49+
50+ size_t current = getProcessMemory ();
51+ if (current > peak_memory) peak_memory = current;
52+
53+ std::cout << " [" << std::setw (4 ) << elapsed << " s] " << std::setw (30 )
54+ << stage << " | "
55+ << " PROCESS MEM: " << std::setw (6 ) << current << " MB"
56+ << " (PEAK: " << std::setw (6 ) << peak_memory << " MB)"
57+ << " (DELTA: " << std::setw (4 ) << (current - initial_memory)
58+ << " MB)\n " ;
59+ }
60+
61+ ~MemoryLogger () {
62+ log (" END" );
63+ std::cout << " ====================================\n " ;
64+ std::cout << " PEAK PROCESS MEMORY: " << peak_memory << " MB\n " ;
65+ std::cout << " INITIAL PROCESS MEMORY: " << initial_memory << " MB\n " ;
66+ std::cout << " FINAL PROCESS MEMORY: " << getProcessMemory () << " MB\n " ;
67+ if (getProcessMemory () > initial_memory + 10 ) {
68+ std::cout << " WARNING: Process memory growth! (+"
69+ << (getProcessMemory () - initial_memory) << " MB)\n " ;
70+ } else {
71+ std::cout << " OK: No significant process memory growth\n " ;
72+ }
73+ }
74+ };
75+
76+ MemoryLogger g_memLogger;
77+
78+ #define LOG_MEM (stage ) g_memLogger.log(stage)
79+
1080namespace fs = std::filesystem;
1181using namespace it_lab_ai ;
1282
1383int main (int argc, char * argv[]) {
84+ LOG_MEM (" Program start" );
85+
1486 std::string model_name = " alexnet_mnist" ;
1587 RuntimeOptions options;
1688 size_t num_photo = 1000 ;
89+ size_t batch_size = 32 ;
1790
1891 for (int i = 1 ; i < argc; ++i) {
1992 if (std::string (argv[i]) == " --model" && i + 1 < argc) {
2093 model_name = argv[++i];
94+ } else if (std::string (argv[i]) == " --batch" && i + 1 < argc) {
95+ batch_size = std::stoi (argv[++i]);
2196 } else if (std::string (argv[i]) == " --onednn" ) {
2297 options.backend = Backend::kOneDnn ;
2398 if (options.par_backend != ParBackend::kSeq ) {
@@ -64,6 +139,8 @@ int main(int argc, char* argv[]) {
64139 }
65140 }
66141
142+ LOG_MEM (" After args parsing" );
143+
67144 std::string dataset_path;
68145 if (model_name == " alexnet_mnist" ) {
69146 dataset_path = MNIST_PATH ;
@@ -75,8 +152,10 @@ int main(int argc, char* argv[]) {
75152 std::vector<int > input_shape = get_input_shape_from_json (json_path);
76153
77154 std::cout << ' \n ' ;
78-
155+ int batch_count = 0 ;
79156 if (model_name == " alexnet_mnist" ) {
157+ LOG_MEM (" MNIST start" );
158+
80159 std::vector<size_t > counts = {979 , 1134 , 1031 , 1009 , 981 ,
81160 891 , 957 , 1027 , 973 , 1008 };
82161 int stat = 0 ;
@@ -144,15 +223,20 @@ int main(int argc, char* argv[]) {
144223 (static_cast <double >(stat) / static_cast <double >(sum + 10 )) * 100 ;
145224 std::cout << " Stat: " << std::fixed << std::setprecision (2 ) << percentage
146225 << " %" << ' \n ' ;
226+
227+ LOG_MEM (" MNIST end" );
147228 return 0 ;
148229 }
149230
231+ LOG_MEM (" ImageNet start" );
232+
150233 std::vector<size_t > counts (1000 , 0 );
151234 std::vector<std::string> image_paths;
152235 std::vector<int > true_labels;
153236 std::vector<float > all_image_data;
154237 size_t total_images = 0 ;
155238
239+ LOG_MEM (" Counting classes" );
156240 for (int class_id = 0 ; class_id < 1000 ; ++class_id) {
157241 std::ostringstream folder_oss;
158242 folder_oss << std::setw (5 ) << std::setfill (' 0' ) << class_id;
@@ -176,13 +260,16 @@ int main(int argc, char* argv[]) {
176260 int height = input_shape[2 ];
177261 int width = input_shape[3 ];
178262 size_t image_size = channels * height * width;
263+ size_t output_classes = 1000 ;
179264
265+ LOG_MEM (" Reserving memory" );
180266 all_image_data.reserve (num_photo * image_size);
181267 image_paths.reserve (num_photo);
182268 true_labels.reserve (num_photo);
183269
184270 total_images = 0 ;
185271
272+ LOG_MEM (" Loading images start" );
186273 for (int class_id = 0 ; class_id < 1000 ; ++class_id) {
187274 size_t need_from_class = images_per_class_base;
188275 if (remaining > 0 ) {
@@ -230,72 +317,148 @@ int main(int argc, char* argv[]) {
230317 std::cout << " Warning: Class " << class_id << " has only " << taken
231318 << " images (needed " << need_from_class << " )" << ' \n ' ;
232319 }
320+
321+ if (class_id % 100 == 0 && class_id > 0 ) {
322+ char buf[50 ];
323+ sprintf (buf, " Class %d" , class_id);
324+ LOG_MEM (buf);
325+ }
233326 }
234327
328+ LOG_MEM (" Images loaded" );
329+
235330 if (total_images != num_photo) {
236331 std::cout << " Warning: Requested " << num_photo << " images but loaded "
237332 << total_images << " due to insufficient data" << ' \n ' ;
238333 num_photo = total_images;
239334 }
240335
241- it_lab_ai::Shape input_shape_imagenet (
242- {num_photo, static_cast <size_t >(channels), static_cast <size_t >(height),
243- static_cast <size_t >(width)});
244- it_lab_ai::Tensor input =
245- it_lab_ai::make_tensor (all_image_data, input_shape_imagenet);
246-
247- size_t output_classes = 1000 ;
248- it_lab_ai::Shape output_shape ({num_photo, output_classes});
249- it_lab_ai::Tensor output =
250- it_lab_ai::Tensor (output_shape, it_lab_ai::Type::kFloat );
251-
252- Graph graph;
253- build_graph (graph, input, output, json_path, options, false );
254- graph.inference (options);
255- print_time_stats (graph);
256-
257- std::vector<std::vector<float >> processed_outputs;
258- const std::vector<float >& raw_output = *output.as <float >();
259-
260- for (size_t i = 0 ; i < num_photo; ++i) {
261- std::vector<float > single_output (
262- raw_output.begin () + i * output_classes,
263- raw_output.begin () + (i + 1 ) * output_classes);
264- std::vector<float > processed_output =
265- process_model_output (single_output, model_name);
266- processed_outputs.push_back (processed_output);
267- }
268-
269336 int correct_predictions_top1 = 0 ;
270337 int correct_predictions_top5 = 0 ;
271- for (size_t i = 0 ; i < processed_outputs.size (); ++i) {
272- int true_label = true_labels[i];
273- const std::vector<float >& probabilities = processed_outputs[i];
274-
275- std::vector<size_t > indices (probabilities.size ());
276- std::iota (indices.begin (), indices.end (), 0 );
277- std::sort (indices.begin (), indices.end (), [&](size_t a, size_t b) {
278- return probabilities[a] > probabilities[b];
279- });
280-
281- size_t predicted_class_top1 = indices[0 ];
282- if (predicted_class_top1 == static_cast <size_t >(true_label)) {
283- correct_predictions_top1++;
284- }
285338
286- bool found_in_top5 = false ;
287- for (int top_k = 0 ; top_k < std::min (5 , static_cast <int >(indices.size ()));
288- ++top_k) {
289- if (indices[top_k] == static_cast <size_t >(true_label)) {
290- found_in_top5 = true ;
291- break ;
339+ LOG_MEM (" Starting batch processing" );
340+ auto total_start_time = std::chrono::high_resolution_clock::now ();
341+ int total_inference_time = 0 ;
342+
343+ for (size_t batch_start = 0 ; batch_start < num_photo;
344+ batch_start += batch_size) {
345+ size_t batch_end = std::min (batch_start + batch_size, num_photo);
346+ size_t current_batch_size = batch_end - batch_start;
347+
348+ char batch_log[100 ];
349+ sprintf (batch_log, " Batch %zu/%zu (size %zu)" , batch_start / batch_size + 1 ,
350+ (num_photo + batch_size - 1 ) / batch_size, current_batch_size);
351+ LOG_MEM (batch_log);
352+
353+ std::vector<float > batch_data;
354+ batch_data.reserve (current_batch_size * image_size);
355+
356+ size_t batch_offset = batch_start * image_size;
357+ batch_data.insert (batch_data.end (), all_image_data.begin () + batch_offset,
358+ all_image_data.begin () + batch_offset +
359+ current_batch_size * image_size);
360+
361+ it_lab_ai::Shape batch_input_shape (
362+ {current_batch_size, static_cast <size_t >(channels),
363+ static_cast <size_t >(height), static_cast <size_t >(width)});
364+ it_lab_ai::Tensor batch_input = make_tensor (batch_data, batch_input_shape);
365+
366+ it_lab_ai::Shape batch_output_shape ({current_batch_size, output_classes});
367+ it_lab_ai::Tensor batch_output (batch_output_shape, it_lab_ai::Type::kFloat );
368+
369+ Graph graph;
370+ build_graph (graph, batch_input, batch_output, json_path, options, false );
371+
372+ LOG_MEM (" Batch inference" );
373+ // auto batch_start_time =
374+ // std::chrono::high_resolution_clock::now();
375+ graph.inference (options);
376+ total_inference_time += print_time_stats (graph);
377+ // auto batch_end_time = std::chrono::high_resolution_clock::now();
378+ // int batch_time =
379+ // static_cast<int>(std::chrono::duration_cast<std::chrono::milliseconds>(
380+ // batch_end_time - batch_start_time)
381+ // .count()); // ← Добавлен static_cast
382+ // total_inference_time += batch_time;
383+ // batch_count++;
384+
385+ // #ifdef ENABLE_STATISTIC_TIME
386+ // std::vector<int> elps_time = graph.getTime();
387+ // int batch_time = std::accumulate(elps_time.begin(),
388+ // elps_time.end(), 0); total_inference_time += batch_time;
389+ // batch_count++;
390+ //
391+ // char time_log[100];
392+ // sprintf(time_log, "Batch %d time: %d ms", batch_count,
393+ // batch_time); LOG_MEM(time_log);
394+ // #endif
395+
396+ const std::vector<float >& raw_batch_output = *batch_output.as <float >();
397+
398+ for (size_t i = 0 ; i < current_batch_size; ++i) {
399+ size_t global_idx = batch_start + i;
400+
401+ std::vector<float > single_output (
402+ raw_batch_output.begin () + i * output_classes,
403+ raw_batch_output.begin () + (i + 1 ) * output_classes);
404+
405+ float max_val =
406+ *std::max_element (single_output.begin (), single_output.end ());
407+ float sum = 0 .0f ;
408+ for (float & val : single_output) {
409+ val = exp (val - max_val);
410+ sum += val;
411+ }
412+ for (float & val : single_output) {
413+ val /= sum;
414+ }
415+
416+ std::vector<size_t > indices (single_output.size ());
417+ std::iota (indices.begin (), indices.end (), 0 );
418+ std::sort (indices.begin (), indices.end (), [&](size_t a, size_t b) {
419+ return single_output[a] > single_output[b];
420+ });
421+
422+ if (indices[0 ] == static_cast <size_t >(true_labels[global_idx])) {
423+ correct_predictions_top1++;
424+ }
425+
426+ for (int top_k = 0 ; top_k < std::min (5 , static_cast <int >(indices.size ()));
427+ ++top_k) {
428+ if (indices[top_k] == static_cast <size_t >(true_labels[global_idx])) {
429+ correct_predictions_top5++;
430+ break ;
431+ }
292432 }
293433 }
294- if (found_in_top5) {
295- correct_predictions_top5++ ;
296- }
434+
435+ batch_data. clear () ;
436+ batch_data. shrink_to_fit ();
297437 }
298438
439+ auto total_end_time = std::chrono::high_resolution_clock::now ();
440+ int total_time =
441+ static_cast <int >(std::chrono::duration_cast<std::chrono::milliseconds>(
442+ total_end_time - total_start_time)
443+ .count ());
444+
445+ std::cout << " \n !INFERENCE TIME INFO START!" << ' \n ' ;
446+ std::cout << " Total inference time (sum of batches): " << total_inference_time
447+ << " ms\n " ;
448+ std::cout << " Total wall-clock time for all batches: " << total_time
449+ << " ms\n " ;
450+ std::cout << " Number of batches: " << batch_count << ' \n ' ;
451+ std::cout << " Average time per batch: "
452+ << (batch_count > 0 ? total_inference_time / batch_count : 0 )
453+ << " ms\n " ;
454+ std::cout << " !INFERENCE TIME INFO END!" << ' \n ' ;
455+ /* std::cout << "\n!INFERENCE TIME INFO START!" << '\n';
456+ std::cout << "Total inference time for all batches: " << total_inference_time
457+ << " ms\n";
458+ std::cout << "Number of batches: " << batch_count << '\n';
459+ std::cout << "!INFERENCE TIME INFO END!" << '\n';
460+ LOG_MEM("All batches processed");*/
461+
299462 double final_accuracy_top1 =
300463 (static_cast <double >(correct_predictions_top1) / num_photo) * 100 ;
301464 double final_accuracy_top5 =
@@ -305,6 +468,7 @@ int main(int argc, char* argv[]) {
305468 std::cout << " Model: " << model_name << ' \n ' ;
306469 std::cout << " Dataset: " << dataset_path << ' \n ' ;
307470 std::cout << " Total images: " << num_photo << ' \n ' ;
471+ std::cout << " Batch size: " << batch_size << ' \n ' ;
308472 std::cout << " Correct predictions (Top-1): " << correct_predictions_top1
309473 << ' \n ' ;
310474 std::cout << " Correct predictions (Top-5): " << correct_predictions_top5
@@ -314,5 +478,13 @@ int main(int argc, char* argv[]) {
314478 std::cout << " Top-5 Accuracy: " << std::fixed << std::setprecision (2 )
315479 << final_accuracy_top5 << " %" << ' \n ' ;
316480
481+ all_image_data.clear ();
482+ all_image_data.shrink_to_fit ();
483+ image_paths.clear ();
484+ image_paths.shrink_to_fit ();
485+ true_labels.clear ();
486+ true_labels.shrink_to_fit ();
487+
488+ LOG_MEM (" Program end" );
317489 return 0 ;
318490}
0 commit comments