Spaces:
Running on Zero
Add wayneworkman2012/peacebell-v1-148M (WWII domain model, greedy; additive Peacebell-only branch)
Browse filesAdds **wayneworkman2012/peacebell-v1-148M** to the main (chat) arena: https://huggingface.co/wayneworkman2012/peacebell-v1-148M
148.55M parameters, trained from scratch, Apache-2.0. It is a single-domain model: it only knows World War II, and it redirects most other topics back to the war. It will lose plenty of general battles and that is fine; it is a first version and I would like it out there.
**Why this is a PR and not just a model id**
I replayed this Space's own `load_models` / `build_inputs` / `generate_for_model` code against the model locally. It loads fine with your generic loader (`AutoTokenizer` + `AutoModelForCausalLM`, `trust_remote_code=True`, float32), but every reply came back as `[Error generating ... 'GPTForCausalLM' object has no attribute 'generate']`. Two reasons, both in my repo's design:
- the model ships its own KV-cached decoder (`chat_generate`) instead of HF `generate()`;
- it has no Jinja `chat_template` on purpose: the ChatML control tokens are injected by id exactly as at training time (`tokenizer.build_chatml_ids`), which a string template cannot reproduce with SentencePiece.
So it needs a small special case, the same way MetaDiffusion has one.
**What this PR changes** (`app.py`: 20 lines added, 0 removed; `requirements.txt`: 1 line added)
- one entry each in `MODEL_IDS`, `MODEL_DISPLAY`, `MODEL_PARAMS` (148.55e6), `GEN_DEFAULTS`, `MODEL_CONTEXT` (16384);
- `is_peacebell_model()` + `generate_peacebell()`, and a two-line branch in `generate_for_model` placed right after the diffusion branch. It honours the same `max_new` the slider gives every other model;
- `sentencepiece>=0.2.0` in `requirements.txt` (the model's tokenizer imports it).
**Decoding: greedy on purpose.** Peacebell is trained and validated at temperature 0, with no repetition penalty and no n-gram block, so that is how it is wired (`temperature=0.0`, `no_repeat_ngram_size=0`). Its answers are deterministic.
**Nothing else is affected.** No existing line is modified; other models never enter the new branch. What I checked locally (transformers 5.14.1, your pinned version):
- a control entrant, `HuggingFaceTB/SmolLM2-135M-Instruct`, run through the original and the patched `app.py` with the same seeds over 8 prompts: output SHA-256 identical (`d45c0901...c02f9f` both ways);
- because `sentencepiece` is a new dependency, I loaded the tokenizer of every model in `MODEL_IDS` + `BASE_MODEL_IDS` in a clean environment without and then with `sentencepiece` installed: tokenizer class, vocabulary size, special tokens, encodings of three test strings and chat-template output are identical for all of them;
- peak GPU memory for Peacebell in float32: 0.59 GiB. The same modeling code already runs on ZeroGPU in my own demo Space.
Unrelated, in case it helps: `DedeProGames/Kiyo-135M` currently returns 404 on the Hub (it failed to load in both of my runs), so that entry is probably erroring in battles. I did not touch it.
Sample replies through the patched code, 128 new tokens:
- "When did World War II begin and end?" -> "World War II began in 1939 and ended in 1945."
- "Who commanded the Allied forces on D-Day?" -> "General Dwight D. Eisenhower commanded the Allied forces on D-Day."
- "Tell me a joke." -> "I won't do that. We can go over World War II together, if you'd like to explore it."
Thanks for running the arena.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01Kpv2a5EA4htxnrqzE1VdGG
- app.py +20 -0
- requirements.txt +2 -1
|
@@ -39,6 +39,7 @@ MODEL_IDS: List[str] = [
|
|
| 39 |
"BananaMind/BananaMind-2-Pro-Preview-Chat",
|
| 40 |
"BananaMind/BananaMind-2-Nano-Chat",
|
| 41 |
"BananaMind/BananaMind-2-Mini-Chat",
|
|
|
|
| 42 |
]
|
| 43 |
|
| 44 |
MODEL_DISPLAY: Dict[str, str] = {
|
|
@@ -53,6 +54,7 @@ MODEL_DISPLAY: Dict[str, str] = {
|
|
| 53 |
"BananaMind/BananaMind-2-Pro-Preview-Chat": "BananaMind-2-Pro-Preview-Chat",
|
| 54 |
"BananaMind/BananaMind-2-Nano-Chat": "BananaMind-2-Nano-Chat",
|
| 55 |
"BananaMind/BananaMind-2-Mini-Chat": "BananaMind-2-Mini-Chat",
|
|
|
|
| 56 |
}
|
| 57 |
|
| 58 |
BASE_MODEL_IDS: List[str] = [
|
|
@@ -121,6 +123,7 @@ MODEL_PARAMS: Dict[str, float] = {
|
|
| 121 |
"DedeProGames/Kiyo-230M-Preview": 229.7e6,
|
| 122 |
"DedeProGames/Kiyo-135M": 134.5e6,
|
| 123 |
"DedeProGames/Kiyo-65M": 65.0e6,
|
|
|
|
| 124 |
}
|
| 125 |
|
| 126 |
FALLBACK_IDS: Dict[str, str] = {}
|
|
@@ -218,6 +221,8 @@ GEN_DEFAULTS: Dict[str, dict] = {
|
|
| 218 |
"DedeProGames/Kiyo-230M-Preview": {"max_new_tokens": 64, "temperature": 0.8, "top_p": 0.95, "repetition_penalty": 1.1, "do_sample": True},
|
| 219 |
"DedeProGames/Kiyo-135M": {"max_new_tokens": 64, "temperature": 0.8, "top_p": 0.95, "repetition_penalty": 1.1, "do_sample": True},
|
| 220 |
"DedeProGames/Kiyo-65M": {"max_new_tokens": 64, "temperature": 0.8, "top_p": 0.95, "repetition_penalty": 1.1, "do_sample": True},
|
|
|
|
|
|
|
| 221 |
}
|
| 222 |
|
| 223 |
MODEL_CONTEXT: Dict[str, int] = {
|
|
@@ -248,6 +253,7 @@ MODEL_CONTEXT: Dict[str, int] = {
|
|
| 248 |
"DedeProGames/Kiyo-230M-Preview": 2048,
|
| 249 |
"DedeProGames/Kiyo-135M": 8192,
|
| 250 |
"DedeProGames/Kiyo-65M": 2048,
|
|
|
|
| 251 |
}
|
| 252 |
|
| 253 |
|
|
@@ -894,6 +900,18 @@ def build_inputs(tokenizer, model_id: str, prompt: str):
|
|
| 894 |
def is_diffusion_model(model_id: str) -> bool:
|
| 895 |
return "metadiffusion" in model_id.lower()
|
| 896 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 897 |
def generate_for_model(model_id: str, prompt: str, max_new_tokens: int = 0) -> str:
|
| 898 |
ensure_models_loaded()
|
| 899 |
if model_id not in models or model_id not in tokenizers:
|
|
@@ -910,6 +928,8 @@ def generate_for_model(model_id: str, prompt: str, max_new_tokens: int = 0) -> s
|
|
| 910 |
try:
|
| 911 |
if is_diffusion_model(model_id):
|
| 912 |
return generate_diffusion(model, tokenizer, prompt, cfg) # type: ignore
|
|
|
|
|
|
|
| 913 |
inputs = build_inputs(tokenizer, model_id, prompt)
|
| 914 |
input_len = inputs["input_ids"].shape[1]
|
| 915 |
gen_kwargs = {
|
|
|
|
| 39 |
"BananaMind/BananaMind-2-Pro-Preview-Chat",
|
| 40 |
"BananaMind/BananaMind-2-Nano-Chat",
|
| 41 |
"BananaMind/BananaMind-2-Mini-Chat",
|
| 42 |
+
"wayneworkman2012/peacebell-v1-148M",
|
| 43 |
]
|
| 44 |
|
| 45 |
MODEL_DISPLAY: Dict[str, str] = {
|
|
|
|
| 54 |
"BananaMind/BananaMind-2-Pro-Preview-Chat": "BananaMind-2-Pro-Preview-Chat",
|
| 55 |
"BananaMind/BananaMind-2-Nano-Chat": "BananaMind-2-Nano-Chat",
|
| 56 |
"BananaMind/BananaMind-2-Mini-Chat": "BananaMind-2-Mini-Chat",
|
| 57 |
+
"wayneworkman2012/peacebell-v1-148M": "peacebell-v1-148M",
|
| 58 |
}
|
| 59 |
|
| 60 |
BASE_MODEL_IDS: List[str] = [
|
|
|
|
| 123 |
"DedeProGames/Kiyo-230M-Preview": 229.7e6,
|
| 124 |
"DedeProGames/Kiyo-135M": 134.5e6,
|
| 125 |
"DedeProGames/Kiyo-65M": 65.0e6,
|
| 126 |
+
"wayneworkman2012/peacebell-v1-148M": 148.55e6,
|
| 127 |
}
|
| 128 |
|
| 129 |
FALLBACK_IDS: Dict[str, str] = {}
|
|
|
|
| 221 |
"DedeProGames/Kiyo-230M-Preview": {"max_new_tokens": 64, "temperature": 0.8, "top_p": 0.95, "repetition_penalty": 1.1, "do_sample": True},
|
| 222 |
"DedeProGames/Kiyo-135M": {"max_new_tokens": 64, "temperature": 0.8, "top_p": 0.95, "repetition_penalty": 1.1, "do_sample": True},
|
| 223 |
"DedeProGames/Kiyo-65M": {"max_new_tokens": 64, "temperature": 0.8, "top_p": 0.95, "repetition_penalty": 1.1, "do_sample": True},
|
| 224 |
+
# Peacebell: greedy (temperature 0), no repetition penalty, no n-gram block; decoded by its own ChatML path (generate_peacebell)
|
| 225 |
+
"wayneworkman2012/peacebell-v1-148M": {"max_new_tokens": 64, "temperature": 0.0, "do_sample": False, "repetition_penalty": 1.0},
|
| 226 |
}
|
| 227 |
|
| 228 |
MODEL_CONTEXT: Dict[str, int] = {
|
|
|
|
| 253 |
"DedeProGames/Kiyo-230M-Preview": 2048,
|
| 254 |
"DedeProGames/Kiyo-135M": 8192,
|
| 255 |
"DedeProGames/Kiyo-65M": 2048,
|
| 256 |
+
"wayneworkman2012/peacebell-v1-148M": 16384,
|
| 257 |
}
|
| 258 |
|
| 259 |
|
|
|
|
| 900 |
def is_diffusion_model(model_id: str) -> bool:
|
| 901 |
return "metadiffusion" in model_id.lower()
|
| 902 |
|
| 903 |
+
def is_peacebell_model(model_id: str) -> bool:
|
| 904 |
+
return model_id.lower().startswith("wayneworkman2012/peacebell-")
|
| 905 |
+
|
| 906 |
+
def generate_peacebell(model, tokenizer, prompt: str, max_new: int) -> str:
|
| 907 |
+
"""Peacebell ships its own ChatML encoder + KV-cached greedy decoder (no HF generate(), no Jinja chat_template):
|
| 908 |
+
special-token ids are injected by id exactly as at training time. Same path as its demo Space. Temperature 0."""
|
| 909 |
+
ids = tokenizer.build_chatml_ids([{"role": "user", "content": prompt}], add_generation_prompt=True)
|
| 910 |
+
input_ids = torch.tensor(ids, dtype=torch.long, device=DEVICE)
|
| 911 |
+
out_ids = model.chat_generate(input_ids, max_new_tokens=int(max_new), temperature=0.0, no_repeat_ngram_size=0)
|
| 912 |
+
text = tokenizer.decode_response(out_ids)
|
| 913 |
+
return text if text else "[Empty response]"
|
| 914 |
+
|
| 915 |
def generate_for_model(model_id: str, prompt: str, max_new_tokens: int = 0) -> str:
|
| 916 |
ensure_models_loaded()
|
| 917 |
if model_id not in models or model_id not in tokenizers:
|
|
|
|
| 928 |
try:
|
| 929 |
if is_diffusion_model(model_id):
|
| 930 |
return generate_diffusion(model, tokenizer, prompt, cfg) # type: ignore
|
| 931 |
+
if is_peacebell_model(model_id):
|
| 932 |
+
return generate_peacebell(model, tokenizer, prompt, max_new)
|
| 933 |
inputs = build_inputs(tokenizer, model_id, prompt)
|
| 934 |
input_len = inputs["input_ids"].shape[1]
|
| 935 |
gen_kwargs = {
|
|
@@ -7,4 +7,5 @@ huggingface_hub==1.22.0
|
|
| 7 |
accelerate==1.14.0
|
| 8 |
numpy==2.2.6
|
| 9 |
plotly>=5.18.0
|
| 10 |
-
tiktoken>=0.8.0
|
|
|
|
|
|
| 7 |
accelerate==1.14.0
|
| 8 |
numpy==2.2.6
|
| 9 |
plotly>=5.18.0
|
| 10 |
+
tiktoken>=0.8.0
|
| 11 |
+
sentencepiece>=0.2.0
|