Instructions to use Nurymanau/EmbeddingGemma2-Reflex with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- MLX
How to use Nurymanau/EmbeddingGemma2-Reflex with MLX:
# Download the model from the Hub pip install huggingface_hub[hf_xet] hf download Nurymanau/EmbeddingGemma2-Reflex --local-dir EmbeddingGemma2-Reflex
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- LM Studio
- Atomic Chat
Download reflex.py from Nurymanau/EmbeddingGemma2-Reflex: direct link, hf CLI and curl.
- Browser
- Download file 5.16 kB
-
https://huggingface.co/Nurymanau/EmbeddingGemma2-Reflex/resolve/main/reflex.py
- Command line
-
hf download hf://Nurymanau/EmbeddingGemma2-Reflex/reflex.py
-
curl -L -o reflex.py https://huggingface.co/Nurymanau/EmbeddingGemma2-Reflex/resolve/main/reflex.py
5.16 kB
| """Standalone text decision runtime. Modified model; not a text generator. | |
| Apache-2.0. EmbeddingGemma 2 base model: Google DeepMind. | |
| """ | |
| import argparse | |
| import json | |
| import math | |
| import subprocess | |
| import time | |
| from pathlib import Path | |
| import numpy as np | |
| class Reflex: | |
| def __init__(self, model_root, seed=17, encoder_executable=None, head_path=None): | |
| self.root = Path(model_root) | |
| folder = self.root / f'seed-{seed}' | |
| with np.load(head_path or folder / 'head.npz', allow_pickle=False) as f: | |
| self.weights = {k: f[k] for k in f.files if k != 'metadata'} | |
| self.options = {} | |
| self.process = None | |
| if encoder_executable: | |
| self.process = subprocess.Popen([str(encoder_executable), str(folder / 'text-q8'), 'compiled-exact'], | |
| stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True, bufsize=1) | |
| if not json.loads(self.process.stdout.readline()).get('ready'): | |
| raise RuntimeError('Encoder did not become ready') | |
| else: | |
| import torch | |
| from safetensors.torch import load_file | |
| from transformers import AutoTokenizer, EmbeddingGemma2TextConfig, EmbeddingGemma2TextModel | |
| torch.set_num_threads(2) | |
| directory = folder / 'text-bf16' | |
| config = EmbeddingGemma2TextConfig(**json.loads((directory/'config.json').read_text())['text_config']) | |
| config._attn_implementation = 'eager' | |
| self.model = EmbeddingGemma2TextModel(config).float().eval() | |
| source = load_file(str(directory / 'model.safetensors')) | |
| self.model.load_state_dict({k.removeprefix('language_model.'):v for k,v in source.items()}, strict=True) | |
| self.tokenizer = AutoTokenizer.from_pretrained(directory, local_files_only=True) | |
| def encode(self, texts): | |
| if self.process: | |
| self.process.stdin.write(json.dumps({'texts': texts})+'\n'); self.process.stdin.flush() | |
| result = json.loads(self.process.stdout.readline()) | |
| if 'error' in result: raise RuntimeError(result['error']) | |
| return np.asarray(result['embeddings'], np.float32) | |
| import torch | |
| tokens = self.tokenizer(texts, padding=True, return_tensors='pt') | |
| if tokens['input_ids'].shape[1] > 192: | |
| raise ValueError('This research release was trained with at most 192 tokens per text.') | |
| with torch.inference_mode(): | |
| hidden = self.model(**tokens).last_hidden_state.float() | |
| mask = tokens['attention_mask'].unsqueeze(-1) | |
| pooled = (hidden*mask).sum(1)/mask.sum(1) | |
| return torch.nn.functional.normalize(pooled, dim=-1).numpy() | |
| def logits(self, query, options): | |
| w=self.weights; x=np.asarray(query,np.float32)*math.sqrt(768); o=np.asarray(options,np.float32) | |
| a=np.tanh(x@w['query.0.weight'].T+w['query.0.bias']) | |
| a=a@w['query.2.weight'].T+w['query.2.bias'] | |
| b=np.tanh(o*math.sqrt(768)@w['option.weight'].T+w['option.bias']) | |
| g=np.tanh(x@w['gate.0.weight'].T+w['gate.0.bias'])@w['gate.2.weight'].T+w['gate.2.bias'] | |
| gate=1/(1+np.exp(-np.clip(g,-60,60))) | |
| return (o*query).sum(-1)/.08+gate*(a*b).sum(-1)/math.sqrt(128) | |
| def predict(self, instructions, state, options): | |
| if not isinstance(instructions,str) or not isinstance(state,str): raise TypeError('instructions/state must be text') | |
| if not 2<=len(options)<=32 or not all(isinstance(x,str) for x in options): raise ValueError('Supply 2–32 text options') | |
| if len(set(options))!=len(options): raise ValueError('Options must be distinct') | |
| start=time.perf_counter() | |
| missing=sorted(set(options)-self.options.keys()) | |
| vectors=self.encode(['task: classification | query: '+instructions+' '+state]+missing) | |
| self.options.update(zip(missing,vectors[1:])) | |
| z=self.logits(vectors[0],np.asarray([self.options[o] for o in options],np.float32)) | |
| p=np.exp(z-z.max());p/=p.sum();index=int(p.argmax()) | |
| return {'index':index,'choice':options[index],'probabilities':p.tolist(), | |
| 'probabilities_calibrated':False,'wall_ms':(time.perf_counter()-start)*1000} | |
| def close(self): | |
| if self.process: | |
| self.process.stdin.close() | |
| try:self.process.wait(timeout=10) | |
| except subprocess.TimeoutExpired:self.process.terminate();self.process.wait(timeout=5) | |
| def main(): | |
| p=argparse.ArgumentParser() | |
| p.add_argument('--model-root',type=Path,default=Path(__file__).parent) | |
| p.add_argument('--seed',type=int,choices=[17,41],default=17) | |
| p.add_argument('--encoder',type=Path,help='Built reflex-embed Swift executable; otherwise CPU Torch reference') | |
| p.add_argument('--head',type=Path,help='Optional explicitly selected compatible head') | |
| p.add_argument('--request',required=True,help='JSON object with instructions, state, options') | |
| args=p.parse_args();model=Reflex(args.model_root,args.seed,args.encoder,args.head) | |
| try: print(json.dumps(model.predict(**json.loads(args.request)),ensure_ascii=False)) | |
| finally:model.close() | |
| if __name__=='__main__':main() | |