Simple Llama model inference on macOS with MLX
Project description
infer.py - Annotated single file LLM inference with MLX / Apple Silicon
infer.py is a single Python program with the fewest parts you need to do inference of Llama-compatible models on macOS (that I've figured out so far).
On a modern Mac with Python and the dependencies installed, python infer.py --prompt 'Tell me a joke.' should result in a cringeworthy joke.
The big win for you is being able to manipulate the inference process for education or entertainment (as shown in some examples later).
Motivation
When I saw Apple's work on LLM inference tooling I had fun using it, but realized if I really wanted to understand inference I'd need to rework it, reimplement parts of it, and get my head into the whole process.
infer.py is the result of that. I've annotated the source with lots of comments to provide guidance to anyone as naive as me, so check it out. Much of the code has been changed from Apple's original source (and the structure is totally different) but you can go to the mlx_lm project if you want to see where all of this began and to use something more fully featured.
My other motivation is to easily play with dynamic temperature changes during inference (especially during 'thinking' stages) and with logit stuffing (i.e. forcing the model to generate certain things or to give it verbal 'tics') which can have some very curious results some of which I will include here later.
For now, I will let you play instead. The whole point is to dig around in infer.py, learn things, change things, force the model into hilarious situations, and have a laugh.
How to run
You need Python 3.11+ (it may work on lower), MLX and some of the Transformers stuff installed:
pip install -r requirements.txt
Then:
python -m infermlx.infer --prompt 'Tell me a joke.'
# OR if you choose to use infer.py on its own:
python infer.py --prompt 'Tell me a joke.'
It defaults to unsloth/Llama-3.2-1B-Instruct as it's free to use, quick, and only needs 4GB of RAM for inference out of the box. However, mistralai/Mistral-7B-Instruct-v0.2 is another good one to use, it's very smart, but needs 16GB of free RAM.
There are a handful of options:
-
--model
Default:"unsloth/Llama-3.2-1B-Instruct"
Description: The model to load for inference. Can be a HuggingFace repo or local directory. -
--prompt,-p
Default:"Tell me a joke."
Description: Your prompt, unsurprisingly. -
--system-prompt,-sDefault: None Description: An optional system prompt, e.g. "Talk like a pirate." -
--max-tokens,-m
Type:int
Default:1000
Description: The maximum number of tokens to generate. -
--temp
Type:float
Default:0.0
Description: Temperature for sampling. As always, values yield more deterministic outputs, while higher values introduce more randomness. This is explained in more detail in the code. -
--seed
Type:int
Default:42Description: A random seed for the PRNG. Everyone in LLM-land seems to use 42 as a default because Ilya Sutskever did it in a demo once or something.
Logits processors (the fun bit)
One way to have fun with LLMs, even small ones, is to 'force' them to say things. For example, if your model always refuses to answer a specific prompt, what happens if you force it to start its response with 'Yes, I am happy to help'? It depends. But you can do that!
token_stream = model.tokenizer.encode("I refuse to answer that because", False, False)
def make_the_model_start_with_something(tokens_so_far, logits):
nonlocal token_stream
if token_stream:
next_token = token_stream.pop(0)
logits[:, next_token] = 2000
return logits
model.generate(args.prompt, max_tokens=args.max_tokens, sampler=sampler, logits_processors=[make_the_model_start_with_something])
You could also give the model a 'tic' of sorts:
token_stream = []
import random
def make_the_model_weird(tokens_so_far, logits):
nonlocal token_stream
if len(token_stream) > 0:
next_token = token_stream.pop(0)
logits[:, next_token] = 2000
else:
if random.random() < 0.08:
token_stream.extend(model.tokenizer.encode("What the??", False, False))
return logits
model.generate(args.prompt, max_tokens=args.max_tokens, sampler=sampler, logits_processors=[make_the_model_weird])
Let your imagination run wild! (You could also detect certain things it has said and then force its ongoing response from there.)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file infermlx-0.0.1.tar.gz.
File metadata
- Download URL: infermlx-0.0.1.tar.gz
- Upload date:
- Size: 13.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.11.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6f0476405763531b0d6b799c6f31c75ee16f47824ae504e9d476c5cb6056d759
|
|
| MD5 |
71e41c0559e2cacdc7ebf0c7065e2ff8
|
|
| BLAKE2b-256 |
58bf179ed83b41d1dc15cce1f151684617611db8b0f9903e051e37979438ed49
|
File details
Details for the file infermlx-0.0.1-py3-none-any.whl.
File metadata
- Download URL: infermlx-0.0.1-py3-none-any.whl
- Upload date:
- Size: 12.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.11.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
44592550e7dc5590cb4a6d5b50ec7e30969a43db8190b2f98af8a3328caa37f7
|
|
| MD5 |
9985c8d7662732052916f40b2406efbf
|
|
| BLAKE2b-256 |
d608e56a1919a22daeba2cd60777bf5a5ebca4322e8c85e961e7b3fd3e8ef3c3
|