egumasa commited on
Commit
bb65e54
·
1 Parent(s): a12eec8

Enhance GPU support with stronger enforcement

Browse files

- Added spacy.require_gpu() for stronger GPU enforcement in base_analyzer.py
- Created gpu_init.py module to initialize GPU before any SpaCy imports
- Import gpu_init at the very start of app.py to ensure early GPU setup
- Enhanced GPU debugging scripts for HuggingFace Spaces

These changes ensure that when deployed to HuggingFace Spaces with GPU:
1. GPU is initialized before any model loading
2. SpaCy is forced to use GPU with require_gpu()
3. All model components are explicitly moved to GPU
4. GPU usage is verified and reported

test_current_gpu.py ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Quick GPU diagnostic for current environment."""
3
+
4
+ import sys
5
+ import os
6
+
7
+ print("=== GPU Diagnostic ===")
8
+ print(f"Python: {sys.version}")
9
+ print(f"Platform: {sys.platform}")
10
+ print(f"Current directory: {os.getcwd()}")
11
+
12
+ # Check PyTorch
13
+ try:
14
+ import torch
15
+ print(f"\nPyTorch: {torch.__version__}")
16
+ print(f"CUDA available: {torch.cuda.is_available()}")
17
+
18
+ if torch.cuda.is_available():
19
+ print(f"CUDA version: {torch.version.cuda}")
20
+ print(f"GPU count: {torch.cuda.device_count()}")
21
+ for i in range(torch.cuda.device_count()):
22
+ print(f"GPU {i}: {torch.cuda.get_device_name(i)}")
23
+ print(f" Memory: {torch.cuda.get_device_properties(i).total_memory / 1024**3:.2f} GB")
24
+ else:
25
+ print("Running on CPU")
26
+
27
+ # Check environment variables
28
+ print("\nRelevant environment variables:")
29
+ for var in ['CUDA_VISIBLE_DEVICES', 'CUDA_HOME', 'SPACES', 'SPACE_ID']:
30
+ print(f" {var}: {os.environ.get(var, 'Not set')}")
31
+
32
+ except ImportError as e:
33
+ print(f"PyTorch not available: {e}")
34
+
35
+ # Check SpaCy
36
+ print("\n--- SpaCy Configuration ---")
37
+ try:
38
+ import spacy
39
+ print(f"SpaCy: {spacy.__version__}")
40
+
41
+ # Try to enable GPU
42
+ gpu_id = spacy.prefer_gpu()
43
+ print(f"spacy.prefer_gpu(): {gpu_id}")
44
+
45
+ # Check if we can require GPU
46
+ if torch.cuda.is_available():
47
+ try:
48
+ spacy.require_gpu()
49
+ print("spacy.require_gpu(): Success")
50
+ except Exception as e:
51
+ print(f"spacy.require_gpu(): Failed - {e}")
52
+
53
+ except ImportError as e:
54
+ print(f"SpaCy not available: {e}")
55
+ except Exception as e:
56
+ print(f"SpaCy error: {e}")
test_debug_mode_gpu.py CHANGED
@@ -1,86 +1,186 @@
1
  #!/usr/bin/env python3
2
- """
3
- Test script to verify the GPU status display in debug mode works correctly.
4
- This tests the functionality without running the full Streamlit app.
5
- """
6
 
7
- import sys
8
  import os
 
9
 
10
- # Add parent directory to path
11
- sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
12
 
13
- from web_app.debug_utils import show_gpu_status
14
- import streamlit as st
 
15
 
16
- # Mock streamlit components for testing
17
- class MockStreamlit:
18
- """Mock Streamlit for testing without running the actual app."""
19
-
20
- @staticmethod
21
- def write(*args, **kwargs):
22
- print(*args)
23
-
24
- @staticmethod
25
- def columns(n):
26
- return [MockContext()] * n
 
 
 
 
 
 
 
 
 
 
27
 
28
- @staticmethod
29
- def expander(title, expanded=False):
30
- print(f"\n=== {title} ===")
31
- return MockContext()
32
 
33
- @staticmethod
34
- def info(text):
35
- print(f"[INFO] {text}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
 
37
- @staticmethod
38
- def warning(text):
39
- print(f"[WARNING] {text}")
 
 
 
 
 
 
 
 
 
 
 
40
 
41
- @staticmethod
42
- def error(text):
43
- print(f"[ERROR] {text}")
44
 
45
- class session_state:
46
- analyzer = None
47
- parser = None
48
 
49
- class MockContext:
50
- """Mock context manager for with statements."""
51
- def __enter__(self):
52
- return self
 
 
53
 
54
- def __exit__(self, *args):
55
- pass
56
 
57
- def write(self, *args, **kwargs):
58
- print(*args)
59
-
60
- def test_gpu_status_display():
61
- """Test the GPU status display functionality."""
62
- print("Testing GPU Status Display Function")
63
- print("=" * 50)
 
 
 
 
 
 
 
 
 
 
 
 
64
 
65
- # Replace streamlit with mock for testing
66
- import web_app.debug_utils
67
- web_app.debug_utils.st = MockStreamlit()
68
 
69
- # Import the function after mocking
70
- from web_app.debug_utils import show_gpu_status
 
 
 
 
 
 
 
 
71
 
72
- try:
73
- # Test the function
74
- show_gpu_status()
75
- print("\n✅ GPU status display function executed successfully!")
 
76
 
77
- except Exception as e:
78
- print(f"\n❌ Error in GPU status display: {str(e)}")
79
- import traceback
80
- traceback.print_exc()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
 
82
- print("\n" + "=" * 50)
83
- print("Test completed!")
 
 
84
 
85
- if __name__ == "__main__":
86
- test_gpu_status_display()
 
 
 
 
 
 
 
1
  #!/usr/bin/env python3
2
+ """Debug GPU issues in HuggingFace Spaces environment."""
 
 
 
3
 
 
4
  import os
5
+ import sys
6
 
7
+ print("=== Debugging GPU in HuggingFace Spaces ===")
 
8
 
9
+ # Set environment variables BEFORE any imports
10
+ os.environ['CUDA_VISIBLE_DEVICES'] = '0'
11
+ os.environ['SPACY_PREFER_GPU'] = '1'
12
 
13
+ # Now import libraries
14
+ import torch
15
+ import spacy
16
+
17
+ print("\n1. Environment Check:")
18
+ print(f" Platform: {sys.platform}")
19
+ print(f" Python: {sys.version}")
20
+ print(f" Working dir: {os.getcwd()}")
21
+ print(f" CUDA_VISIBLE_DEVICES: {os.environ.get('CUDA_VISIBLE_DEVICES', 'Not set')}")
22
+ print(f" SPACY_PREFER_GPU: {os.environ.get('SPACY_PREFER_GPU', 'Not set')}")
23
+ print(f" SPACES: {os.environ.get('SPACES', 'Not set')}")
24
+
25
+ print("\n2. PyTorch GPU Status:")
26
+ print(f" PyTorch version: {torch.__version__}")
27
+ print(f" CUDA available: {torch.cuda.is_available()}")
28
+
29
+ if torch.cuda.is_available():
30
+ print(f" CUDA version: {torch.version.cuda}")
31
+ print(f" GPU count: {torch.cuda.device_count()}")
32
+ print(f" Current device: {torch.cuda.current_device()}")
33
+ print(f" GPU 0: {torch.cuda.get_device_name(0)}")
34
 
35
+ # Force CUDA initialization
36
+ torch.cuda.init()
37
+ print(" CUDA initialized")
 
38
 
39
+ # Set default device
40
+ torch.cuda.set_device(0)
41
+ print(" Set default CUDA device to 0")
42
+
43
+ print("\n3. SpaCy GPU Configuration:")
44
+ print(f" SpaCy version: {spacy.__version__}")
45
+
46
+ # Try multiple methods to enable GPU
47
+ print("\n Attempting spacy.prefer_gpu()...")
48
+ gpu_id = spacy.prefer_gpu(gpu_id=0)
49
+ print(f" Result: {gpu_id}")
50
+
51
+ if torch.cuda.is_available():
52
+ print("\n Attempting spacy.require_gpu()...")
53
+ try:
54
+ spacy.require_gpu(gpu_id=0)
55
+ print(" ✓ spacy.require_gpu() succeeded")
56
+ except Exception as e:
57
+ print(f" ✗ spacy.require_gpu() failed: {e}")
58
+
59
+ print("\n4. Test Model Loading:")
60
+ try:
61
+ # Try loading a small model first
62
+ print(" Loading en_core_web_md...")
63
+ nlp_md = spacy.load("en_core_web_md")
64
 
65
+ # Check if components are on GPU
66
+ print(" Checking MD model components:")
67
+ for name, component in nlp_md.pipeline:
68
+ device = "Unknown"
69
+ if hasattr(component, 'model'):
70
+ if hasattr(component.model, 'device'):
71
+ device = str(component.model.device)
72
+ elif hasattr(component.model, 'parameters'):
73
+ try:
74
+ param = next(component.model.parameters())
75
+ device = str(param.device)
76
+ except:
77
+ pass
78
+ print(f" {name}: {device}")
79
 
80
+ # Test processing
81
+ doc = nlp_md("Test sentence")
82
+ print(f" MD model processed {len(doc)} tokens")
83
 
84
+ except Exception as e:
85
+ print(f" ✗ MD model failed: {e}")
 
86
 
87
+ print("\n5. Test Transformer Model with GPU:")
88
+ try:
89
+ # Force GPU before loading transformer
90
+ if torch.cuda.is_available():
91
+ torch.cuda.set_device(0)
92
+ os.environ['CUDA_VISIBLE_DEVICES'] = '0'
93
 
94
+ print(" Loading en_core_web_trf with GPU config...")
 
95
 
96
+ # Load with explicit GPU configuration
97
+ config = {
98
+ "nlp": {
99
+ "pipeline": ["transformer", "tagger", "parser", "ner", "lemmatizer"]
100
+ },
101
+ "components": {
102
+ "transformer": {
103
+ "model": {
104
+ "mixed_precision": True,
105
+ "@architectures": "spacy-transformers.TransformerModel.v3",
106
+ "get_spans": {
107
+ "@span_getters": "spacy-transformers.strided_spans.v1",
108
+ "window": 128,
109
+ "stride": 96
110
+ }
111
+ }
112
+ }
113
+ }
114
+ }
115
 
116
+ nlp_trf = spacy.load("en_core_web_trf")
 
 
117
 
118
+ # Force components to GPU
119
+ print(" Forcing transformer components to GPU...")
120
+ for name, component in nlp_trf.pipeline:
121
+ if hasattr(component, 'model'):
122
+ if hasattr(component.model, 'to'):
123
+ try:
124
+ component.model.to('cuda:0')
125
+ print(f" ✓ Moved {name} to GPU")
126
+ except Exception as e:
127
+ print(f" ✗ Failed to move {name}: {e}")
128
 
129
+ # Verify GPU usage
130
+ print("\n Verifying GPU usage:")
131
+ for name, component in nlp_trf.pipeline:
132
+ on_gpu = False
133
+ device_info = "Unknown"
134
 
135
+ if hasattr(component, 'model'):
136
+ # Check parameters
137
+ if hasattr(component.model, 'parameters'):
138
+ try:
139
+ for param in component.model.parameters():
140
+ if param.is_cuda:
141
+ on_gpu = True
142
+ device_info = str(param.device)
143
+ break
144
+ except:
145
+ pass
146
+
147
+ # Check device attribute
148
+ if hasattr(component.model, 'device'):
149
+ device_info = str(component.model.device)
150
+ on_gpu = 'cuda' in device_info
151
+
152
+ status = "✓ GPU" if on_gpu else "✗ CPU"
153
+ print(f" {name}: {status} ({device_info})")
154
+
155
+ # Test processing with timing
156
+ print("\n Testing transformer processing...")
157
+ import time
158
+
159
+ text = "The quick brown fox jumps over the lazy dog. " * 5
160
+ start = time.time()
161
+ doc = nlp_trf(text)
162
+ end = time.time()
163
+
164
+ print(f" ✓ Processed {len(doc)} tokens in {end-start:.2f}s")
165
+
166
+ # Check memory usage
167
+ if torch.cuda.is_available():
168
+ mem_allocated = torch.cuda.memory_allocated(0) / 1024**3
169
+ mem_reserved = torch.cuda.memory_reserved(0) / 1024**3
170
+ print(f"\n GPU Memory:")
171
+ print(f" Allocated: {mem_allocated:.2f} GB")
172
+ print(f" Reserved: {mem_reserved:.2f} GB")
173
 
174
+ except Exception as e:
175
+ print(f" Transformer model failed: {e}")
176
+ import traceback
177
+ traceback.print_exc()
178
 
179
+ print("\n=== Summary ===")
180
+ if torch.cuda.is_available():
181
+ print("✓ CUDA is available")
182
+ print("✓ PyTorch can see GPU")
183
+ print("→ Check if SpaCy models are using GPU above")
184
+ else:
185
+ print("✗ No GPU detected in this environment")
186
+ print("→ This script should be run in HuggingFace Spaces with GPU")
text_analyzer/base_analyzer.py CHANGED
@@ -128,11 +128,17 @@ class BaseAnalyzer:
128
  torch.cuda.set_device(device_id)
129
  os.environ['CUDA_VISIBLE_DEVICES'] = str(device_id)
130
 
131
- # Force spaCy to use GPU
132
- gpu_id = spacy.prefer_gpu(gpu_id=device_id)
133
-
134
- if gpu_id is False:
135
- raise RuntimeError("spacy.prefer_gpu() returned False despite GPU being available")
 
 
 
 
 
 
136
 
137
  logger.info(f"GPU strongly configured for spaCy - using {device_name} (device {device_id})")
138
 
 
128
  torch.cuda.set_device(device_id)
129
  os.environ['CUDA_VISIBLE_DEVICES'] = str(device_id)
130
 
131
+ # Force spaCy to use GPU - use require_gpu for stronger enforcement
132
+ try:
133
+ spacy.require_gpu(gpu_id=device_id)
134
+ logger.info(f"Successfully enforced GPU usage with spacy.require_gpu()")
135
+ except Exception as e:
136
+ # Fallback to prefer_gpu if require_gpu fails
137
+ logger.warning(f"spacy.require_gpu() failed: {e}, trying prefer_gpu()")
138
+ gpu_id = spacy.prefer_gpu(gpu_id=device_id)
139
+
140
+ if gpu_id is False:
141
+ raise RuntimeError("spacy.prefer_gpu() returned False despite GPU being available")
142
 
143
  logger.info(f"GPU strongly configured for spaCy - using {device_name} (device {device_id})")
144
 
web_app/app.py CHANGED
@@ -5,7 +5,6 @@ Provides lexical sophistication analysis and POS/dependency parsing.
5
  Refactored version with modular architecture for better maintainability.
6
  """
