Tonic commited on
Commit
acf9798
·
unverified ·
1 Parent(s): 89a0834

improve text inference

Browse files
Files changed (2) hide show
  1. submission_script.py +92 -0
  2. tasks/text.py +98 -97
submission_script.py ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import json
3
+ from pprint import pprint
4
+ import time
5
+ import sys
6
+
7
+ def evaluate_text_model(space_url: str, max_retries=3, retry_delay=5):
8
+ """
9
+ Evaluate a text classification model through its API endpoint
10
+ """
11
+ params = {
12
+ "dataset_name": "QuotaClimat/frugalaichallenge-text-train",
13
+ "test_size": 0.2,
14
+ "test_seed": 42,
15
+ }
16
+
17
+ # Construct API URL
18
+ if "localhost" in space_url:
19
+ api_url = f"{space_url}/text"
20
+ else:
21
+ api_url = f"https://{space_url.replace('/', '-')}.hf.space/text"
22
+
23
+ headers = {
24
+ 'Content-Type': 'application/json',
25
+ 'Accept': 'application/json'
26
+ }
27
+
28
+ for attempt in range(max_retries):
29
+ try:
30
+ print(f"\nAttempt {attempt + 1} of {max_retries}")
31
+ print(f"Making request to: {api_url}")
32
+
33
+ # Health check
34
+ health_url = f"https://{space_url.replace('/', '-')}.hf.space/health"
35
+ health_response = requests.get(health_url, timeout=30)
36
+
37
+ if health_response.status_code != 200:
38
+ print(f"Space not ready (status: {health_response.status_code})")
39
+ time.sleep(retry_delay)
40
+ continue
41
+
42
+ # Make API call
43
+ response = requests.post(
44
+ api_url,
45
+ json=params,
46
+ headers=headers,
47
+ timeout=300
48
+ )
49
+
50
+ if response.status_code == 200:
51
+ return response.json()
52
+ else:
53
+ print(f"Error: Status {response.status_code}")
54
+ print(f"Response: {response.text}")
55
+ time.sleep(retry_delay)
56
+
57
+ except requests.exceptions.RequestException as e:
58
+ print(f"Request error: {str(e)}")
59
+ if attempt < max_retries - 1:
60
+ time.sleep(retry_delay)
61
+ except Exception as e:
62
+ print(f"Unexpected error: {str(e)}")
63
+ if attempt < max_retries - 1:
64
+ time.sleep(retry_delay)
65
+
66
+ return None
67
+
68
+ def main():
69
+ # Space URL
70
+ space_url = "Tonic/frugal-ai-submission-template"
71
+
72
+ print("\nStarting model evaluation...")
73
+ results = evaluate_text_model(space_url)
74
+
75
+ if results:
76
+ print("\nEvaluation Results:")
77
+ print("-" * 50)
78
+ print(f"Accuracy: {results.get('accuracy', 'N/A'):.4f}")
79
+ print(f"Energy (Wh): {results.get('energy_consumed_wh', 'N/A'):.6f}")
80
+ print(f"Emissions (gCO2eq): {results.get('emissions_gco2eq', 'N/A'):.6f}")
81
+ print("\nFull Results:")
82
+ pprint(results)
83
+ else:
84
+ print("\nEvaluation failed!")
85
+ print("Troubleshooting:")
86
+ print(f"1. Check space status: https://{space_url.replace('/', '-')}.hf.space")
87
+ print("2. Verify API implementation")
88
+ print("3. Try again later")
89
+ sys.exit(1)
90
+
91
+ if __name__ == "__main__":
92
+ main()
tasks/text.py CHANGED
@@ -2,7 +2,6 @@ from fastapi import APIRouter
2
  from datetime import datetime
3
  from datasets import load_dataset
4
  from sklearn.metrics import accuracy_score
5
- import random
6
  import torch
7
  from transformers import AutoTokenizer, AutoModelForSequenceClassification
8
  from torch.utils.data import Dataset, DataLoader
@@ -12,23 +11,45 @@ from .utils.emissions import tracker, clean_emissions_data, get_space_info
12
 
13
  router = APIRouter()
14
 
15
- DESCRIPTION = "Random Baseline"
16
  ROUTE = "/text"
17
 
18
- @router.post(ROUTE, tags=["Text Task"],
19
- description=DESCRIPTION)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  async def evaluate_text(request: TextEvaluationRequest):
21
  """
22
  Evaluate text classification for climate disinformation detection.
23
-
24
- Current Model: Random Baseline
25
- - Makes random predictions from the label space (0-7)
26
- - Used as a baseline for comparison
27
  """
