TinyDecide / python /README.md
TheREZOR's picture
Python, Rust and ESP32 engines, shared conformance set, promo video
f2878d0 verified
|
Raw History Blame Contribute Delete
3.69 kB
# TinyDecide for Python
The TinyDecide engine in Python. It needs only numpy. On the shared conformance set it gives the
same token ids, picks and spans as the JavaScript engine, and its probabilities differ by about 1e-6.
## Install
Install it from a downloaded copy of the model repo.
```sh
hf download TheREZOR/TinyDecide --local-dir TinyDecide --exclude "assets/*"
pip install ./TinyDecide/python # add [hub] for TinyDecide.from_pretrained()
```
The package is not on PyPI yet.
## Use
```python
from tinydecide import TinyDecide
model = TinyDecide.load("TinyDecide") # folder with meta.json + model.bin
# model = TinyDecide.from_pretrained() # downloads from the Hub (needs huggingface_hub)
# model = TinyDecide.from_pretrained(subfolder="full") # the 13.8M build
r = model.answer(
"Book a table for 4 at an Italian place near the station on Friday at 7:30",
[
{"type": "choice", "text": "Which app should handle this?",
"options": ["reminders", "music", "calendar", "restaurants", "weather"]},
{"type": "noul", "text": "The message is urgent."},
{"type": "score", "text": "How positive is the tone?", "options": ["negative", "neutral", "positive"]},
{"type": "span", "text": "Extract the time."},
],
)
app, urgent, tone, time = r["answers"]
app["pick"], urgent["p"], tone["score"], time["text"] # 3, 0.22, 0.52, "7:30"
```
`python examples/quickstart.py` runs this example.
## Answers
| type | fields |
|---|---|
| `choice` | `probs` (one per option), `pick`, `confidence` (1 - normalised entropy), `qvec`, `z0` |
| `score` | the same, plus `score` from 0 (first level) to 1 (last level) |
| `noul` | `p`, the probability the statement is true; `qvec`, `z0` |
| `span` | `text`, `p_present`, `p_span`, `tok` (first and last state token), `char` |
`char` is a `[start, end)` pair of Python string indices into the message, so
`message[start:end]` is the span before trimming. The JavaScript engine counts UTF-16 units instead.
The two agree unless the message has characters outside the BMP, such as emoji.
The result also has `tokens`, `ids`, `ms` and `truncated`. The engine reads the first 127 tokens of a
message and sets `truncated` when it cuts the rest. A question longer than 192 tokens raises
`ValueError`, and so does a choice or score question without 2 to 32 options.
## Corrections
Store the answer's `qvec` and `z0` under the option a person says is right, and pass them back as
`protos`. Nothing retrains the model. Also keep the mean `qvec` of every message asked with the
question, and pass it as `center`. Without it, the centre is the mean of the examples, and a single
example has no effect.
```python
import numpy as np
from tinydecide import make_protos
q = {"type": "choice", "text": "What kind of note is this?", "options": ["shopping", "todo", "event"]}
lists, seen = [[], [], []], [] # examples per option (noul: [false, true])
for msg, k in [("buy oat milk", 0), ("call the plumber", 1), ("dentist thursday 4pm", 2)]:
a = model.answer(msg, [q])["answers"][0]
seen.append(a["qvec"])
lists[k].append({"v": a["qvec"], "z": a["z0"]}) # a person said option k was right
protos = make_protos(q["type"], lists, model.meta["beta"], center=np.mean(seen, axis=0))
model.answer("get coffee beans", [q], protos=[protos])
```
## Test
```sh
python tests/test_conformance.py # inside the downloaded repo: checks model.bin and full/
python tests/test_conformance.py <dir with meta.json + model.bin> <full build dir> <conformance dir>
```
This checks the engine against the JavaScript reference outputs in `sdk/conformance`.