ktejeshnaidu commited on
Commit
9618e1c
·
verified ·
1 Parent(s): 71c1ed1

Update model.py

Browse files
Files changed (1) hide show
  1. model.py +103 -56
model.py CHANGED
@@ -1,66 +1,113 @@
1
  import torch
2
- import torchvision.transforms as transforms
 
 
 
 
3
  import pickle
 
 
 
 
 
4
  import numpy as np
5
- # Import your specific model architecture here if you saved a state_dict!
6
- # from your_network_file import YourCNNClass
7
 
8
- class EmotionPredictor:
9
- def __init__(self, model_path='face_classifier.pth', classes_path='classes.pkl'):
10
- # 1. Device Management: Automatically fall back to CPU for Hugging Face Spaces
11
- self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
12
-
13
- # 2. Weight & Class Caching: Load these ONLY ONCE when the server starts
14
- self.classes = self._load_classes(classes_path)
15
- self.model = self._load_model(model_path)
 
 
 
 
 
 
 
 
 
 
 
 
16
 
17
- # 3. Pre-compiled Tensor Transformations
18
- # (Adjust the Resize dimensions to match what you used in Train_model.ipynb)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  self.transform = transforms.Compose([
20
- transforms.ToPILImage(),
21
- transforms.Resize((224, 224)),
 
22
  transforms.ToTensor(),
23
- transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
 
 
24
  ])
25
 
26
- def _load_classes(self, path):
27
- try:
28
- with open(path, 'rb') as f:
29
- return pickle.load(f)
30
- except Exception as e:
31
- print(f"Warning: Could not load {path}. Defaulting to standard classes. Error: {e}")
32
- return ['Angry', 'Disgust', 'Fear', 'Happy', 'Sad', 'Surprise', 'Neutral']
33
-
34
- def _load_model(self, path):
35
- try:
36
- # OPTION A: If you saved the ENTIRE model in your Jupyter Notebook
37
- model = torch.load(path, map_location=self.device)
38
-
39
- # OPTION B: If you saved ONLY the state_dict (Best Practice)
40
- # Uncomment and use this if Option A throws an architecture error:
41
- # model = YourCNNClass(num_classes=len(self.classes))
42
- # model.load_state_dict(torch.load(path, map_location=self.device))
43
-
44
- model.to(self.device)
45
-
46
- # CRITICAL: Put the model in evaluation mode to disable dropout/batchnorm
47
- model.eval()
48
- return model
49
-
50
- except Exception as e:
51
- raise RuntimeError(f"Failed to load PyTorch model: {e}")
52
-
53
- def predict(self, face_image_rgb):
54
- """
55
- Expects an RGB numpy array of the cropped face from OpenCV.
56
- """
57
- # Apply transforms and add the batch dimension (B, C, H, W)
58
- tensor = self.transform(face_image_rgb).unsqueeze(0).to(self.device)
59
-
60
- # Disable gradient calculation for significantly faster CPU inference
61
- with torch.no_grad():
62
- outputs = self.model(tensor)
63
- _, predicted = torch.max(outputs, 1)
64
-
65
- return self.classes[predicted.item()]
66
 
 
 
1
  import torch
2
+
3
+ import torch.nn as nn
4
+
5
+ import torch.nn.functional as F
6
+
7
  import pickle
8
+
9
+ from torchvision import transforms
10
+
11
+
12
+
13
  import numpy as np
 
 
14
 
15
+ from PIL import Image
16
+
17
+
18
+
19
+
20
+
21
+ class FaceClassifier(nn.Module):
22
+
23
+ def __init__(self, num_classes):
24
+
25
+ super().__init__()
26
+
27
+ self.conv1 = nn.Conv2d(3, 32, 3, padding=1)
28
+
29
+ self.conv2 = nn.Conv2d(32, 64, 3, padding=1)
30
+
31
+ self.conv3 = nn.Conv2d(64, 128, 3, padding=1)
32
+
33
+ self.pool = nn.MaxPool2d(2, 2)
34
+
35
 
36
+
37
+ self.dropout = nn.Dropout(0.1)
38
+
39
+ self.fc1 = nn.Linear(128 * 16 * 16, 512)
40
+
41
+ self.fc2 = nn.Linear(512, num_classes)
42
+
43
+
44
+
45
+ def forward(self, x):
46
+
47
+ x = self.pool(F.relu(self.conv1(x)))
48
+
49
+ x = self.pool(F.relu(self.conv2(x)))
50
+
51
+ x = self.pool(F.relu(self.conv3(x)))
52
+
53
+ x = x.view(-1, 128 * 16 * 16)
54
+
55
+ x = self.dropout(F.relu(self.fc1(x)))
56
+
57
+ x = self.fc2(x)
58
+
59
+ return x
60
+
61
+
62
+
63
+
64
+
65
+
66
+
67
+ class EmotionPredictor:
68
+
69
+ def __init__(self):
70
+
71
+ self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
72
+
73
+
74
+
75
+ with open("classes.pkl", "rb") as f:
76
+
77
+ self.classes = pickle.load(f)
78
+
79
+
80
+
81
+ self.model = FaceClassifier(len(self.classes))
82
+
83
+ self.model.load_state_dict(
84
+
85
+ torch.load("face_classifier.pth", map_location=self.device)
86
+
87
+ )
88
+
89
+ self.model.to(self.device).eval()
90
+
91
+
92
+
93
  self.transform = transforms.Compose([
94
+
95
+ transforms.Resize((128, 128)),
96
+
97
  transforms.ToTensor(),
98
+
99
+ transforms.Normalize((0.5,), (0.5,))
100
+
101
  ])
102
 
103
+ @torch.inference_mode()
104
+
105
+ def predict(self, image_np: np.ndarray) -> str:
106
+
107
+ img = Image.fromarray(image_np)
108
+
109
+ tensor = self.transform(img).unsqueeze(0).to(self.device)
110
+
111
+ output = self.model(tensor)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
 
113
+ return self.classes[output.argmax(1).item()]