28
- # Get space info
29
  username, space_url = get_space_info()
30
 
31
- # Define the label mapping
32
  LABEL_MAPPING = {
33
  "0_not_relevant": 0,
34
  "1_not_happening": 1,
@@ -40,99 +61,79 @@ async def evaluate_text(request: TextEvaluationRequest):
40
  "7_fossil_fuels_needed": 7
41
  }
42
 
43
- # Load and prepare the dataset
44
  dataset = load_dataset(request.dataset_name)
45
-
46
  # Convert string labels to integers
47
  dataset = dataset.map(lambda x: {"label": LABEL_MAPPING[x["label"]]})
48
-
49
- # Split dataset
50
- train_test = dataset["train"]
51
  test_dataset = dataset["test"]
52
 
53
  # Start tracking emissions
54
  tracker.start()
55
- tracker.start_task("inference")
56
-
57
- # Load the model and tokenizer
58
- model_name = "Tonic/climate-guard-toxic-agent"
59
- tokenizer = AutoTokenizer.from_pretrained(model_name)
60
- model = AutoModelForSequenceClassification.from_pretrained(model_name)
61
-
62
- class TextDataset(Dataset):
63
- def __init__(self, texts, labels, tokenizer, max_len=128):
64
- self.texts = texts
65
- self.labels = labels
66
- self.tokenizer = tokenizer
67
- self.max_len = max_len
68
-
69
- def __len__(self):
70
- return len(self.texts)
71
-
72
- def __getitem__(self, idx):
73
- text = self.texts[idx]
74
- label = self.labels[idx]
75
- encodings = self.tokenizer(
76
- text,
77
- max_length=self.max_len,
78
- padding='max_length',
79
- truncation=True,
80
- return_tensors="pt"
81
- )
82
- return {
83
- 'input_ids': encodings['input_ids'].squeeze(0),
84
- 'attention_mask': encodings['attention_mask'].squeeze(0),
85
- 'labels': torch.tensor(label, dtype=torch.long)
86
- }
87
-
88
- # Create dataset and dataloader
89
- test_dataset = TextDataset(texts, labels, tokenizer)
90
- test_loader = DataLoader(test_dataset, batch_size=16)
91
-
92
- # Model inference
93
- model.eval()
94
- predictions = []
95
- ground_truth = []
96
- DEVICE = 'cpu'
97
- with torch.no_grad():
98
- for batch in test_loader:
99
- input_ids = batch['input_ids'].to(DEVICE)
100
- attention_mask = batch['attention_mask'].to(DEVICE)
101
- labels = batch['labels'].to(DEVICE)
102
-
103
- outputs = model(input_ids=input_ids, attention_mask=attention_mask)
104
- _, predicted = torch.max(outputs.logits, 1)
105
-
106
- predictions.extend(predicted.cpu().numpy())
107
- ground_truth.extend(labels.cpu().numpy())
108
-
109
- #--------------------------------------------------------------------------------------------
110
- # YOUR MODEL INFERENCE STOPS HERE
111
- #--------------------------------------------------------------------------------------------
112
-
113
 
114
- # Stop tracking emissions
115
- emissions_data = tracker.stop_task()
116
-
117
- # Calculate accuracy
118
- accuracy = accuracy_score(ground_truth, predictions)
119
-
120
- # Prepare results dictionary
121
- results = {
122
- "username": username,
123
- "space_url": space_url,
124
- "submission_timestamp": datetime.now().isoformat(),
125
- "model_description": DESCRIPTION,
126
- "accuracy": float(accuracy),
127
- "energy_consumed_wh": emissions_data.energy_consumed * 1000,
128
- "emissions_gco2eq": emissions_data.emissions * 1000,
129
- "emissions_data": clean_emissions_data(emissions_data),
130
- "api_route": ROUTE,
131
- "dataset_config": {
132
- "dataset_name": request.dataset_name,
133
- "test_size": request.test_size,
134
- "test_seed": request.test_seed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
135
  }
136
- }
137
-
138
- return results
 
 
 
 
2
  from datetime import datetime
3
  from datasets import load_dataset
4
  from sklearn.metrics import accuracy_score
 
5
  import torch
6
  from transformers import AutoTokenizer, AutoModelForSequenceClassification
7
  from torch.utils.data import Dataset, DataLoader
 
