Răsfoiți Sursa

Fix segmentation fault in model loading

- Fix string lifetime issue by creating persistent string copies for all paths
- Improve path selection logic for models in root /data/SD_MODELS/ directory
- Add special handling for Qwen models to prefer diffusion_model_path regardless of directory
- Enhance fallback logic with proper context parameter initialization
- Add verbose debug logging throughout the model loading process
- Add GGUF/GGML model detection and minimal parameter fallback
- Use absolute paths in all console output messages

This fixes the segmentation fault when loading diffusion models, particularly
Qwen models in the root models directory.
Fszontagh 3 luni în urmă
părinte
comite
e78bec3fff
1 a modificat fișierele cu 181 adăugiri și 46 ștergeri
  1. 181 46
      src/stable_diffusion_wrapper.cpp

+ 181 - 46
src/stable_diffusion_wrapper.cpp

@@ -37,10 +37,22 @@ public:
         sd_ctx_params_t ctxParams;
         sd_ctx_params_init(&ctxParams);
         
-        std::cout << "Loading model: " << modelPath << std::endl;
+        // Get absolute path for logging
+        std::filesystem::path absModelPath = std::filesystem::absolute(modelPath);
+        std::cout << "Loading model from absolute path: " << absModelPath << std::endl;
         
-        // Use folder-based path selection instead of architecture detection
-        // This is more reliable and faster than parsing model files
+        // Create persistent string copies to fix lifetime issues
+        // These strings will remain valid for the entire lifetime of the context
+        std::string persistentModelPath = modelPath;
+        std::string persistentClipLPath = params.clipLPath;
+        std::string persistentClipGPath = params.clipGPath;
+        std::string persistentVaePath = params.vaePath;
+        std::string persistentTaesdPath = params.taesdPath;
+        std::string persistentControlNetPath = params.controlNetPath;
+        std::string persistentLoraModelDir = params.loraModelDir;
+        std::string persistentEmbeddingDir = params.embeddingDir;
+        
+        // Use folder-based path selection with enhanced logic
         bool useDiffusionModelPath = false;
         std::string detectionSource = "folder";
         
@@ -48,22 +60,83 @@ public:
         std::filesystem::path modelFilePath(modelPath);
         std::filesystem::path parentDir = modelFilePath.parent_path();
         std::string parentDirName = parentDir.filename().string();
+        std::string modelFileName = modelFilePath.filename().string();
         
         // Convert to lowercase for comparison
         std::transform(parentDirName.begin(), parentDirName.end(), parentDirName.begin(), ::tolower);
+        std::transform(modelFileName.begin(), modelFileName.end(), modelFileName.begin(), ::tolower);
         
         // Variables for fallback detection
         ModelDetectionResult detectionResult;
         bool detectionSuccessful = false;
+        bool isQwenModel = false;
+        
+        // Check if this is a Qwen model based on filename
+        if (modelFileName.find("qwen") != std::string::npos) {
+            isQwenModel = true;
+            std::cout << "Detected Qwen model from filename: " << modelFileName << std::endl;
+        }
         
