hamxaameer commited on
Commit
903b858
·
1 Parent(s): 581b6a9

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +24 -38
app.py CHANGED
@@ -35,47 +35,33 @@ def load_model_from_pickle(pickle_path="best_model.pkl"):
35
  if not os.path.exists(pickle_path):
36
  return f"❌ Model file not found: {pickle_path}\n\nPlease ensure best_model.pkl is uploaded to the HuggingFace Space."
37
 
38
- # Strategy: Use a custom unpickler that forces all CUDA tensors to CPU during deserialization
39
- # This prevents the "Attempting to deserialize object on a CUDA device" error entirely
40
- class CPUUnpickler(pickle.Unpickler):
41
- def find_class(self, module, name):
42
- # Remap torch CUDA classes to CPU equivalents
43
- if module == 'torch.storage' and name.endswith('Storage'):
44
- # Force all storage types to CPU (e.g., cuda:0 -> cpu)
45
- return super().find_class('torch', name.replace('Cuda', '').replace('cuda', ''))
46
- return super().find_class(module, name)
47
-
48
- def persistent_load(self, pid):
49
- # Handle torch storage tuples: ('storage', storage_type, key, location, size)
50
- if isinstance(pid, tuple) and len(pid) > 0 and pid[0] == 'storage':
51
- storage_type, key, location, size = pid[1], pid[2], pid[3], pid[4]
52
- # Force location to CPU regardless of original device
53
- if 'cuda' in str(location).lower():
54
- location = 'cpu'
55
- # Rebuild the storage descriptor with CPU location
56
- return ('storage', storage_type, key, location, size)
57
- return pid
58
 
59
  try:
60
- # Attempt 1: Custom CPU unpickler (most robust for CUDA->CPU)
 
 
 
 
61
  with open(pickle_path, 'rb') as f:
62
- model_package = CPUUnpickler(f).load()
63
- except Exception as e1:
64
- try:
65
- # Attempt 2: torch.load with map_location (standard approach)
66
- model_package = torch.load(pickle_path, map_location=torch.device('cpu'))
67
- except Exception as e2:
68
- try:
69
- # Attempt 3: torch.load with weights_only=False (for older torch versions)
70
- model_package = torch.load(pickle_path, map_location='cpu', weights_only=False)
71
- except Exception as e3:
72
- # All strategies failed - return combined error info
73
- return (f"❌ All loading strategies failed:\n\n"
74
- f"1. Custom CPU unpickler: {str(e1)[:100]}\n"
75
- f"2. torch.load(map_location): {str(e2)[:100]}\n"
76
- f"3. torch.load(weights_only=False): {str(e3)[:100]}\n\n"
77
- f"The pickle may be corrupted or incompatible with this PyTorch version.\n"
78
- f"Try re-saving with: model.to('cpu'); torch.save({{'model': model, ...}}, 'file.pkl')")
79
 
80
  # Success! Model loaded with one of the strategies above
81
  # Handle a few common package shapes.
 
35
  if not os.path.exists(pickle_path):
36
  return f"❌ Model file not found: {pickle_path}\n\nPlease ensure best_model.pkl is uploaded to the HuggingFace Space."
37
 
38
+ # ULTIMATE FIX: Monkey-patch torch.cuda.is_available during unpickling
39
+ # This tricks PyTorch into thinking CUDA is available, then we immediately move to CPU
40
+ import torch.cuda
41
+ import torch.serialization
42
+
43
+ original_is_available = torch.cuda.is_available
44
+ original_device_count = torch.cuda.device_count
45
+
46
+ def fake_is_available():
47
+ return True
48
+
49
+ def fake_device_count():
50
+ return 1
 
 
 
 
 
 
 
51
 
52
  try:
53
+ # Temporarily make PyTorch think CUDA is available
54
+ torch.cuda.is_available = fake_is_available
55
+ torch.cuda.device_count = fake_device_count
56
+
57
+ # Load the pickle (PyTorch will accept CUDA device references now)
58
  with open(pickle_path, 'rb') as f:
59
+ model_package = torch.load(f, map_location=lambda storage, loc: storage.cpu())
60
+
61
+ finally:
62
+ # Always restore original functions
63
+ torch.cuda.is_available = original_is_available
64
+ torch.cuda.device_count = original_device_count
 
 
 
 
 
 
 
 
 
 
 
65
 
66
  # Success! Model loaded with one of the strategies above
67
  # Handle a few common package shapes.