Skip to content

Commit 7ef42d3

Browse files
committed
Add raw CUDA Graph realization for optimization
1 parent f844949 commit 7ef42d3

1 file changed

Lines changed: 95 additions & 97 deletions

File tree

src/engine/server/NN/ModelManager.cpp

Lines changed: 95 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ float lambda = 0.95f; // GAE lambda
4444
float old_models_train = 0.2f; // Percent of old models
4545
int count_cached_old_models = 100; // old_models_train * ((float)count_bots / 2.f)
4646

47+
int warmup_index = 0;
48+
4749
ActorCritic ac_update;
4850
ActorCritic ac_work;
4951
std::shared_ptr<torch::optim::Adam> opt;
@@ -55,11 +57,11 @@ std::vector<int> input_to_model_id;
5557
bool graph_recorded = false;
5658

5759
// Tested CUDA Graphs - produce numerical instability
58-
//std::vector<torch::Tensor> graph_input_tensors;
59-
//std::vector<torch::Tensor> graph_output_tensors;
60-
//torch::Tensor graph_main_input_tensor, graph_main_output_tensor;
61-
//at::cuda::CUDAGraph graph;
62-
//at::cuda::CUDAStream graph_stream = at::cuda::getStreamFromPool();
60+
std::vector<torch::Tensor> graph_input_tensors;
61+
std::vector<torch::Tensor> graph_output_tensors;
62+
torch::Tensor graph_main_input_tensor, graph_main_output_tensor;
63+
at::cuda::CUDAGraph graph;
64+
at::cuda::CUDAStream graph_stream = at::cuda::getStreamFromPool();
6365

