CadenShokat commited on
Commit
bef81d1
·
verified ·
1 Parent(s): 87a2111

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +47 -11
app.py CHANGED
@@ -1,5 +1,6 @@
1
  from fastapi import FastAPI, Query
2
  from pydantic import BaseModel
 
3
  from transformers import AutoTokenizer, AutoModelForSequenceClassification, pipeline
4
  import math
5
 
@@ -18,17 +19,35 @@ def health():
18
  return {"status": "healthy", "model": loaded_model_id}
19
 
20
  def load_pipeline():
 
 
 
 
 
 
21
  global clf, loaded_model_id
22
  if clf is not None:
23
  return clf
 
24
  for model_id in (PRIMARY_MODEL, FALLBACK_MODEL):
25
  try:
26
- tok = AutoTokenizer.from_pretrained(model_id)
27
- mdl = AutoModelForSequenceClassification.from_pretrained(model_id)
 
 
 
 
28
  loaded_model_id = model_id
29
- return pipeline("text-classification", model=mdl, tokenizer=tok, return_all_scores=True, truncation=True)
 
 
 
 
 
 
30
  except Exception as e:
31
  print(f"Failed to load {model_id}: {e}")
 
32
  raise RuntimeError("No sentiment model could be loaded")
33
 
34
  def compute_score(pos: float, neg: float, neu: float, mode: str) -> float:
@@ -39,9 +58,10 @@ def compute_score(pos: float, neg: float, neu: float, mode: str) -> float:
39
  return pos - neg
40
  elif mode == "logit": # optional slightly squashed
41
  # difference of logits, then tanh to clamp to [-1,1]
42
- lp = math.log(max(1e-9, pos)) - math.log(max(1e-9, 1-pos))
43
- ln = math.log(max(1e-9, neg)) - math.log(max(1e-9, 1-neg))
44
- return math.tanh((lp - ln) / 4.0)
 
45
  else:
46
  return pos - neg
47
 
@@ -70,7 +90,7 @@ def scores_to_label(scores, mode: str, binary_hint: bool | None, min_conf: float
70
  detected_binary = (neu == 0.0)
71
 
72
  is_binary = detected_binary if binary_hint is None else bool(binary_hint)
73
- if is_binary:
74
  neu = 0.0
75
 
76
  score = compute_score(pos, neg, neu, mode)
@@ -94,13 +114,29 @@ def scores_to_label(scores, mode: str, binary_hint: bool | None, min_conf: float
94
  @app.post("/predict")
95
  def predict(
96
  payload: Payload,
97
- mode: str = Query("raw", pattern="^(raw|debias|logit)$"),
98
- min_conf: float = Query(0.60, ge=0.0, le=1.0),
99
- neutral_zone: float = Query(0.20, ge=0.0, le=1.0)
100
  ):
 
 
 
 
101
  clf = load_pipeline()
102
  texts = payload.sentences or []
103
- outs = clf(texts, top_k=None)
 
 
 
 
 
 
 
 
 
 
 
 
104
  binary_hint = (loaded_model_id == FALLBACK_MODEL)
105
  results = [scores_to_label(s, mode, binary_hint, min_conf, neutral_zone) for s in outs]
106
  return {"model": loaded_model_id, "results": results}
 
1
  from fastapi import FastAPI, Query
2
  from pydantic import BaseModel
3
+ from typing import Literal
4
  from transformers import AutoTokenizer, AutoModelForSequenceClassification, pipeline
5
  import math
6
 
 
19
  return {"status": "healthy", "model": loaded_model_id}
20
 
21
  def load_pipeline():
22
+ """
23
+ Robust loader:
24
+ - Avoid meta-tensor issue by forcing low_cpu_mem_usage=False
25
+ - No device_map; keep on CPU
26
+ - Cache the pipeline in the global `clf`
27
+ """
28
  global clf, loaded_model_id
29
  if clf is not None:
30
  return clf
31
+
32
  for model_id in (PRIMARY_MODEL, FALLBACK_MODEL):
33
  try:
34
+ tok = AutoTokenizer.from_pretrained(model_id) # use_fast default is fine
35
+ mdl = AutoModelForSequenceClassification.from_pretrained(
36
+ model_id,
37
+ low_cpu_mem_usage=False, # <-- important to avoid meta tensors
38
+ trust_remote_code=False
39
+ )
40
  loaded_model_id = model_id
41
+ clf = pipeline(
42
+ "text-classification",
43
+ model=mdl,
44
+ tokenizer=tok,
45
+ device=-1 # CPU
46
+ )
47
+ return clf
48
  except Exception as e:
49
  print(f"Failed to load {model_id}: {e}")
50
+
51
  raise RuntimeError("No sentiment model could be loaded")
52
 
53
  def compute_score(pos: float, neg: float, neu: float, mode: str) -> float:
 
58
  return pos - neg
59
  elif mode == "logit": # optional slightly squashed
60
  # difference of logits, then tanh to clamp to [-1,1]
61
+ import math as _m
62
+ lp = _m.log(max(1e-9, pos)) - _m.log(max(1e-9, 1-pos))
63
+ ln = _m.log(max(1e-9, neg)) - _m.log(max(1e-9, 1-neg))
64
+ return _m.tanh((lp - ln) / 4.0)
65
  else:
66
  return pos - neg
67
 
 
90
  detected_binary = (neu == 0.0)
91
 
92
  is_binary = detected_binary if binary_hint is None else bool(binary_hint)
93
+ if is_binary:
94
  neu = 0.0
95
 
96
  score = compute_score(pos, neg, neu, mode)
 
114
  @app.post("/predict")
115
  def predict(
116
  payload: Payload,
117
+ mode: Literal["raw","debias","logit"] = Query("raw"),
118
+ min_conf: float = Query(0.60, ge=0.0, le=1.0),
119
+ neutral_zone: float = Query(0.20, ge=0.0, le=1.0)
120
  ):
121
+ """
122
+ - Use top_k=None (replacement for deprecated return_all_scores=True)
123
+ - Force truncation/padding/max_length to avoid 631>514 crashes
124
+ """
125
  clf = load_pipeline()
126
  texts = payload.sentences or []
127
+
128
+ outs = clf(
129
+ texts,
130
+ top_k=None, # replaces return_all_scores=True
131
+ truncation=True, # <-- important for long inputs
132
+ padding=True,
133
+ max_length=512
134
+ )
135
+
136
+ # If a single string was passed, HF may return a single item; normalize to list
137
+ if isinstance(outs, dict) or (outs and isinstance(outs[0], dict)):
138
+ outs = [outs] # ensure list[list[dict]]
139
+
140
  binary_hint = (loaded_model_id == FALLBACK_MODEL)
141
  results = [scores_to_label(s, mode, binary_hint, min_conf, neutral_zone) for s in outs]
142
  return {"model": loaded_model_id, "results": results}