Isaiah6b commited on
Commit
1bb7727
·
verified ·
1 Parent(s): 64bd146

Deploy space_sentiment from monorepo

Browse files
Files changed (6) hide show
  1. README.md +17 -7
  2. app.py +49 -0
  3. preprocess.py +43 -0
  4. requirements.txt +3 -0
  5. sentiment.onnx +3 -0
  6. vocab.json +29 -0
README.md CHANGED
@@ -1,13 +1,23 @@
1
  ---
2
- title: Sentiment
3
- emoji: 😻
4
- colorFrom: pink
5
- colorTo: blue
6
  sdk: gradio
7
- sdk_version: 6.15.2
8
- python_version: '3.13'
9
  app_file: app.py
10
  pinned: false
 
11
  ---
12
 
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: ONNX Sentiment Demo
3
+ emoji: 💬
4
+ colorFrom: yellow
5
+ colorTo: red
6
  sdk: gradio
7
+ sdk_version: 5.23.1
8
+ python_version: "3.12"
9
  app_file: app.py
10
  pinned: false
11
+ license: mit
12
  ---
13
 
14
+ # ONNX Sentiment Demo
15
+
16
+ Binary sentiment classifier trained **from scratch** in PyTorch (bag-of-words + linear layer), exported to ONNX, served with **ONNX Runtime**.
17
+
18
+ Built from `spaces/space_sentiment/` in the monorepo. Retrain and re-export with:
19
+
20
+ ```bash
21
+ python train.py
22
+ python export_onnx.py
23
+ ```
app.py ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Gradio demo: bag-of-words sentiment via ONNX Runtime."""
2
+
3
+ import json
4
+ from pathlib import Path
5
+
6
+ import gradio as gr
7
+ import numpy as np
8
+ import onnxruntime as ort
9
+
10
+ from preprocess import text_to_bow
11
+
12
+ VOCAB_PATH = Path(__file__).resolve().parent / "vocab.json"
13
+ vocab_data = json.loads(VOCAB_PATH.read_text())
14
+ VOCAB: list[str] = vocab_data["vocab"]
15
+ LABELS: list[str] = vocab_data["labels"]
16
+
17
+ session = ort.InferenceSession("sentiment.onnx")
18
+
19
+
20
+ def predict(text: str) -> dict[str, float]:
21
+ if not text.strip():
22
+ return {label: 0.0 for label in LABELS}
23
+
24
+ bow = text_to_bow(text, VOCAB)[np.newaxis, :]
25
+ logits = session.run(None, {"bow": bow})[0][0]
26
+ exp_logits = np.exp(logits - logits.max())
27
+ probs = exp_logits / exp_logits.sum()
28
+
29
+ return {label: float(prob) for label, prob in zip(LABELS, probs)}
30
+
31
+
32
+ demo = gr.Interface(
33
+ fn=predict,
34
+ inputs=gr.Textbox(label="Text", placeholder="I love this product"),
35
+ outputs=gr.Label(num_top_classes=2, label="Sentiment"),
36
+ title="ONNX Sentiment Demo",
37
+ description=(
38
+ "Tiny bag-of-words classifier trained from scratch in PyTorch "
39
+ "(no pretrained model). Exported to ONNX for inference."
40
+ ),
41
+ examples=[
42
+ ["I love this"],
43
+ ["This is awful"],
44
+ ["Amazing product"],
45
+ ["So disappointed"],
46
+ ],
47
+ )
48
+
49
+ demo.launch()
preprocess.py ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Bag-of-words preprocessing for tiny sentiment classifier."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import re
7
+ from pathlib import Path
8
+
9
+ import numpy as np
10
+
11
+ VOCAB_PATH = Path(__file__).resolve().parent / "vocab.json"
12
+
13
+ TOKEN_PATTERN = re.compile(r"[a-z]+")
14
+
15
+
16
+ def tokenize(text: str) -> list[str]:
17
+ return TOKEN_PATTERN.findall(text.lower())
18
+
19
+
20
+ def build_vocab(texts: list[str]) -> list[str]:
21
+ words: set[str] = set()
22
+ for text in texts:
23
+ words.update(tokenize(text))
24
+ return sorted(words)
25
+
26
+
27
+ def text_to_bow(text: str, vocab: list[str]) -> np.ndarray:
28
+ word_to_idx = {word: idx for idx, word in enumerate(vocab)}
29
+ bow = np.zeros(len(vocab), dtype=np.float32)
30
+ for token in tokenize(text):
31
+ idx = word_to_idx.get(token)
32
+ if idx is not None:
33
+ bow[idx] = 1.0
34
+ return bow
35
+
36
+
37
+ def save_vocab(vocab: list[str], labels: list[str]) -> None:
38
+ VOCAB_PATH.write_text(json.dumps({"vocab": vocab, "labels": labels}, indent=2))
39
+
40
+
41
+ def load_vocab() -> tuple[list[str], list[str]]:
42
+ data = json.loads(VOCAB_PATH.read_text())
43
+ return data["vocab"], data["labels"]
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ # Runtime deps for the HF Space (gradio is provided by the Space SDK).
2
+ onnxruntime>=1.18.0
3
+ numpy>=1.26.0
sentiment.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:03b106867260d989f12eab99a18bfd962b77745f65041b7a042f16648dec2108
3
+ size 571
vocab.json ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "vocab": [
3
+ "amazing",
4
+ "awful",
5
+ "best",
6
+ "day",
7
+ "disappointed",
8
+ "ever",
9
+ "experience",
10
+ "great",
11
+ "happy",
12
+ "hate",
13
+ "i",
14
+ "is",
15
+ "it",
16
+ "love",
17
+ "product",
18
+ "purchase",
19
+ "so",
20
+ "terrible",
21
+ "this",
22
+ "with",
23
+ "worst"
24
+ ],
25
+ "labels": [
26
+ "negative",
27
+ "positive"
28
+ ]
29
+ }