Any-to-Any
MLX
Safetensors
gemma4
mlx-vlm
rlcd
multimodal
classification
parallel-inference
image-text-to-text
audio
video
4-bit precision
Instructions to use larkooo/gemma-e2b-rlcd with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- MLX
How to use larkooo/gemma-e2b-rlcd with MLX:
# Download the model from the Hub pip install huggingface_hub[hf_xet] hf download larkooo/gemma-e2b-rlcd --local-dir gemma-e2b-rlcd
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- LM Studio
- Atomic Chat
File size: 7,849 Bytes
53e24ca f092803 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 | import math
from string import ascii_uppercase
import pytest
from gemma_rlcd import Choice, DecisionEngine, Independent, Noul, Score, State
from gemma_rlcd.core import TokenScores, parse_question, softmax
class StubBackend:
def __init__(self, probabilities):
self.probabilities = iter(probabilities)
def symbols(self, count):
return ascii_uppercase[:count]
def score(self, state, prompt, symbols):
return TokenScores(tuple(math.log(p) for p in next(self.probabilities)), 0.8, 100)
def test_choice_returns_all_labels_and_correct_winner():
answer = DecisionEngine(StubBackend([[0.2, 0.8]])).decide(
State(text="test"), Choice("Which?", {"cat": "Cat", "dog": "Dog"})
)
assert answer["choice"] == "dog"
assert answer["probabilities"] == pytest.approx({"cat": 0.2, "dog": 0.8})
assert answer["selected_probability"] == pytest.approx(0.8)
assert answer["calibration_status"] == "unvalidated"
def test_score_uses_weighted_level_positions():
answer = DecisionEngine(StubBackend([[0.1, 0.6, 0.3]])).decide(
State(text="test"), Score("How severe?", ["Cosmetic", "Workaround", "Blocking"])
)
assert answer["score"] == pytest.approx(1.2)
assert answer["legend"]["2"] == "Blocking"
assert sum(answer["probabilities"].values()) == pytest.approx(1.0)
def test_noul_handles_reversed_criteria_order():
answer = DecisionEngine(StubBackend([[0.8, 0.2]])).decide(
State(text="test"), Noul("Is there a cat?", {"false": "No cat", "true": "Cat"})
)
assert answer["noul"] == pytest.approx(0.2)
assert "confidence" not in answer
def test_independent_probabilities_do_not_compete():
answer = DecisionEngine(StubBackend([[0.9, 0.1], [0.8, 0.2]])).decide(
State(text="test"), Independent("What is present?", {"cat": "Cat", "dog": "Dog"})
)
assert answer["probabilities"] == pytest.approx({"cat": 0.9, "dog": 0.8})
def test_all_primitives_share_state_in_one_request():
engine = DecisionEngine(StubBackend([[0.5, 0.5], [0.3, 0.7], [0.8, 0.2]]))
answers = engine.system_one(
State(text="test"),
{
"category": Choice("Which?", {"a": "A", "b": "B"}),
"grade": Score("How much?", ["Low", "High"]),
"present": Noul("Present?"),
},
)["answers"]
assert set(answers) == {"category", "grade", "present"}
assert answers["category"]["confidence"] == pytest.approx(0.0)
assert answers["grade"]["score"] == pytest.approx(0.7)
def test_native_backend_receives_complete_schema_and_preserves_answer_contracts():
state = State(text="Two cats. No dogs.")
questions = {
"animal": Choice("Which animal?", {"cat": "Cat", "dog": "Dog"}),
"count": Score("How many cats?", ["Zero", "One", "Two"]),
"dog": Noul("Any dogs?", {"false": "No dogs", "true": "Dogs present"}),
"presence": Independent("Which animals?", {"cat": "A cat", "dog": "A dog"}),
}
class Native(StubBackend):
def score_batch(self, *args):
raise AssertionError("Native backend must receive the original questions")
def score_questions(self, actual_state, actual_questions):
assert actual_state is state
assert actual_questions is questions
probabilities = [[0.9, 0.1], [0.1, 0.1, 0.8], [0.9, 0.1], [0.9, 0.1], [0.1, 0.9]]
return [TokenScores(tuple(map(math.log, values)), 1, 100) for values in probabilities]
answers = DecisionEngine(Native([])).system_one(state, questions)["answers"]
assert answers["animal"]["choice"] == "cat"
assert answers["count"]["score"] == pytest.approx(1.7)
assert answers["dog"]["noul"] == pytest.approx(0.1)
assert answers["presence"]["probabilities"] == pytest.approx({"cat": 0.9, "dog": 0.1})
@pytest.mark.parametrize(
"data",
[
{"type": "score", "instructions": "x", "criteria": ["only"]},
{"type": "noul", "instructions": "x", "criteria": {"yes": "Yes", "no": "No"}},
{"type": "choice", "instructions": "x", "criteria": {"one": "one"}},
{"type": "typo", "instructions": "x", "criteria": {}},
{"type": "noul", "instructions": "x", "extra": 1},
],
)
def test_invalid_questions_rejected(data):
with pytest.raises(ValueError):
parse_question(data)
def test_choice_supports_255_criteria_but_rejects_256():
Choice("Which?", {str(i): str(i) for i in range(255)})
with pytest.raises(ValueError):
Choice("Which?", {str(i): str(i) for i in range(256)})
@pytest.mark.parametrize("logits, temperature", [([math.nan, 0], 1), ([0, 1], 0), ([0], math.inf)])
def test_invalid_numerics_rejected(logits, temperature):
with pytest.raises(ValueError):
softmax(logits, temperature)
def test_large_logits_are_stable():
assert softmax([10000, 10000]) == [0.5, 0.5]
def test_media_cannot_be_silently_dropped(tmp_path):
video = tmp_path / "video.mp4"
video.write_bytes(b"placeholder")
assert State(videos=(str(video),)).videos == (str(video),)
with pytest.raises(ValueError):
State(images=(str(tmp_path / "missing.png"),))
with pytest.raises(ValueError):
State(audio=(str(video), str(video)))
def test_backend_invalid_output_is_rejected():
class Invalid(StubBackend):
def score(self, *args):
return TokenScores((0.0, math.nan), 1, 100)
with pytest.raises(ValueError):
DecisionEngine(Invalid([])).decide(State(text="test"), Noul("True?"))
def test_all_fields_and_independent_labels_are_sent_in_one_batch():
class Batched(StubBackend):
def __init__(self):
self.calls = []
def score(self, *args):
raise AssertionError("Batched backend must not use sequential score calls")
def score_batch(self, state, requests):
self.calls.append(requests)
return [TokenScores((math.log(0.8), math.log(0.2)), 0.9, 120) for _ in requests]
backend = Batched()
result = DecisionEngine(backend).system_one(
State(text="A cat and a dog."),
{
"choice": Choice("Which?", {"cat": "Cat", "dog": "Dog"}),
"grade": Score("How clear?", ["Clear", "Unclear"]),
"labels": Independent("What is present?", {"cat": "A cat", "dog": "A dog"}),
"noul": Noul("Any animal?"),
},
)
assert len(backend.calls) == 1
assert len(backend.calls[0]) == 5
assert list(result["answers"]) == ["choice", "grade", "labels", "noul"]
assert result["answers"]["labels"]["probabilities"] == pytest.approx({"cat": 0.8, "dog": 0.8})
def test_batch_result_count_is_checked():
class Broken(StubBackend):
def score_batch(self, state, requests):
return []
with pytest.raises(ValueError, match="wrong number of question results"):
DecisionEngine(Broken([])).system_one(State(text="test"), {"test": Noul("True?")})
def test_streamed_decisions_arrive_before_later_batches_and_match_final_answers():
seen = []
class Streaming(StubBackend):
def score_questions(self, state, questions, on_scores=None):
scores = [TokenScores((2.0, 0.0), 0.8, 50), TokenScores((0.0, 2.0), 0.8, 50)]
on_scores([(0, scores[0])])
assert len(seen) == 1
on_scores([(1, scores[1])])
return scores
result = DecisionEngine(Streaming([])).system_one(
State(text="evidence"),
{"visible": Independent("Which?", {"cat": "Cat", "dog": "Dog"})},
on_answer=lambda path, answer: seen.append((path, answer)),
)
assert [path for path, _ in seen] == [("visible", "cat"), ("visible", "dog")]
assert result["answers"]["visible"]["probabilities"] == {
path[1]: answer["probabilities"]["yes"] for path, answer in seen
}
|