7
 
8
- import streamlit as st
9
  import sys
10
  import os
11
  from pathlib import Path
@@ -13,6 +12,11 @@ from pathlib import Path
13
  # Add parent directory to path for imports
14
  sys.path.append(os.path.dirname(os.path.dirname(__file__)))
15
 
 
 
 
 
 
16
  # Import custom modules
17
  from web_app.session_manager import SessionManager
18
  from web_app.components.ui_components import UIComponents
@@ -40,15 +44,11 @@ def main():
40
  st.title("�� Linguistic Data Analysis I - Text Analysis Tools")
41
  st.markdown("*Educational tools for lexical sophistication analysis, POS/dependency parsing, and word frequency visualization*")
42
 
43
- # GPU verification on startup (following HuggingFace docs)
44
- try:
45
- import torch
46
- if torch.cuda.is_available():
47
- logger.info(f"CUDA is available: {torch.cuda.get_device_name(torch.cuda.current_device())}")
48
- else:
49
- logger.info("CUDA not available - running on CPU")
50
- except ImportError:
51
- logger.info("PyTorch not installed - GPU support unavailable")
52
 
53
  # Initialize session state
54
  SessionManager.initialize_session_state()
 
5
  Refactored version with modular architecture for better maintainability.
6
  """
7
 
 
8
  import sys
9
  import os
10
  from pathlib import Path
 
12
  # Add parent directory to path for imports
13
  sys.path.append(os.path.dirname(os.path.dirname(__file__)))
14
 
15
+ # CRITICAL: Initialize GPU BEFORE any SpaCy/model imports
16
+ from web_app.gpu_init import GPU_AVAILABLE
17
+
18
+ import streamlit as st
19
+
20
  # Import custom modules
21
  from web_app.session_manager import SessionManager
22
  from web_app.components.ui_components import UIComponents
 
44
  st.title("�� Linguistic Data Analysis I - Text Analysis Tools")
45
  st.markdown("*Educational tools for lexical sophistication analysis, POS/dependency parsing, and word frequency visualization*")
46
 
47
+ # GPU status is already initialized in gpu_init module
48
+ if GPU_AVAILABLE:
49
+ logger.info("GPU initialization successful - models will use GPU")
50
+ else:
51
+ logger.info("GPU not available - models will use CPU")
 
 
 
 
52
 
53
  # Initialize session state
54
  SessionManager.initialize_session_state()
web_app/gpu_init.py ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ GPU initialization module that must be imported BEFORE any SpaCy modules.
3
+ This ensures GPU is properly configured before SpaCy loads any models.
4
+ """
5
+
6
+ import os
7
+ import logging
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+ def initialize_gpu_environment():
12
+ """
13
+ Initialize GPU environment variables and settings before SpaCy import.
14
+ This function should be called at the very beginning of the application.
15
+ """
16
+ # Set environment variables BEFORE any imports
17
+ os.environ['CUDA_VISIBLE_DEVICES'] = '0'
18
+ os.environ['SPACY_PREFER_GPU'] = '1'
19
+
20
+ try:
21
+ import torch
22
+
23
+ if torch.cuda.is_available():
24
+ # Force CUDA initialization
25
+ torch.cuda.init()
26
+
27
+ # Set default device
28
+ torch.cuda.set_device(0)
29
+
30
+ # Log GPU info
31
+ gpu_name = torch.cuda.get_device_name(0)
32
+ gpu_memory = torch.cuda.get_device_properties(0).total_memory / 1024**3
33
+
34
+ logger.info(f"GPU initialized: {gpu_name} ({gpu_memory:.1f} GB)")
35
+ logger.info(f"CUDA version: {torch.version.cuda}")
36
+ logger.info(f"PyTorch version: {torch.__version__}")
37
+
38
+ # Pre-configure SpaCy for GPU
39
+ import spacy
40
+ try:
41
+ # Try require_gpu first for strong enforcement
42
+ spacy.require_gpu(gpu_id=0)
43
+ logger.info("SpaCy GPU enforced with require_gpu()")
44
+ except Exception as e:
45
+ # Fallback to prefer_gpu
46
+ logger.warning(f"require_gpu() failed: {e}, using prefer_gpu()")
47
+ gpu_id = spacy.prefer_gpu(gpu_id=0)
48
+ if gpu_id is not False:
49
+ logger.info(f"SpaCy GPU enabled with prefer_gpu(): device {gpu_id}")
50
+ else:
51
+ logger.error("SpaCy GPU initialization failed!")
52
+
53
+ return True
54
+ else:
55
+ logger.info("No CUDA device available - running on CPU")
56
+ return False
57
+
58
+ except ImportError:
59
+ logger.info("PyTorch not installed - GPU support unavailable")
60
+ return False
61
+ except Exception as e:
62
+ logger.error(f"GPU initialization error: {e}")
63
+ return False
64
+
65
+ # Initialize GPU on module import
66
+ GPU_AVAILABLE = initialize_gpu_environment()