jesse-tong commited on
Commit
63812ec
·
1 Parent(s): 44c78a2
Files changed (1) hide show
  1. inference_lstm.py +76 -16
inference_lstm.py CHANGED
@@ -7,6 +7,10 @@ from torch.utils.data import DataLoader
7
  import numpy as np
8
  import argparse
9
 
 
 
 
 
10
  if __name__ == "__main__":
11
  parser = argparse.ArgumentParser(description="Document Classification with LSTM")
12
  parser.add_argument("--data_path", type=str, required=True, help="Path to the dataset")
@@ -26,25 +30,13 @@ if __name__ == "__main__":
26
  parser.add_argument("--hidden_dim", type=int, default=256, help="Hidden dimension of LSTM")
27
  parser.add_argument("--num_layers", type=int, default=2, help="Number of LSTM layers")
28
  parser.add_argument("--dropout", type=float, default=0.5, help="Dropout probability")
29
- # Add this argument to your parser
30
- parser.add_argument("--fix_class_mapping", action="store_true",
31
- help="Apply a fix for class mapping issues")
32
  args = parser.parse_args()
33
 
34
  class_names = args.class_names
35
 
36
- # Add this after model loading, before inference
37
- if args.fix_class_mapping:
38
- print("Applying class mapping fix...")
39
-
40
- # Create a class mapping to realign predictions
41
- # This is a permutation map to try various class alignments
42
- # Option 1: Try a complete reversal
43
- class_map = {0:3, 1:2, 2:1, 3:0} # Reverse mapping
44
-
45
- # Print the mapping being used
46
- print(f"Class mapping: {class_map}")
47
- print(f"Class names in new order: {[class_names[class_map[i]] for i in range(len(class_names))]}")
48
 
49
  # Set device
50
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
@@ -66,6 +58,57 @@ if __name__ == "__main__":
66
 
67
  test_loader = DataLoader(test_dataset, batch_size=args.batch_size)
68
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  # Load model
70
  model = DocumentBiLSTM(vocab_size=tokenizer.vocab_size,
71
  embedding_dim=args.embedding_dim,
@@ -135,7 +178,7 @@ if __name__ == "__main__":
135
 
136
 
137
  # In your inference loop, apply the mapping to predictions
138
- if args.fix_class_mapping:
139
  predictions_mapped = torch.tensor([class_map[p.item()] for p in predictions], device=device)
140
  all_predictions = np.append(all_predictions, predictions_mapped.cpu().numpy())
141
  else:
@@ -150,6 +193,23 @@ if __name__ == "__main__":
150
 
151
  batch_count += 1
152
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
  # Print classification report
154
  # Calculate accuracy, F1 score, recall, and precision
155
  accuracy = metrics.accuracy_score(all_labels, all_predictions)
 
7
  import numpy as np
8
  import argparse
9
 
10
+ # Add these imports for mapping optimization
11
+ from itertools import permutations
12
+ import copy
13
+
14
  if __name__ == "__main__":
15
  parser = argparse.ArgumentParser(description="Document Classification with LSTM")
16
  parser.add_argument("--data_path", type=str, required=True, help="Path to the dataset")
 
30
  parser.add_argument("--hidden_dim", type=int, default=256, help="Hidden dimension of LSTM")
31
  parser.add_argument("--num_layers", type=int, default=2, help="Number of LSTM layers")
32
  parser.add_argument("--dropout", type=float, default=0.5, help="Dropout probability")
33
+ # Add after parsing arguments
34
+ parser.add_argument("--optimize_mapping", action="store_true",
35
+ help="Automatically find the optimal class mapping")
36
  args = parser.parse_args()
37
 
38
  class_names = args.class_names
39
 
 
 
 
 
 
 
 
 
 
 
 
 
40
 
41
  # Set device
42
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
 
58
 
59
  test_loader = DataLoader(test_dataset, batch_size=args.batch_size)
60
 
61
+ # Replace the fixed mapping with this dynamic approach
62
+ if args.optimize_mapping:
63
+ print("Finding optimal class mapping...")
64
+
65
+ # Create a small validation set for mapping optimization
66
+ val_size = min(50, len(test_dataset))
67
+ val_indices = np.random.choice(len(test_dataset), val_size, replace=False)
68
+ val_subset = torch.utils.data.Subset(test_dataset, val_indices)
69
+ val_loader = DataLoader(val_subset, batch_size=args.batch_size)
70
+
71
+ # Try all possible class mappings (permutations)
72
+ best_mapping = None
73
+ best_accuracy = 0
74
+
75
+ # Get all possible permutations for the class indices
76
+ all_permutations = list(permutations(range(args.num_classes)))
77
+
78
+ for perm in all_permutations:
79
+ # Create mapping dictionary
80
+ mapping = {i: perm[i] for i in range(args.num_classes)}
81
+
82
+ # Evaluate with this mapping
83
+ val_preds = []
84
+ val_labels = []
85
+
86
+ with torch.no_grad():
87
+ for batch in val_loader:
88
+ input_ids = batch['input_ids'].to(device)
89
+ labels = batch['label'].to(device)
90
+
91
+ outputs = model(input_ids)
92
+ predictions = torch.argmax(outputs, dim=1)
93
+
94
+ # Apply mapping
95
+ mapped_preds = torch.tensor([mapping[p.item()] for p in predictions], device=device)
96
+
97
+ val_preds.extend(mapped_preds.cpu().numpy())
98
+ val_labels.extend(labels.cpu().numpy())
99
+
100
+ # Calculate accuracy
101
+ accuracy = metrics.accuracy_score(val_labels, val_preds)
102
+
103
+ if accuracy > best_accuracy:
104
+ best_accuracy = accuracy
105
+ best_mapping = mapping
106
+
107
+ class_map = best_mapping
108
+ print(f"Optimal class mapping found: {class_map}")
109
+ print(f"Validation accuracy with this mapping: {best_accuracy:.4f}")
110
+ print(f"Class names in new order: {[class_names[class_map[i]] for i in range(len(class_names))]}")
111
+
112
  # Load model
113
  model = DocumentBiLSTM(vocab_size=tokenizer.vocab_size,
114
  embedding_dim=args.embedding_dim,
 
178
 
179
 
180
  # In your inference loop, apply the mapping to predictions
181
+ if args.optimize_mapping:
182
  predictions_mapped = torch.tensor([class_map[p.item()] for p in predictions], device=device)
183
  all_predictions = np.append(all_predictions, predictions_mapped.cpu().numpy())
184
  else:
 
193
 
194
  batch_count += 1
195
 
196
+ # Add before inference
197
+ label_counts = np.bincount(all_labels)
198
+ print(f"Label distribution: {label_counts}")
199
+ print(f"Label percentages: {label_counts/sum(label_counts)}")
200
+
201
+ # Add after inference
202
+ print("\nExample misclassifications:")
203
+ misclassified = np.where(all_predictions != all_labels)[0][:5] # First 5 errors
204
+ for idx in misclassified:
205
+ text = test_dataset.get_text_(idx)['text'][:100] + "..."
206
+ true_class = class_names[all_labels[idx]]
207
+ pred_class = class_names[all_predictions[idx]]
208
+ print(f"Text: {text}")
209
+ print(f"True: {true_class}, Predicted: {pred_class}")
210
+ print("---")
211
+
212
+
213
  # Print classification report
214
  # Calculate accuracy, F1 score, recall, and precision
215
  accuracy = metrics.accuracy_score(all_labels, all_predictions)