diff --git a/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.cpp b/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.cpp
index 7d51fc2e7a..76a3cc62b7 100644
--- a/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.cpp
+++ b/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.cpp
@@ -146,6 +146,12 @@ GlobalSettings::GlobalSettings()
LockMode::UNLOCK_WHILE_RUNNING,
false
)
+ , USE_GPU_FOR_ML_INFERENCE(
+ "Use GPU for Machine learning inference:
"
+ "Use the GPU by default for machine learning. Will fall-back to CPU if using the GPU fails.",
+ LockMode::UNLOCK_WHILE_RUNNING,
+ true
+ )
, WINDOW_SIZE(
CONSTRUCT_TOKEN,
"Window Size/Position:",
@@ -261,6 +267,7 @@ GlobalSettings::GlobalSettings()
PA_ADD_OPTION(TEMP_FOLDER);
PA_ADD_OPTION(THEME);
PA_ADD_OPTION(USE_PADDLE_OCR);
+ PA_ADD_OPTION(USE_GPU_FOR_ML_INFERENCE);
PA_ADD_OPTION(WINDOW_SIZE);
PA_ADD_OPTION(LOG_WINDOW_SIZE);
PA_ADD_OPTION(LOG_WINDOW_STARTUP);
diff --git a/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.h b/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.h
index 8bc9014214..df5a1f4bbe 100644
--- a/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.h
+++ b/SerialPrograms/Source/CommonFramework/GlobalSettingsPanel.h
@@ -124,6 +124,7 @@ class GlobalSettings : public BatchOption, private ConfigOption::Listener, priva
Pimpl THEME;
BooleanCheckBoxOption USE_PADDLE_OCR;
+ BooleanCheckBoxOption USE_GPU_FOR_ML_INFERENCE;
Pimpl WINDOW_SIZE;
Pimpl LOG_WINDOW_SIZE;
BooleanCheckBoxOption LOG_WINDOW_STARTUP;
diff --git a/SerialPrograms/Source/ML/DataLabeling/ML_SegmentAnythingModel.cpp b/SerialPrograms/Source/ML/DataLabeling/ML_SegmentAnythingModel.cpp
index 5680b3fcc3..6d69f60ffa 100644
--- a/SerialPrograms/Source/ML/DataLabeling/ML_SegmentAnythingModel.cpp
+++ b/SerialPrograms/Source/ML/DataLabeling/ML_SegmentAnythingModel.cpp
@@ -28,8 +28,7 @@ namespace ML{
SAMEmbedderSession::SAMEmbedderSession(const std::string& model_path, bool use_gpu)
: m_env{create_ORT_env()}
- , m_session_options{create_session_options(ML_MODEL_CACHE_PATH() + "SAMEmbedder/", use_gpu)}
- , session{create_session(m_env, m_session_options, model_path, ML_MODEL_CACHE_PATH() + "SAMEmbedder/")}
+ , session{create_session(m_env, model_path, ML_MODEL_CACHE_PATH() + "SAMEmbedder/", use_gpu)}
, memory_info{Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU)}
, input_names{session.GetInputNames()}
, output_names{session.GetOutputNames()}
@@ -69,8 +68,7 @@ void SAMEmbedderSession::run(cv::Mat& input_image, std::vector& model_out
SAMSession::SAMSession(const std::string& model_path, bool use_gpu)
: m_env{create_ORT_env()}
- , m_session_options{create_session_options(ML_MODEL_CACHE_PATH() + "SAM/", use_gpu)}
- , session{create_session(m_env, m_session_options, model_path, ML_MODEL_CACHE_PATH() + "SAM/")}
+ , session{create_session(m_env, model_path, ML_MODEL_CACHE_PATH() + "SAM/", use_gpu)}
, memory_info{Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU)}
, input_names{session.GetInputNames()}
, output_names{session.GetOutputNames()}
diff --git a/SerialPrograms/Source/ML/DataLabeling/ML_SegmentAnythingModel.h b/SerialPrograms/Source/ML/DataLabeling/ML_SegmentAnythingModel.h
index 0296bd178e..dccdac3e29 100644
--- a/SerialPrograms/Source/ML/DataLabeling/ML_SegmentAnythingModel.h
+++ b/SerialPrograms/Source/ML/DataLabeling/ML_SegmentAnythingModel.h
@@ -39,7 +39,6 @@ class SAMEmbedderSession{
private:
Ort::Env m_env;
- Ort::SessionOptions m_session_options;
Ort::Session session;
Ort::MemoryInfo memory_info;
Ort::RunOptions run_options;
@@ -74,7 +73,6 @@ class SAMSession{
std::vector& output_boolean_mask);
private:
Ort::Env m_env;
- Ort::SessionOptions m_session_options;
Ort::Session session;
Ort::MemoryInfo memory_info;
Ort::RunOptions run_options;
diff --git a/SerialPrograms/Source/ML/Inference/ML_PaddleOCRPipeline.cpp b/SerialPrograms/Source/ML/Inference/ML_PaddleOCRPipeline.cpp
index 158bd51df3..4b6037460f 100644
--- a/SerialPrograms/Source/ML/Inference/ML_PaddleOCRPipeline.cpp
+++ b/SerialPrograms/Source/ML/Inference/ML_PaddleOCRPipeline.cpp
@@ -10,6 +10,7 @@
#include
#include
#include "CommonFramework/Globals.h"
+#include "CommonFramework/GlobalSettingsPanel.h"
#include "Common/Cpp/Exceptions.h"
#include "ML/Models/ML_ONNXRuntimeHelpers.h"
#include "ML_PaddleOCRPipeline.h"
@@ -53,7 +54,7 @@ PaddleOCRPipeline::PaddleOCRPipeline(Language language)
PaddleOCRPipeline::PaddleOCRPipeline(Language language, std::string rec_path, std::string dict_path)
: m_env{create_ORT_env()}
// , det_session(env, std::wstring(det_path.begin(), det_path.end()).c_str(), Ort::SessionOptions{})
- , m_rec_session(create_session(m_env, Ort::SessionOptions{}, rec_path, ML_MODEL_CACHE_PATH() + "PaddleOCRPipeline/"))
+ , m_rec_session(create_session(m_env, rec_path, ML_MODEL_CACHE_PATH() + "PaddleOCRPipeline/", GlobalSettings::instance().USE_GPU_FOR_ML_INFERENCE))
// , memory_info(Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault))
, m_language(language)
, m_input_name(m_rec_session.GetInputNameAllocated(0, Ort::AllocatorWithDefaultOptions{}).get())
diff --git a/SerialPrograms/Source/ML/Inference/ML_YOLOv5Detector.cpp b/SerialPrograms/Source/ML/Inference/ML_YOLOv5Detector.cpp
index 5b70ba3959..6fb47c6335 100644
--- a/SerialPrograms/Source/ML/Inference/ML_YOLOv5Detector.cpp
+++ b/SerialPrograms/Source/ML/Inference/ML_YOLOv5Detector.cpp
@@ -13,6 +13,7 @@
#include "Common/Cpp/PrettyPrint.h"
#include "Common/Cpp/Filesystem.h"
#include "Common/Cpp/Concurrency/SpinLock.h"
+#include "CommonFramework/GlobalSettingsPanel.h"
#include "CommonFramework/ImageTypes/ImageViewRGB32.h"
#include "CommonFramework/VideoPipeline/VideoOverlay.h"
#include "CommonFramework/VideoPipeline/VideoOverlayScopes.h"
@@ -44,7 +45,7 @@ YOLOv5Detector::~YOLOv5Detector() = default;
YOLOv5Detector::YOLOv5Detector(const std::string& model_path)
: m_model_path(to_resource_filepath(model_path))
- , m_use_gpu(true)
+ , m_use_gpu(GlobalSettings::instance().USE_GPU_FOR_ML_INFERENCE)
{
if (!model_path.ends_with(".onnx")){
throw InternalProgramError(nullptr, PA_CURRENT_FUNCTION,
diff --git a/SerialPrograms/Source/ML/Models/ML_ONNXRuntimeHelpers.cpp b/SerialPrograms/Source/ML/Models/ML_ONNXRuntimeHelpers.cpp
index 16a13b7f8d..2d447753d3 100644
--- a/SerialPrograms/Source/ML/Models/ML_ONNXRuntimeHelpers.cpp
+++ b/SerialPrograms/Source/ML/Models/ML_ONNXRuntimeHelpers.cpp
@@ -86,7 +86,7 @@ if (use_gpu){
std::cout << "Using ROCm execution provider for GPU acceleration" << std::endl;
rocm_available = true;
}catch (const Ort::Exception& e){
- std::cout << "ROCm execution provider not available, falling back to CPU: " << e.what() << std::endl;
+ std::cout << "ROCm execution provider not available: " << e.what() << std::endl;
}
}
@@ -181,24 +181,58 @@ void write_cache_flag_file(const std::string& model_cache_path, const std::strin
}
-Ort::Session create_session(const Ort::Env& env, const Ort::SessionOptions& so,
- const std::string& model_path, const std::string& model_cache_path)
-{
+Ort::Session create_session(
+ const Ort::Env& env,
+ const std::string& model_path,
+ const std::string& model_cache_path,
+ bool try_gpu
+){
bool write_flag_file = true;
std::string file_hash;
std::tie(write_flag_file, file_hash) = clean_up_old_model_cache(model_cache_path, model_path);
+ auto onnx_path = str_to_onnx_str(model_path);
+
auto& logger = global_logger_tagged();
logger.log("Creating Ort::session from model " + model_path);
- try{
- Ort::Session session{env, str_to_onnx_str(model_path).c_str(), so};
- logger.log("Ort::Session created");
- // when Ort::Ssssion is created, if possible, it will create a model cache
- if (write_flag_file){
- write_cache_flag_file(model_cache_path, file_hash);
+
+ // Attempt 1. using GPU.
+ if (try_gpu){
+ try{
+ logger.log("Attempting to create Ort::Session with GPU acceleration...");
+ Ort::SessionOptions gpu_options = create_session_options(model_cache_path, true);
+ Ort::Session session{env, onnx_path.c_str(), gpu_options};
+ logger.log("Ort::Session created");
+ // when Ort::Ssssion is created, if possible, it will create a model cache
+ if (write_flag_file){
+ write_cache_flag_file(model_cache_path, file_hash);
+ }
+ return session;
+ }catch (const Ort::Exception& e) {
+ logger.log("GPU Session creation failed: " + std::string(e.what()));
+ logger.log("Falling back cleanly to CPU execution...");
+ // Do not throw yet. Fall through to the CPU execution block below
+ } catch (...) {
+ logger.log("Unknown GPU initialization failure. Falling back cleanly to CPU...");
}
+ }
+
+ // Attempt 2. CPU fallback
+ try {
+ logger.log("Creating dedicated CPU-only session...");
+
+ Ort::SessionOptions cpu_options = create_session_options(model_cache_path, false);;
+
+ Ort::Session session{env, onnx_path.c_str(), cpu_options};
+ logger.log("Ort::Session created");
return session;
- }catch (...){
+ }
+ catch (const Ort::Exception& e) {
+ logger.log("CRITICAL: CPU fallback failed completely: " + std::string(e.what()));
+ throw MLModelSessionCreationError(&logger, model_path);
+ }
+ catch (...) {
+ logger.log("CRITICAL: Unknown failure during CPU session fallback.");
throw MLModelSessionCreationError(&logger, model_path);
}
}
diff --git a/SerialPrograms/Source/ML/Models/ML_ONNXRuntimeHelpers.h b/SerialPrograms/Source/ML/Models/ML_ONNXRuntimeHelpers.h
index 94e9600e45..31fcab833c 100644
--- a/SerialPrograms/Source/ML/Models/ML_ONNXRuntimeHelpers.h
+++ b/SerialPrograms/Source/ML/Models/ML_ONNXRuntimeHelpers.h
@@ -30,8 +30,12 @@ Ort::SessionOptions create_session_options(const std::string& model_cache_path,
// model_cache_path: the path to store model caches. This path must be the same path
// used in `create_session_options()` to construct the passed-in session options so.
// NOTE: it may throw `MLModelSessionCreationError` if failed to create session.
-Ort::Session create_session(const Ort::Env& env, const Ort::SessionOptions& so,
- const std::string& model_path, const std::string& model_cache_path);
+Ort::Session create_session(
+ const Ort::Env& env,
+ const std::string& model_path,
+ const std::string& model_cache_path,
+ bool try_gpu
+);
// Handy function to create an ONNX Runtime tensor view class from a vector-like `buffer` object holding
// the tensor data and an array-like `shape` object that represents the dimension of the tensor.
diff --git a/SerialPrograms/Source/ML/Models/ML_YOLOv5Model.cpp b/SerialPrograms/Source/ML/Models/ML_YOLOv5Model.cpp
index b9333ba08c..0ba86c44ce 100644
--- a/SerialPrograms/Source/ML/Models/ML_YOLOv5Model.cpp
+++ b/SerialPrograms/Source/ML/Models/ML_YOLOv5Model.cpp
@@ -134,8 +134,7 @@ std::tuple resize_image_with_border(
YOLOv5Session::YOLOv5Session(const std::string& model_path, bool use_gpu)
: m_env{create_ORT_env()}
-, m_session_options(create_session_options(ML_MODEL_CACHE_PATH() + "YOLOv5", use_gpu))
-, m_session{create_session(m_env, m_session_options, model_path, ML_MODEL_CACHE_PATH() + "YOLOv5")}
+, m_session{create_session(m_env, model_path, ML_MODEL_CACHE_PATH() + "YOLOv5", use_gpu)}
, m_memory_info{Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU)}
, m_input_names{m_session.GetInputNames()}
, m_output_names{m_session.GetOutputNames()}
diff --git a/SerialPrograms/Source/ML/Models/ML_YOLOv5Model.h b/SerialPrograms/Source/ML/Models/ML_YOLOv5Model.h
index c7e0e406ef..3d6ebdef6b 100644
--- a/SerialPrograms/Source/ML/Models/ML_YOLOv5Model.h
+++ b/SerialPrograms/Source/ML/Models/ML_YOLOv5Model.h
@@ -44,7 +44,6 @@ class YOLOv5Session{
std::vector m_label_names;
Ort::Env m_env;
- Ort::SessionOptions m_session_options;
Ort::Session m_session;
Ort::MemoryInfo m_memory_info;
Ort::RunOptions m_run_options;
diff --git a/SerialPrograms/Source/ML/Programs/ML_LabelImages.cpp b/SerialPrograms/Source/ML/Programs/ML_LabelImages.cpp
index 26ba7b85a6..0109dbd413 100644
--- a/SerialPrograms/Source/ML/Programs/ML_LabelImages.cpp
+++ b/SerialPrograms/Source/ML/Programs/ML_LabelImages.cpp
@@ -15,6 +15,7 @@
#include "Common/Cpp/Json/JsonObject.h"
#include "Common/Cpp/Json/JsonValue.h"
#include "Common/Cpp/Json/JsonTools.h"
+#include "CommonFramework/GlobalSettingsPanel.h"
#include "Pokemon/Pokemon_Strings.h"
#include "ML/DataLabeling/ML_SegmentAnythingModel.h"
#include "ML/DataLabeling/ML_AnnotationIO.h"
@@ -56,7 +57,7 @@ LabelImages::LabelImages(const LabelImages_Descriptor& descriptor)
: PanelInstance(descriptor)
, m_display_session(m_display_option)
, m_options(LockMode::UNLOCK_WHILE_RUNNING)
- , m_use_gpu_for_sam_anno(true)
+ , m_use_gpu_for_sam_anno(GlobalSettings::instance().USE_GPU_FOR_ML_INFERENCE)
, X("X Coordinate:", LockMode::UNLOCK_WHILE_RUNNING, 0.3, 0.0, 1.0)
, Y("Y Coordinate:", LockMode::UNLOCK_WHILE_RUNNING, 0.3, 0.0, 1.0)
, WIDTH("Width:", LockMode::UNLOCK_WHILE_RUNNING, 0.4, 0.0, 1.0)
@@ -67,7 +68,6 @@ LabelImages::LabelImages(const LabelImages_Descriptor& descriptor)
, CUSTOM_LABEL_DATABASE(create_string_select_database({"mc"})) // mc for "main character"
, CUSTOM_SET_LABEL(CUSTOM_LABEL_DATABASE, LockMode::UNLOCK_WHILE_RUNNING, 0)
, MANUAL_LABEL(false, LockMode::UNLOCK_WHILE_RUNNING, "", "Custom Label", true)
- , USE_GPU_FOR_EMBEDDER_SESSION("Enable GPU for Embedder session:", LockMode::LOCK_WHILE_RUNNING, true)
, SELECTED_ANNO_COLOR(
"Color of selected annotation:",
{
@@ -121,7 +121,6 @@ LabelImages::LabelImages(const LabelImages_Descriptor& descriptor)
ADD_OPTION(FORM_LABEL);
ADD_OPTION(CUSTOM_SET_LABEL);
ADD_OPTION(MANUAL_LABEL);
- ADD_OPTION(USE_GPU_FOR_EMBEDDER_SESSION);
ADD_OPTION(SELECTED_ANNO_COLOR);
ADD_OPTION(UNSELECTED_ANNO_COLOR);
@@ -136,7 +135,7 @@ LabelImages::LabelImages(const LabelImages_Descriptor& descriptor)
- init_sam_session(true);
+ init_sam_session(GlobalSettings::instance().USE_GPU_FOR_ML_INFERENCE);
m_overlay_manager = new LabelImages_OverlayManager(*this);
}
@@ -511,7 +510,7 @@ void LabelImages::remove_segmentation_exclusion_point(double x, double y){
void LabelImages::compute_embeddings_for_folder(const std::string& image_folder_path){
std::string embedding_model_path = RESOURCE_PATH() + "ML/sam_embedder_cpu.onnx";
std::cout << "Use SAM Embedding model " << embedding_model_path << std::endl;
- ML::compute_embeddings_for_folder(embedding_model_path, image_folder_path, USE_GPU_FOR_EMBEDDER_SESSION);
+ ML::compute_embeddings_for_folder(embedding_model_path, image_folder_path, GlobalSettings::instance().USE_GPU_FOR_ML_INFERENCE);
}
void LabelImages::delete_selected_annotation(){
diff --git a/SerialPrograms/Source/ML/Programs/ML_LabelImages.h b/SerialPrograms/Source/ML/Programs/ML_LabelImages.h
index 766129e4ee..0431484317 100644
--- a/SerialPrograms/Source/ML/Programs/ML_LabelImages.h
+++ b/SerialPrograms/Source/ML/Programs/ML_LabelImages.h
@@ -178,8 +178,6 @@ class LabelImages : public PanelInstance, public ConfigOption::Listener {
// source 3: editable text input
StringCell MANUAL_LABEL;
- BooleanCheckBoxOption USE_GPU_FOR_EMBEDDER_SESSION;
-
EnumDropdownOption SELECTED_ANNO_COLOR;
EnumDropdownOption UNSELECTED_ANNO_COLOR;
diff --git a/SerialPrograms/Source/ML/Programs/ML_LabelImagesWidget.cpp b/SerialPrograms/Source/ML/Programs/ML_LabelImagesWidget.cpp
index c2887c8e34..abf5ccacb9 100644
--- a/SerialPrograms/Source/ML/Programs/ML_LabelImagesWidget.cpp
+++ b/SerialPrograms/Source/ML/Programs/ML_LabelImagesWidget.cpp
@@ -129,12 +129,12 @@ LabelImages_Widget::LabelImages_Widget(
annotation_row->addWidget(load_custom_set_button, 2);
annotation_row->addWidget(new QLabel(scroll_inner), 10); // an empty label to push other UIs to the left
- // add GPU checkbox row
- QHBoxLayout* use_gpu_row = new QHBoxLayout();
- scroll_layout->addLayout(use_gpu_row);
+ // // add GPU checkbox row
+ // QHBoxLayout* use_gpu_row = new QHBoxLayout();
+ // scroll_layout->addLayout(use_gpu_row);
- ConfigWidget* gpu_checkbox_widget = ConfigWidget::make_from_option(program.USE_GPU_FOR_EMBEDDER_SESSION, scroll_inner);
- use_gpu_row->addWidget(&gpu_checkbox_widget->widget(), 2);
+ // ConfigWidget* gpu_checkbox_widget = ConfigWidget::make_from_option(program.USE_GPU_FOR_EMBEDDER_SESSION, scroll_inner);
+ // use_gpu_row->addWidget(&gpu_checkbox_widget->widget(), 2);
// add Color selection dropdown
QHBoxLayout* selected_color_choice_row = new QHBoxLayout();