+        // Enhanced path selection logic
         if (parentDirName == "diffusion_models" || parentDirName == "diffusion") {
             useDiffusionModelPath = true;
-            std::cout << "Model is in diffusion_models directory, using diffusion_model_path" << std::endl;
+            std::cout << "Model is in " << parentDirName << " directory, using diffusion_model_path" << std::endl;
         } else if (parentDirName == "checkpoints" || parentDirName == "stable-diffusion") {
             useDiffusionModelPath = false;
-            std::cout << "Model is in checkpoints directory, using model_path" << std::endl;
+            std::cout << "Model is in " << parentDirName << " directory, using model_path" << std::endl;
+        } else if (parentDirName == "sd_models" || parentDirName.empty()) {
+            // Handle models in root /data/SD_MODELS/ directory
+            if (isQwenModel) {
+                // Qwen models should use diffusion_model_path regardless of directory
+                useDiffusionModelPath = true;
+                detectionSource = "qwen_root_detection";
+                std::cout << "Qwen model in root directory, preferring diffusion_model_path" << std::endl;
+            } else {
+                // For non-Qwen models in root, try architecture detection
+                std::cout << "Model is in root directory '" << parentDirName << "', attempting architecture detection" << std::endl;
+                detectionSource = "architecture_fallback";
+                
+                try {
+                    detectionResult = ModelDetector::detectModel(modelPath);
+                    detectionSuccessful = true;
+                    std::cout << "Architecture detection found: " << detectionResult.architectureName << std::endl;
+                } catch (const std::exception& e) {
+                    std::cerr << "Warning: Architecture detection failed: " << e.what() << ". Using default loading method." << std::endl;
+                    detectionResult.architecture = ModelArchitecture::UNKNOWN;
+                    detectionResult.architectureName = "Unknown";
+                }
+
+                if (detectionSuccessful) {
+                    switch (detectionResult.architecture) {
+                        case ModelArchitecture::FLUX_SCHNELL:
+                        case ModelArchitecture::FLUX_DEV:
+                        case ModelArchitecture::FLUX_CHROMA:
+                        case ModelArchitecture::SD_3:
+                        case ModelArchitecture::QWEN2VL:
+                            // Modern architectures use diffusion_model_path
+                            useDiffusionModelPath = true;
+                            break;
+                        case ModelArchitecture::SD_1_5:
+                        case ModelArchitecture::SD_2_1:
+                        case ModelArchitecture::SDXL_BASE:
+                        case ModelArchitecture::SDXL_REFINER:
+                            // Traditional SD models use model_path
+                            useDiffusionModelPath = false;
+                            break;
+                        case ModelArchitecture::UNKNOWN:
+                        default:
+                            // Unknown architectures fall back to model_path for backward compatibility
+                            useDiffusionModelPath = false;
+                            std::cout << "Warning: Unknown model architecture detected, using default model_path for backward compatibility" << std::endl;
+                            break;
+                    }
+                } else {
+                    useDiffusionModelPath = false; // Default fallback
+                    detectionSource = "default_fallback";
+                }
+            }
         } else {
-            // Fallback: try architecture detection for unknown locations
+            // Unknown directory - try architecture detection
             std::cout << "Model is in unknown directory '" << parentDirName << "', attempting architecture detection as fallback" << std::endl;
             detectionSource = "architecture_fallback";
             
@@ -109,36 +182,43 @@ public:
 
         // Set the appropriate model path based on folder location or fallback detection
         if (useDiffusionModelPath) {
-            ctxParams.diffusion_model_path = modelPath.c_str();
+            ctxParams.diffusion_model_path = persistentModelPath.c_str();
             ctxParams.model_path = nullptr; // Clear the traditional path
             std::cout << "Using diffusion_model_path (source: " << detectionSource << ")" << std::endl;
         } else {
-            ctxParams.model_path = modelPath.c_str();
+            ctxParams.model_path = persistentModelPath.c_str();
             ctxParams.diffusion_model_path = nullptr; // Clear the modern path
             std::cout << "Using model_path (source: " << detectionSource << ")" << std::endl;
         }
 
-        // Set optional model paths if provided
-        if (!params.clipLPath.empty()) {
-            ctxParams.clip_l_path = params.clipLPath.c_str();
+        // Set optional model paths using persistent strings to fix lifetime issues
+        if (!persistentClipLPath.empty()) {
+            ctxParams.clip_l_path = persistentClipLPath.c_str();
+            std::cout << "Using CLIP-L path: " << std::filesystem::absolute(persistentClipLPath) << std::endl;
         }
-        if (!params.clipGPath.empty()) {
-            ctxParams.clip_g_path = params.clipGPath.c_str();
+        if (!persistentClipGPath.empty()) {
+            ctxParams.clip_g_path = persistentClipGPath.c_str();
+            std::cout << "Using CLIP-G path: " << std::filesystem::absolute(persistentClipGPath) << std::endl;
         }
-        if (!params.vaePath.empty()) {
-            ctxParams.vae_path = params.vaePath.c_str();
+        if (!persistentVaePath.empty()) {
+            ctxParams.vae_path = persistentVaePath.c_str();
+            std::cout << "Using VAE path: " << std::filesystem::absolute(persistentVaePath) << std::endl;
         }
-        if (!params.taesdPath.empty()) {
-            ctxParams.taesd_path = params.taesdPath.c_str();
+        if (!persistentTaesdPath.empty()) {
+            ctxParams.taesd_path = persistentTaesdPath.c_str();
+            std::cout << "Using TAESD path: " << std::filesystem::absolute(persistentTaesdPath) << std::endl;
         }
-        if (!params.controlNetPath.empty()) {
-            ctxParams.control_net_path = params.controlNetPath.c_str();
+        if (!persistentControlNetPath.empty()) {
+            ctxParams.control_net_path = persistentControlNetPath.c_str();
+            std::cout << "Using ControlNet path: " << std::filesystem::absolute(persistentControlNetPath) << std::endl;
         }
-        if (!params.loraModelDir.empty()) {
-            ctxParams.lora_model_dir = params.loraModelDir.c_str();
+        if (!persistentLoraModelDir.empty()) {
+            ctxParams.lora_model_dir = persistentLoraModelDir.c_str();
+            std::cout << "Using LoRA model directory: " << std::filesystem::absolute(persistentLoraModelDir) << std::endl;
         }
-        if (!params.embeddingDir.empty()) {
-            ctxParams.embedding_dir = params.embeddingDir.c_str();
+        if (!persistentEmbeddingDir.empty()) {
+            ctxParams.embedding_dir = persistentEmbeddingDir.c_str();
+            std::cout << "Using embedding directory: " << std::filesystem::absolute(persistentEmbeddingDir) << std::endl;
         }
 
         // Set performance parameters
@@ -154,9 +234,11 @@ public:
         ctxParams.wtype = StableDiffusionWrapper::stringToModelType(params.modelType);
 
         // Create the stable-diffusion context
+        std::cout << "Attempting to create stable-diffusion context with selected parameters..." << std::endl;
         sdContext = new_sd_ctx(&ctxParams);
         if (!sdContext) {
             lastError = "Failed to create stable-diffusion context";
+            std::cerr << "Error: " << lastError << " with initial attempt" << std::endl;
 
             // If we used diffusion_model_path and it failed, try fallback to model_path
             if (useDiffusionModelPath) {
@@ -165,31 +247,31 @@ public:
                 // Re-initialize context parameters
                 sd_ctx_params_init(&ctxParams);
 
-                // Set fallback model path
-                ctxParams.model_path = modelPath.c_str();
+                // Set fallback model path using persistent string
+                ctxParams.model_path = persistentModelPath.c_str();
                 ctxParams.diffusion_model_path = nullptr;
 
-                // Re-apply other parameters
-                if (!params.clipLPath.empty()) {
-                    ctxParams.clip_l_path = params.clipLPath.c_str();
+                // Re-apply other parameters using persistent strings
+                if (!persistentClipLPath.empty()) {
+                    ctxParams.clip_l_path = persistentClipLPath.c_str();
                 }
-                if (!params.clipGPath.empty()) {
-                    ctxParams.clip_g_path = params.clipGPath.c_str();
+                if (!persistentClipGPath.empty()) {
+                    ctxParams.clip_g_path = persistentClipGPath.c_str();
                 }
-                if (!params.vaePath.empty()) {
-                    ctxParams.vae_path = params.vaePath.c_str();
+                if (!persistentVaePath.empty()) {
+                    ctxParams.vae_path = persistentVaePath.c_str();
                 }
-                if (!params.taesdPath.empty()) {
-                    ctxParams.taesd_path = params.taesdPath.c_str();
+                if (!persistentTaesdPath.empty()) {
+                    ctxParams.taesd_path = persistentTaesdPath.c_str();
                 }
-                if (!params.controlNetPath.empty()) {
-                    ctxParams.control_net_path = params.controlNetPath.c_str();
+                if (!persistentControlNetPath.empty()) {
+                    ctxParams.control_net_path = persistentControlNetPath.c_str();
                 }
-                if (!params.loraModelDir.empty()) {
-                    ctxParams.lora_model_dir = params.loraModelDir.c_str();
+                if (!persistentLoraModelDir.empty()) {
+                    ctxParams.lora_model_dir = persistentLoraModelDir.c_str();
                 }
-                if (!params.embeddingDir.empty()) {
-                    ctxParams.embedding_dir = params.embeddingDir.c_str();
+                if (!persistentEmbeddingDir.empty()) {
+                    ctxParams.embedding_dir = persistentEmbeddingDir.c_str();
                 }
 
                 // Re-apply performance parameters
@@ -204,25 +286,78 @@ public:
                 // Re-apply model type
                 ctxParams.wtype = StableDiffusionWrapper::stringToModelType(params.modelType);
 
+                std::cout << "Attempting to create context with fallback model_path..." << std::endl;
                 // Try creating context again with fallback
                 sdContext = new_sd_ctx(&ctxParams);
                 if (!sdContext) {
                     lastError = "Failed to create stable-diffusion context with both diffusion_model_path and model_path fallback";
                     std::cerr << "Error: " << lastError << std::endl;
-                    return false;
+                    
+                    // Additional fallback: try with minimal parameters for GGUF models
+                    if (modelFileName.find(".gguf") != std::string::npos || modelFileName.find(".ggml") != std::string::npos) {
+                        std::cout << "Detected GGUF/GGML model, attempting minimal parameter fallback..." << std::endl;
+                        
+                        // Re-initialize with minimal parameters
+                        sd_ctx_params_init(&ctxParams);
+                        ctxParams.model_path = persistentModelPath.c_str();
+                        ctxParams.diffusion_model_path = nullptr;
+                        
+                        // Set only essential parameters for GGUF
+                        ctxParams.n_threads = params.nThreads;
+                        ctxParams.wtype = StableDiffusionWrapper::stringToModelType(params.modelType);
+                        
+                        std::cout << "Attempting to create context with minimal GGUF parameters..." << std::endl;
+                        sdContext = new_sd_ctx(&ctxParams);
+                        
+                        if (!sdContext) {
+                            lastError = "Failed to create stable-diffusion context even with minimal GGUF parameters";
+                            std::cerr << "Error: " << lastError << std::endl;
+                            return false;
+                        }
+                        
+                        std::cout << "Successfully loaded GGUF model with minimal parameters: " << absModelPath << std::endl;
+                    } else {
+                        return false;
+                    }
+                } else {
+                    std::cout << "Successfully loaded model with fallback to model_path: " << absModelPath << std::endl;
                 }
-
-                std::cout << "Successfully loaded model with fallback to model_path: " << modelPath << std::endl;
             } else {
-                std::cerr << "Error: " << lastError << std::endl;
-                return false;
+                // Try minimal fallback for non-diffusion_model_path failures
+                if (modelFileName.find(".gguf") != std::string::npos || modelFileName.find(".ggml") != std::string::npos) {
+                    std::cout << "Detected GGUF/GGML model, attempting minimal parameter fallback..." << std::endl;
+                    
+                    // Re-initialize with minimal parameters
+                    sd_ctx_params_init(&ctxParams);
+                    ctxParams.model_path = persistentModelPath.c_str();
+                    
+                    // Set only essential parameters for GGUF
+                    ctxParams.n_threads = params.nThreads;
+                    ctxParams.wtype = StableDiffusionWrapper::stringToModelType(params.modelType);
+                    
+                    std::cout << "Attempting to create context with minimal GGUF parameters..." << std::endl;
+                    sdContext = new_sd_ctx(&ctxParams);
+                    
+                    if (!sdContext) {
+                        lastError = "Failed to create stable-diffusion context even with minimal GGUF parameters";
+                        std::cerr << "Error: " << lastError << std::endl;
+                        return false;
+                    }
+                    
+                    std::cout << "Successfully loaded GGUF model with minimal parameters: " << absModelPath << std::endl;
+                } else {
+                    std::cerr << "Error: " << lastError << std::endl;
+                    return false;
+                }
             }
         }
 
         // Log successful loading with detection information
-        std::cout << "Successfully loaded model: " << modelPath << std::endl;
+        std::cout << "Successfully loaded model: " << absModelPath << std::endl;
         std::cout << "  Detection source: " << detectionSource << std::endl;
         std::cout << "  Loading method: " << (useDiffusionModelPath ? "diffusion_model_path" : "model_path") << std::endl;
+        std::cout << "  Parent directory: " << parentDirName << std::endl;
+        std::cout << "  Model filename: " << modelFileName << std::endl;
 
         // Log additional model properties if architecture detection was performed
         if (detectionSuccessful) {