11
 
12
  router = APIRouter()
13
 
14
+ DESCRIPTION = "Climate Guard Toxic Agent Model"
15
  ROUTE = "/text"
16
 
17
+ class TextDataset(Dataset):
18
+ def __init__(self, texts, labels, tokenizer, max_len=128):
19
+ self.texts = texts
20
+ self.labels = labels
21
+ self.tokenizer = tokenizer
22
+ self.max_len = max_len
23
+
24
+ def __len__(self):
25
+ return len(self.texts)
26
+
27
+ def __getitem__(self, idx):
28
+ text = str(self.texts[idx])
29
+ label = self.labels[idx]
30
+
31
+ encoding = self.tokenizer(
32
+ text,
33
+ max_length=self.max_len,
34
+ padding='max_length',
35
+ truncation=True,
36
+ return_tensors="pt"
37
+ )
38
+
39
+ return {
40
+ 'input_ids': encoding['input_ids'].squeeze(0),
41
+ 'attention_mask': encoding['attention_mask'].squeeze(0),
42
+ 'labels': torch.tensor(label, dtype=torch.long)
43
+ }
44
+
45
+ @router.post(ROUTE, tags=["Text Task"], description=DESCRIPTION)
46
  async def evaluate_text(request: TextEvaluationRequest):
47
  """
48
  Evaluate text classification for climate disinformation detection.
 
 
 
 
49
  """
 
50
  username, space_url = get_space_info()
51
 
52
+ # Label mapping
53
  LABEL_MAPPING = {
54
  "0_not_relevant": 0,
55
  "1_not_happening": 1,
 
61
  "7_fossil_fuels_needed": 7
62
  }
63
 
64
+ # Load dataset
65
  dataset = load_dataset(request.dataset_name)
66
+
67
  # Convert string labels to integers
68
  dataset = dataset.map(lambda x: {"label": LABEL_MAPPING[x["label"]]})
69
+
70
+ # Get test dataset
 
71
  test_dataset = dataset["test"]
72
 
73
  # Start tracking emissions
74
  tracker.start()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
 
76
+ try:
77
+ # Load model and tokenizer
78
+ model_name = "Tonic/climate-guard-toxic-agent"
79
+ tokenizer = AutoTokenizer.from_pretrained(model_name)
80
+ model = AutoModelForSequenceClassification.from_pretrained(model_name)
81
+
82
+ # Prepare dataset
83
+ test_data = TextDataset(
84
+ texts=test_dataset["text"],
85
+ labels=test_dataset["label"],
86
+ tokenizer=tokenizer
87
+ )
88
+
89
+ test_loader = DataLoader(test_data, batch_size=16)
90
+
91
+ # Model inference
92
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
93
+ model = model.to(device)
94
+ model.eval()
95
+
96
+ predictions = []
97
+ ground_truth = []
98
+
99
+ with torch.no_grad():
100
+ for batch in test_loader:
101
+ input_ids = batch['input_ids'].to(device)
102
+ attention_mask = batch['attention_mask'].to(device)
103
+ labels = batch['labels'].to(device)
104
+
105
+ outputs = model(input_ids=input_ids, attention_mask=attention_mask)
106
+ _, predicted = torch.max(outputs.logits, 1)
107
+
108
+ predictions.extend(predicted.cpu().numpy())
109
+ ground_truth.extend(labels.cpu().numpy())
110
+
111
+ # Calculate accuracy
112
+ accuracy = accuracy_score(ground_truth, predictions)
113
+
114
+ # Stop tracking emissions
115
+ emissions_data = tracker.stop()
116
+
117
+ # Prepare results
118
+ results = {
119
+ "username": username,
120
+ "space_url": space_url,
121
+ "submission_timestamp": datetime.now().isoformat(),
122
+ "model_description": DESCRIPTION,
123
+ "accuracy": float(accuracy),
124
+ "energy_consumed_wh": emissions_data.energy_consumed * 1000,
125
+ "emissions_gco2eq": emissions_data.emissions * 1000,
126
+ "emissions_data": clean_emissions_data(emissions_data),
127
+ "api_route": ROUTE,
128
+ "dataset_config": {
129
+ "dataset_name": request.dataset_name,
130
+ "test_size": request.test_size,
131
+ "test_seed": request.test_seed
132
+ }
133
  }
134
+
135
+ return results
136
+
137
+ except Exception as e:
138
+ tracker.stop()
139
+ raise e