Common issues when training, running, or contributing to MeowLLM, and how to fix them.
On some systems, pip picks the wrong torch wheel. Install torch explicitly first:
# CPU-only (works everywhere, smaller download)
pip install torch --index-url https://download.pytorch.org/whl/cpu
# CUDA 12.1 (for NVIDIA GPUs)
pip install torch --index-url https://download.pytorch.org/whl/cu121
# Then the rest
pip install -e .The tokenizers package comes from Hugging Face and is a separate
install from transformers. If pip install -e . didn't pull it in,
install it directly:
pip install tokenizers>=0.15.0You forgot pip install -e ., or you're running from outside the
repo root. The editable install makes the meow package importable
from any directory. If you can't install for some reason, run scripts
from the repo root with PYTHONPATH:
PYTHONPATH=. python -m meow.generate_data --out-dir data --n 20000If meow.generate_data reports a yield much lower than the expected
~60%, check the rejection reasons in the output. Common causes:
-
You added a new banned phrase that's matching valid outputs.
meow/rules.pyuses whole-phrase matching, but if you added a very short phrase like"i am"as banned, it will reject most lines. Make banned phrases specific ("i am an ai", not"i am"). -
You added a new category core that doesn't contain required vocab. Every long core (>6 words) must contain at least one word from its category's
required_anyset inrules.py. Either rewrite the core or add the missing word torequired_any. -
You increased
--nbeyond what the slot banks can produce. At 20,000 samples, duplicate rejections are already ~11,700. At 50,000 you'd hit a hard ceiling. Fix: add more fragments to existing slot banks inmeow/generate_data.py.
A generated output didn't include any of the required keywords for its category. Look at the specific rejection and either:
- Add the missing word to the category's
required_anyinmeow/rules.py, or - Rewrite the core in
meow/generate_data.pyto include an already-required word.
It shouldn't be — 20,000 samples take ~30 seconds. If it's much
slower, you probably have a huge n or slow I/O. Profile with:
python -c "
import cProfile, random
from meow.generate_data import generate_template_samples
cProfile.run('generate_template_samples(20000, random.Random(0), verbose=False)', sort='cumulative')
" 2>&1 | head -30Expected. The BPE trainer stops early when it runs out of merges that would save at least 2 characters. With a narrow lowercase-only dataset, vocab usually trains to 1600–1800. This is fine — smaller vocab means smaller embedding matrix means fewer parameters.
MeowLLM's tokenizer is byte-level BPE, so it does handle non-ASCII bytes correctly. But the training data is all lowercase ASCII, so if you feed the model non-ASCII input it won't know how to respond. The tokenizer will encode it fine; the model just hasn't seen it.
Check:
- Is the dataset actually loaded? Look for
[train] train=19000 val=1000 - Is the tokenizer correct? Vocab should be ~1700
- Is the learning rate reasonable? Default is 3e-4. If you changed it to something tiny (1e-7) it won't learn.
- Is the data masked correctly? Check
meow/dataset.py—IGNORE_INDEX = -100positions are excluded from loss. If you changed the masking logic and set too many positions to ignored, there's nothing to learn from.
The model is only 3.5M parameters, so it should fit on any GPU. OOM usually means batch size is too large or you're accidentally loading the entire dataset onto GPU. Default batch_size=64 needs <1 GB. Try:
python -m meow.train --batch-size 32 --epochs 10Something wasn't moved to the correct device. The most common cause:
loading a checkpoint on CPU then calling .to('cuda') but not re-moving
the RoPE buffers. Use the provided load_model() in meow.inference
which handles this correctly. If you're writing your own loading code,
make sure to call model.to(device) after load_state_dict.
Check that the model is actually on the GPU:
for name, p in model.named_parameters():
print(name, p.device)
breakIf it says cpu, you forgot model.to('cuda'). If it says cuda:0
and it's still slow, check that your batch isn't being moved one
sample at a time — ensure .to(device) is called on the whole batch
tensor, not inside a loop.
Usually means overfitting (val goes up while train goes down). At ~3.5M params on 19K samples, overfitting is real. Options:
- Reduce epochs to 5
- Add dropout:
--dropout 0.1 - Generate more data
If training finished (loss went down) but outputs still look random, check:
- Are you loading
best.ptorfinal.pt? - Did you pass
--temperaturetoo high? Try0.7or0.5. - Was training actually completed, or did it stop at step 20 (smoke mode)? The smoke mode checkpoint is near-random.
You're on torch 2.4+ where weights_only defaults to True.
meow.inference.load_model explicitly passes weights_only=False
because the checkpoint contains a config dict. If you're writing your
own loading code, do the same:
ckpt = torch.load("best.pt", weights_only=False)The decode() call should strip special tokens automatically. Check
that you're passing skip_special_tokens=True:
tokenizer.decode(ids, skip_special_tokens=True)The provided chat_once() already does this.
Temperature is too low. Try --temperature 0.8 or --temperature 0.9.
If still deterministic, check you're not accidentally using
top_k=1 — that's greedy decoding.
First, verify the environment:
python -c "import torch, tokenizers, pytest; print(torch.__version__, tokenizers.__version__, pytest.__version__)"You need torch>=2.1.0, tokenizers>=0.15.0, pytest>=8.0.0.
Then run tests with verbose output:
pytest tests/ -vIf a specific test fails, read the error. Most test failures on a fresh clone are either missing dependencies or a mismatched torch version (especially on Apple Silicon with MPS).
Python version mismatch. The CI config in .github/workflows/test.yml
tests against 3.10, 3.11, and 3.12. If you're using 3.9 or 3.13 locally,
some type hints or f-string syntax might behave differently. Upgrade
to 3.11 or 3.12 for development.
Install it:
pip install -e ".[hub]"
# or
pip install huggingface_hubThe script expects HF_TOKEN to be set:
export HF_TOKEN=hf_your_token_here
export HF_USERNAME=your_hf_username
bash scripts/upload_to_hf.shGet a token from https://huggingface.co/settings/tokens. It needs "write" permissions to create and upload to repos.
The script uses || true after repo creation so this shouldn't be
fatal. If it is, check the huggingface_hub version — very old versions
don't support repo create. Upgrade:
pip install --upgrade huggingface_hubFree Colab has idle timeouts. Options:
- Keep the browser tab active
- Use a paid tier (Colab Pro) with background execution
- Run training locally if you have a GPU
Runtime → Change runtime type → T4 GPU. If T4 isn't available, try later or use CPU fallback (slow but works).
Colab's pip sometimes gets confused by editable installs. Try:
!pip install -q torch tokenizers pytest
!pip install -q -e .
Or install without editable mode:
!pip install -q .
You added a category to CATEGORIES without adding it to
CATEGORY_KEYWORDS (or vice versa). The test test_categories_match_rules
catches this. Fix: make both files agree.
Your edits to the slot banks or rules are producing samples that can't pass filters. Run the generator manually and look at the rejection reasons:
python -m meow.generate_data --out-dir /tmp/test --n 500- Read the source. Every file in
meow/is under 500 lines (exceptgenerate_data.py) and heavily commented. - Read
persona.mdfor the character rules. - Read
docs/architecture.md(coming soon) for design decisions. - Open a GitHub issue with: the command you ran, the exact error output, your Python/torch versions, and your OS.