zeechimp commited on
Commit
ee93643
·
verified ·
1 Parent(s): 5588683

Create hv_intent.py

Browse files
Files changed (1) hide show
  1. hv_intent.py +125 -0
hv_intent.py ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ hv_intent.py
3
+
4
+ Hypervector intent router for 5-class classification.
5
+
6
+ A 512-byte hypervector memory plus a 15 KB evolved character codebook.
7
+ Inference is one Hamming comparison per intent.
8
+
9
+ Usage:
10
+ from hv_intent import HVIntentRouter
11
+
12
+ router = HVIntentRouter.from_pretrained(".")
13
+ router.predict("what is the weather today")
14
+ # -> "weather"
15
+
16
+ Author: <your name>
17
+ License: apache-2.0
18
+ """
19
+
20
+ import json
21
+ import numpy as np
22
+ from pathlib import Path
23
+
24
+
25
+ VOCAB = "abcdefghijklmnopqrstuvwxyz"
26
+ D_DEFAULT = 4096
27
+
28
+
29
+ class HVIntentRouter:
30
+ def __init__(self, vocab_codebook, intent_codebook, memory, labels):
31
+ self.vocab_codebook = vocab_codebook # (V, D) int8 ±1
32
+ self.intent_codebook = intent_codebook # (C, D) int8 ±1
33
+ self.memory = memory # (D,) int8 ±1
34
+ self.labels = list(labels)
35
+ self.vocab = VOCAB
36
+ self.char_to_idx = {c: i for i, c in enumerate(VOCAB)}
37
+ self.D = vocab_codebook.shape[1]
38
+
39
+ # -----------------------------------------------------------------------
40
+ # Encoding
41
+ # -----------------------------------------------------------------------
42
+
43
+ def encode(self, phrase):
44
+ """Sum-bundle character hypervectors, majority-vote on ties."""
45
+ indices = [self.char_to_idx[c] for c in phrase.lower() if c in self.char_to_idx]
46
+ if not indices:
47
+ return np.zeros(self.D, dtype=np.int8)
48
+ stacked = self.vocab_codebook[indices].astype(np.int32)
49
+ s = stacked.sum(axis=0)
50
+ return np.where(s >= 0, np.int8(1), np.int8(-1))
51
+
52
+ # -----------------------------------------------------------------------
53
+ # Inference
54
+ # -----------------------------------------------------------------------
55
+
56
+ def predict_proba(self, phrase):
57
+ """Return a softmax over intent similarities."""
58
+ phrase_hv = self.encode(phrase).astype(np.int32)
59
+ retrieved = self.memory.astype(np.int32) * phrase_hv
60
+ sims = (retrieved.astype(np.float32) @
61
+ self.intent_codebook.astype(np.float32).T) / 32.0
62
+ sims -= sims.max()
63
+ probs = np.exp(sims)
64
+ probs /= probs.sum()
65
+ return probs
66
+
67
+ def predict(self, phrase):
68
+ """Return the top intent label."""
69
+ probs = self.predict_proba(phrase)
70
+ return self.labels[int(np.argmax(probs))]
71
+
72
+ def predict_batch(self, phrases):
73
+ """Return a list of labels."""
74
+ return [self.predict(p) for p in phrases]
75
+
76
+ def similarity_scores(self, phrase):
77
+ """Return raw Hamming similarity to each intent (no softmax)."""
78
+ phrase_hv = self.encode(phrase).astype(np.int32)
79
+ retrieved = self.memory.astype(np.int32) * phrase_hv
80
+ return (retrieved.astype(np.float32) @
81
+ self.intent_codebook.astype(np.float32).T) / self.D
82
+
83
+ # -----------------------------------------------------------------------
84
+ # Persistence
85
+ # -----------------------------------------------------------------------
86
+
87
+ @classmethod
88
+ def from_pretrained(cls, path):
89
+ """Load from a directory containing config.json and codebooks.npz."""
90
+ path = Path(path)
91
+ with open(path / "config.json") as f:
92
+ config = json.load(f)
93
+ data = np.load(path / config["weights_file"])
94
+ return cls(
95
+ vocab_codebook=data["vocab_codebook"],
96
+ intent_codebook=data["intent_codebook"],
97
+ memory=data["memory"],
98
+ labels=config["intent_labels"],
99
+ )
100
+
101
+ def save_pretrained(self, path):
102
+ """Save codebooks and config to a directory."""
103
+ path = Path(path)
104
+ path.mkdir(parents=True, exist_ok=True)
105
+ np.savez_compressed(
106
+ path / "codebooks.npz",
107
+ vocab_codebook=self.vocab_codebook,
108
+ intent_codebook=self.intent_codebook,
109
+ memory=self.memory,
110
+ )
111
+ config = {
112
+ "model_type": "hv-intent-router",
113
+ "architecture": "evolved-hypervector",
114
+ "dimension": int(self.D),
115
+ "vocabulary_size": len(self.vocab),
116
+ "num_intents": len(self.labels),
117
+ "intent_labels": self.labels,
118
+ "vocabulary": self.vocab,
119
+ "encoding": "sum-bundle",
120
+ "bundling": "majority-vote",
121
+ "similarity": "hamming",
122
+ "weights_file": "codebooks.npz",
123
+ }
124
+ with open(path / "config.json", "w") as f:
125
+ json.dump(config, f, indent=2)