6466
VT states;
6567
VT actions;
@@ -120,8 +122,17 @@ ModelManager::ModelManager(bool is_training, std::string train_folder, size_t ba
120122
ac_update->Initialize(n_in, n_out, h_start, std_dev);
121123
ac_work->Initialize(n_in, n_out, h_start, std_dev);
122124

123-
//graph_main_input_tensor = torch::empty({(int)(count_bots - old_bots_indexes.size()), n_in}, torch::kCUDA);
124-
//graph_main_output_tensor = torch::empty({(int)(count_bots - old_bots_indexes.size()), n_out}, torch::kCUDA);
125+
graph_input_tensors.clear();
126+
graph_output_tensors.clear();
127+
for(size_t i = 0; i < old_bots_indexes.size(); i++)
128+
{
129+
torch::Tensor empty_in = torch::empty({1, n_in}, torch::kCUDA);
130+
graph_input_tensors.push_back(empty_in);
131+
torch::Tensor empty_out = torch::empty({1, ac_work->n_out}, torch::kCUDA);
132+
graph_output_tensors.push_back(empty_out);
133+
}
134+
graph_main_input_tensor = torch::empty({(int)(count_bots - old_bots_indexes.size()), n_in}, torch::kCUDA);
135+
graph_main_output_tensor = torch::empty({(int)(count_bots - old_bots_indexes.size()), ac_work->n_out}, torch::kCUDA);
125136

126137
// Global Speedups
127138
// Produce nondetermenistic behavior even on the same gpu
@@ -339,6 +350,7 @@ torch::Tensor sample_bernoulli_batch(torch::Tensor probs)
339350
torch::Tensor process_old_model_batch(torch::Tensor outputs)
340351
{
341352
// Split tensor components
353+
//printf("000\n");
342354
auto angle_logits = outputs.slice(1, 0, 2);
343355
auto dir_logits = outputs.slice(1, 2, 5);
344356
auto hook_logits = outputs.slice(1, 5, 6);
@@ -462,17 +474,15 @@ std::vector<ModelOutput> ModelManager::Decide(
462474
{
463475
if(!input_to_model_id.empty() && input_to_model_id[i] != -1)
464476
{
465-
/*if(!graph_recorded)
466-
graph_input_tensors.push_back(state_gpu[i].reshape({1, n_in}));
467-
else*/
468-
old_states.push_back(state_gpu[i].reshape({1, n_in}));
477+
graph_input_tensors[graph_counter].copy_(state_gpu[i].reshape({1, n_in}), true);
478+
//old_states.push_back(state_gpu[i].reshape({1, n_in}));
469479
old_indices.push_back(i); // Track the original index
470480
graph_counter += 1;
471481
}
472482
else
473483
{
474-
//current_states[graph_main_counter].copy_(state_gpu[i].reshape({1, n_in}), true);
475-
current_states.push_back(state_gpu[i].reshape({1, n_in}));
484+
graph_main_input_tensor[graph_main_counter].copy_(state_gpu[i].reshape({n_in}), true);
485+
//current_states.push_back(state_gpu[i].reshape({1, n_in}));
476486
current_indices.push_back(i); // Track the original index
477487
graph_main_counter += 1;
478488
}
@@ -481,71 +491,58 @@ std::vector<ModelOutput> ModelManager::Decide(
481491

482492
//old_batches.resize(old_indices.size());
483493

484-
// Vector to hold the futures
485-
//std::vector<std::future<void>> futures;
486-
//printf("1\n");
487-
//// Process each index asynchronously
488-
//for(size_t i = 0; i < old_indices.size(); ++i)
489-
//{
490-
// // Launch a task asynchronously
491-
// futures.push_back(std::async(std::launch::async, [&, i]() {
492-
// cudaSetDevice(0);
493-
// at::Stream stream = at::cuda::getStreamFromPool(); // Create stream for this thread
494-
// at::cuda::CUDAStreamGuard guard(stream); // Guard the stream in this scope
495-
// int model_id = input_to_model_id[old_indices[i]]; // Get the model ID for this input
496-
// auto av_old = old_ac[model_id]->actor_forward(state_gpu[old_indices[i]]);
497-
// old_batches[old_indices[i]] = av_old; // Store the result for this old model
498-
// }));
499-
//}
500-
//printf("2\n");
501-
//if(old_indices.size())
502-
//{
503-
// Sleep(1000);
504-
// printf("2.1\n");
505-
//}
506-
507-
//// Wait for all tasks to complete
508-
//for(auto &future : futures)
509-
//{
510-
// future.get();
511-
//}
512-
//printf("3\n");
513-
514494
auto now = std::chrono::high_resolution_clock::now();
515495
time_pre_forward = std::chrono::duration<double>(now - measure_time).count() * 1000.;
516496

517497
measure_time = std::chrono::high_resolution_clock::now();
518-
torch::Tensor main_input = torch::cat(current_states, 0);
498+
//torch::Tensor main_input = torch::cat(current_states, 0);
519499
//std::cout << graph_main_input_tensor.sizes() << std::endl;
520500

521-
// Process old models
522-
//cudaStreamCreate(&stream);
523-
//omp_set_num_threads(4);
524-
//#pragma omp parallel for
501+
if(!graph_recorded && warmup_index >= 3)
502+
{
503+
torch::StreamGuard stream_guard{graph_stream};
504+
graph.capture_begin();
525505

526-
//graph_main_output_tensor.copy_(ac_work->actor_forward(graph_main_input_tensor), true);
506+
graph_main_output_tensor.copy_(ac_work->actor_forward(graph_main_input_tensor), true);
527507

528-
//for(int i = 0; i < graph_input_tensors.size(); ++i)
529-
//{
530-
// int model_id = input_to_model_id[old_indices[i]]; // get the model id for this input
531-
// auto av_old = old_ac[model_id]->actor_forward(graph_input_tensors[i]);
532-
// graph_output_tensors[i].copy_(av_old.reshape({n_out}), true); // store the result for this old model
533-
//}
508+
for(int i = 0; i < graph_input_tensors.size(); ++i)
509+
{
510+
int model_id = input_to_model_id[old_indices[i]]; // get the model id for this input
511+
auto av_old = old_ac[model_id]->actor_forward(graph_input_tensors[i]);
512+
graph_output_tensors[i].copy_(av_old.reshape({1, ac_work->n_out}), true); // store the result for this old model
513+
}
534514

535-
//nvtxRangePushA("Graph begin");
515+
graph.capture_end();
516+
graph_recorded = true;
517+
}
518+
else if(!graph_recorded && warmup_index < 3)
519+
{
520+
graph_main_output_tensor.copy_(ac_work->actor_forward(graph_main_input_tensor), true);
536521

522+
for(int i = 0; i < graph_input_tensors.size(); ++i)
523+
{
524+
int model_id = input_to_model_id[old_indices[i]]; // get the model id for this input
525+
auto av_old = old_ac[model_id]->actor_forward(graph_input_tensors[i]);
526+
graph_output_tensors[i].copy_(av_old.reshape({1, ac_work->n_out}), true); // store the result for this old model
527+
}
528+
warmup_index += 1;
529+
}
530+
else
531+
{
532+
graph.replay();
533+
}
537534

538-
torch::Tensor av_current = ac_work->actor_forward(main_input);
535+
//torch::Tensor av_current = ac_work->actor_forward(main_input);
539536

540537
//printf("2.1\n");
541-
// Step 2: Record the forward pass into the graph
542-
// Define the kernel parameters for the forward pass using the model
543-
for(int i = 0; i < old_states.size(); ++i)
544-
{
545-
int model_id = input_to_model_id[old_indices[i]]; // get the model id for this input
546-
auto av_old = old_ac[model_id]->actor_forward(old_states[i]);
547-
old_batches.push_back(av_old.reshape({1, ac_work->n_out})); // store the result for this old model
548-
}
538+
//// Step 2: Record the forward pass into the graph
539+
//// Define the kernel parameters for the forward pass using the model
540+
//for(int i = 0; i < old_states.size(); ++i)
541+
//{
542+
// int model_id = input_to_model_id[old_indices[i]]; // get the model id for this input
543+
// auto av_old = old_ac[model_id]->actor_forward(old_states[i]);
544+
// old_batches.push_back(av_old.reshape({1, ac_work->n_out})); // store the result for this old model
545+
//}
549546
//std::cout << old_batches.size() << std::endl;
550547
now = std::chrono::high_resolution_clock::now();
551548
time_forward = std::chrono::duration<double>(now - measure_time).count() * 1000.;
@@ -554,16 +551,16 @@ std::vector<ModelOutput> ModelManager::Decide(
554551
//std::cout << graph_main_output_tensor[0] << std::endl;
555552
torch::Tensor av_current_sampled, old_current_sampled, old_current;
556553
//printf("1\n");
557-
if(old_batches.size())
554+
if(graph_output_tensors.size())
558555
{
559-
old_current = torch::cat(old_batches, 0);
556+
old_current = torch::cat(graph_output_tensors, 0);
560557
// printf("1.5\n");
561-
// std::cout << old_current.sizes() << std::endl;
558+
//std::cout << old_current.sizes() << std::endl;
562559
old_current_sampled = process_old_model_batch(old_current);
563560
}
564561
//printf("1.5\n");
565562

566-
av_current_sampled = process_main_network(av_current);
563+
av_current_sampled = process_main_network(graph_main_output_tensor);
567564
//nvtxRangePop();
568565
//std::cout << av_current[0] << std::endl;
569566
//printf("2\n");
@@ -576,15 +573,15 @@ std::vector<ModelOutput> ModelManager::Decide(
576573

577574
// Combine results from old models and current model in the correct order
578575
std::vector<torch::Tensor> all_actions_sampled(input_inputs.size()), all_actions_original(input_inputs.size());
579-
for(size_t i = 0; i < old_batches.size(); ++i)
576+
for(size_t i = 0; i < graph_output_tensors.size(); ++i)
580577
{
581578
all_actions_sampled[old_indices[i]] = old_current_sampled[i]; // Place old model results in their original positions
582-
all_actions_original[old_indices[i]] = old_batches[i].reshape({ac_work->n_out});
579+
all_actions_original[old_indices[i]] = graph_output_tensors[i].reshape({ac_work->n_out});
583580
}
584-
for(size_t i = 0; i < current_states.size(); ++i)
581+
for(size_t i = 0; i < current_indices.size(); ++i)
585582
{
586583
all_actions_sampled[current_indices[i]] = av_current_sampled[i]; // Place current model results in their original positions
587-
all_actions_original[current_indices[i]] = av_current[i];
584+
all_actions_original[current_indices[i]] = graph_main_output_tensor[i];
588585
}
589586
//printf("888\n");
590587
//nvtxRangePop();
@@ -623,7 +620,7 @@ std::vector<ModelOutput> ModelManager::Decide(
623620
if(is_training && !validating)
624621
{
625622
//torch::Tensor sampled = torch::zeros({(int)input_inputs.size(), 5}, torch::kCUDA);
626-
////printf("13\n");
623+
//printf("13\n");
627624

628625
//sampled.slice(1, 0, 2).copy_(tActions.slice(1, 0, 2));
629626
//sampled.slice(1, 2, 3).copy_(directions);
@@ -749,13 +746,15 @@ void ModelManager::SaveReplays(bool& is_full)
749746
mask.push_back(1);
750747
}
751748
}
752-
for(size_t i = 0; i < dones.size() && old_ac.size(); i++)
753-
{
754-
if(dones[i] && input_to_model_id[i] != -1)
755-
{
756-
input_to_model_id[i] = static_cast<int>(round(random_float() * (float)(old_ac.size() - 1))); // Assign to old model
757-
}
758-
}
749+
750+
// Reassign to new model after completion
751+
//for(size_t i = 0; i < dones.size() && old_ac.size(); i++)
752+
//{
753+
// if(dones[i] && input_to_model_id[i] != -1)
754+
// {
755+
// input_to_model_id[i] = static_cast<int>(round(random_float() * (float)(old_ac.size() - 1))); // Assign to old model
756+
// }
757+
//}
759758
//printf("2\n");
760759
//std::cout << states[0].sizes() << std::endl;
761760
//std::cout << actions[0].sizes() << std::endl;
@@ -815,6 +814,21 @@ void ModelManager::ReassignOldModels()
815814
input_to_model_id[old_bots_indexes[i]] = static_cast<int>(round(random_float() * (float)(old_ac.size() - 1))); // Assign to old model
816815
}
817816

817+
graph_input_tensors.clear();
818+
graph_output_tensors.clear();
819+
for(size_t i = 0; i < old_bots_indexes.size(); i++)
820+
{
821+
torch::Tensor empty_in = torch::empty({1, n_in}, torch::kCUDA);
822+
graph_input_tensors.push_back(empty_in);
823+
torch::Tensor empty_out = torch::empty({1, ac_work->n_out}, torch::kCUDA);
824+
graph_output_tensors.push_back(empty_out);
825+
}
826+
graph_main_input_tensor = torch::empty({(int)(count_bots - old_bots_indexes.size()), n_in}, torch::kCUDA);
827+
graph_main_output_tensor = torch::empty({(int)(count_bots - old_bots_indexes.size()), ac_work->n_out}, torch::kCUDA);
828+
graph_recorded = false;
829+
graph.reset();
830+
warmup_index = 0;
831+
818832
return;
819833
}
820834

@@ -894,22 +908,6 @@ void ModelManager::Update(double avg_reward, bool cache_model, bool &updated,
894908
if(!old_ac.empty())
895909
{
896910
ReassignOldModels();
897-
//graph_input_tensors.clear();
898-
////graph_main_input_tensors.clear();
899-
//graph_output_tensors.clear();
900-
//for(size_t i = 0; i < old_bots_indexes.size(); i++)
901-
//{
902-
// torch::Tensor empty_in = torch::empty({1, n_in}, torch::kCUDA);
903-
// graph_input_tensors.push_back(empty_in);
904-
// torch::Tensor empty_out = torch::empty({n_out}, torch::kCUDA);
905-
// graph_output_tensors.push_back(empty_out);
906-
//}
907-
//graph_main_input_tensor = torch::empty({(int)(count_bots - old_bots_indexes.size()), n_in}, torch::kCUDA);
908-
//graph_main_output_tensor = torch::empty({(int)(count_bots - old_bots_indexes.size()), n_out}, torch::kCUDA);
909-
910-
// Clean up
911-
//graph.reset();
912-
//graph_recorded = false;
913911
}
914912

915913
//int botes = count_bots - old_bots_indexes.size();

0 commit comments

Comments
 (0)