ember.cpp 0.1.0
C++ inference engine for Llama-family and paperkiln models (CPU, CUDA, WebAssembly)
Loading...
Searching...
No Matches
bindings.cpp
Go to the documentation of this file.
1#include <pybind11/pybind11.h>
2#include <pybind11/stl.h>
3#include <pybind11/iostream.h>
4
5#include "model_constants.h"
6#include "model.h"
7#include "api.h"
8#include "utf8_text.h"
9
10namespace py = pybind11;
11
13 m.doc() = R"pbdoc(
14 TinyLlama.cpp Python Bindings
15 =============================
16
17 Python bindings for the tinyllama.cpp inference engine supporting both GGUF and SafeTensors formats.
18
19 Key Classes:
20 - TinyLlamaSession: Main interface for model loading and text generation
21 - ModelConfig: Configuration object containing model parameters and metadata
22
23 Example Usage:
24 import tinyllama_cpp
25
26 # Basic CPU usage
27 session = tinyllama_cpp.TinyLlamaSession(
28 model_path="path/to/model.gguf",
29 tokenizer_path="path/to/tokenizer.json",
30 threads=4
31 )
32
33 # GPU usage with quantized KV cache
34 session = tinyllama_cpp.TinyLlamaSession(
35 model_path="path/to/model.gguf",
36 tokenizer_path="path/to/tokenizer.json",
37 threads=4,
38 n_gpu_layers=-1,
39 use_kv_quant=True
40 )
41
42 # Generate text
43 response = session.generate("What is AI?", steps=64, temperature=0.7)
44 print(response)
45
46 # Batch generation
47 prompts = ["What is AI?", "Explain quantum computing", "Tell me a joke"]
48 responses = session.generate_batch(prompts, steps=64)
49 for prompt, response in zip(prompts, responses):
50 print(f"Q: {prompt}\nA: {response}\n")
51 )pbdoc";
52
53 py::add_ostream_redirect(m, "ostream_redirect");
54
55 py::class_<ModelConfig> model_config_class(m, "ModelConfig", R"pbdoc(
56 Model configuration containing architecture parameters and metadata.
57
58 This class holds all the configuration parameters for a loaded model,
59 including architecture details, tokenizer information, and model metadata.
60 Most fields are automatically populated when loading a model.
61 )pbdoc");
62
64 .def(py::init<>(), "Create an empty ModelConfig object")
65 .def_readwrite("hidden_size", &ModelConfig::hidden_size, "Hidden dimension size of the model")
66 .def_readwrite("intermediate_size", &ModelConfig::intermediate_size, "Intermediate size in feed-forward layers")
67 .def_readwrite("num_attention_heads", &ModelConfig::num_attention_heads, "Number of attention heads")
68 .def_readwrite("num_key_value_heads", &ModelConfig::num_key_value_heads, "Number of key-value heads (for GQA)")
69 .def_readwrite("num_hidden_layers", &ModelConfig::num_hidden_layers, "Number of transformer layers")
70 .def_readwrite("vocab_size", &ModelConfig::vocab_size, "Vocabulary size")
71 .def_readwrite("max_position_embeddings", &ModelConfig::max_position_embeddings, "Maximum sequence length")
72 .def_readwrite("rms_norm_eps", &ModelConfig::rms_norm_eps, "RMS normalization epsilon")
73 .def_readwrite("rope_theta", &ModelConfig::rope_theta, "RoPE theta parameter")
74 .def_readwrite("hidden_act", &ModelConfig::hidden_act, "Activation function name")
75 .def_readwrite("torch_dtype", &ModelConfig::torch_dtype, "Original PyTorch data type")
76 .def_readwrite("bos_token_id", &ModelConfig::bos_token_id, "Beginning-of-sequence token ID")
77 .def_readwrite("eos_token_id", &ModelConfig::eos_token_id, "End-of-sequence token ID")
78 .def_readwrite("architecture", &ModelConfig::architecture, "Model architecture name")
79 .def_readwrite("model_name", &ModelConfig::model_name, "Model name")
80 .def_readwrite("chat_template_type", &ModelConfig::chat_template_type, "Chat template type")
81 .def_readwrite("pre_tokenizer_type", &ModelConfig::pre_tokenizer_type, "Pre-tokenizer type")
82 .def_readwrite("chat_template_string", &ModelConfig::chat_template_string, "Chat template string")
83 .def_readwrite("is_gguf_file_loaded", &ModelConfig::is_gguf_file_loaded, "Whether model was loaded from GGUF format")
84 .def_readonly("tokenizer_family", &ModelConfig::tokenizer_family, "Tokenizer family (LLAMA_SENTENCEPIECE or LLAMA3_TIKTOKEN)")
85 .def("__repr__",
86 [](const ModelConfig &cfg) {
87 std::string tf_str = "UNKNOWN";
88 if (cfg.tokenizer_family == ModelConfig::TokenizerFamily::LLAMA_SENTENCEPIECE) tf_str = "LLAMA_SENTENCEPIECE";
89 else if (cfg.tokenizer_family == ModelConfig::TokenizerFamily::LLAMA3_TIKTOKEN) tf_str = "LLAMA3_TIKTOKEN";
90 return "<ModelConfig: vocab_size=" + std::to_string(cfg.vocab_size) +
91 ", hidden_size=" + std::to_string(cfg.hidden_size) +
92 ", tokenizer_family=" + tf_str +
93 ">";
94 }
95 );
96
97 py::enum_<ModelConfig::TokenizerFamily>(model_config_class, "TokenizerFamily", "Enumeration of supported tokenizer families")
98 .value("UNKNOWN", ModelConfig::TokenizerFamily::UNKNOWN, "Unknown tokenizer family")
99 .value("LLAMA_SENTENCEPIECE", ModelConfig::TokenizerFamily::LLAMA_SENTENCEPIECE, "Llama/Llama2 SentencePiece tokenizer")
100 .value("LLAMA3_TIKTOKEN", ModelConfig::TokenizerFamily::LLAMA3_TIKTOKEN, "Llama3 TikToken-style tokenizer")
101 .export_values();
102
103 py::class_<tinyllama::TinyLlamaSession>(m, "TinyLlamaSession", R"pbdoc(
104 Main interface for TinyLlama model inference.
105
106 This class provides a high-level interface for loading models and generating text.
107 It supports both GGUF and SafeTensors formats, CPU and GPU inference, and various
108 sampling strategies for text generation.
109
110 The session manages the model, tokenizer, and KV cache, providing both single
111 prompt generation and efficient batch processing capabilities.
112 )pbdoc")
113 .def(py::init([](const py::object& model_path, const py::object& tokenizer_path, int threads, int n_gpu_layers, bool use_mmap, bool use_kv_quant, bool use_batch_generation, int max_batch_size) {
114 // Convert path-like objects to strings
115 std::string model_path_str = py::str(model_path);
116 std::string tokenizer_path_str = py::str(tokenizer_path);
118 }),
119 py::arg("model_path"),
120 py::arg("tokenizer_path"),
121 py::arg("threads") = 1,
122 py::arg("n_gpu_layers") = 0,
123 py::arg("use_mmap") = true,
124 py::arg("use_kv_quant") = false,
125 py::arg("use_batch_generation") = false,
126 py::arg("max_batch_size") = 1,
127 R"pbdoc(
128 Initialize a TinyLlama inference session.
129
130 Args:
131 model_path (str or Path): Path to model directory (SafeTensors) or .gguf file
132 tokenizer_path (str or Path): Path to tokenizer.json file. For GGUF models with
133 embedded tokenizer, this can be the same as model_path
134 threads (int, optional): Number of CPU threads for inference. Defaults to 1.
135 n_gpu_layers (int, optional): Number of layers to offload to GPU.
136 -1 = all layers, 0 = CPU only. Defaults to 0.
137 use_mmap (bool, optional): Use memory mapping for model loading. Defaults to True.
138 use_kv_quant (bool, optional): Use INT8 quantization for KV cache on GPU.
139 Reduces VRAM usage. Defaults to False.
140 use_batch_generation (bool, optional): Enable optimized batch generation mode.
141 Defaults to False.
142 max_batch_size (int, optional): Maximum number of sequences for batch processing.
143 Defaults to 1.
144
145 Raises:
146 RuntimeError: If model loading fails due to invalid paths, unsupported format,
147 or insufficient resources.
148
149 Example:
150 # Basic CPU usage
151 session = TinyLlamaSession("model.gguf", "tokenizer.json", threads=4)
152
153 # Using pathlib.Path objects
154 from pathlib import Path
155 session = TinyLlamaSession(
156 model_path=Path("model.gguf"),
157 tokenizer_path=Path("tokenizer.json"),
158 threads=4,
159 n_gpu_layers=-1,
160 use_kv_quant=True
161 )
162 )pbdoc"
163 )
164 // pybind11 decodes a returned std::string strictly (UnicodeDecodeError on a reply cut inside a
165 // character): the text is valid UTF-8 first, as Python's decode(errors="replace") (utf8_text.h).
166 .def("generate",
167 [](tinyllama::TinyLlamaSession& s, const std::string& prompt, int steps, float temperature, int top_k,
168 float top_p, const std::string& system_prompt, bool apply_q_a_format) {
169 return ember::utf8_valid(
170 s.generate(prompt, steps, temperature, top_k, top_p, system_prompt, apply_q_a_format));
171 },
172 py::arg("prompt"),
173 py::arg("steps") = 128,
174 py::arg("temperature") = 0.1f,
175 py::arg("top_k") = 40,
176 py::arg("top_p") = 0.9f,
177 py::arg("system_prompt") = "",
178 py::arg("apply_q_a_format") = true,
179 R"pbdoc(
180 Generate text based on a prompt using various sampling strategies.
181
182 Args:
183 prompt (str): Input text prompt to generate from
184 steps (int, optional): Number of tokens to generate. Defaults to 128.
185 temperature (float, optional): Sampling temperature. Lower values (0.1)
186 produce more focused/deterministic output,
187 higher values (1.0+) more creative/random.
188 Defaults to 0.1.
189 top_k (int, optional): Top-K sampling - limit to K most likely tokens.
190 Set to 0 to disable. Defaults to 40.
191 top_p (float, optional): Nucleus sampling - limit to tokens comprising
192 top P probability mass (0.0-1.0). Defaults to 0.9.
193 system_prompt (str, optional): System prompt to guide generation behavior.
194 Defaults to empty string.
195 apply_q_a_format (bool, optional): Apply Q:A formatting to prompt.
196 Recommended for most models. Defaults to True.
197
198 Returns:
199 str: Generated text (excluding the original prompt)
200
201 Raises:
202 RuntimeError: If generation fails due to tokenization errors or model issues.
203
204 Example:
205 # Basic generation
206 response = session.generate("What is artificial intelligence?")
207
208 # Creative generation with higher temperature
209 story = session.generate(
210 "Once upon a time",
211 steps=200,
212 temperature=0.8,
213 top_k=50
214 )
215
216 # Focused generation with system prompt
217 answer = session.generate(
218 "Explain quantum computing",
219 steps=100,
220 temperature=0.1,
221 system_prompt="You are a helpful physics teacher."
222 )
223 )pbdoc"
224 )
225 .def("generate_batch",
226 [](tinyllama::TinyLlamaSession& s, const std::vector<std::string>& prompts, int steps, float temperature,
227 int top_k, float top_p, const std::string& system_prompt, bool apply_q_a_format) {
228 std::vector<std::string> out =
229 s.generate_batch(prompts, steps, temperature, top_k, top_p, system_prompt, apply_q_a_format);
230 for (std::string& t : out) t = ember::utf8_valid(t);
231 return out;
232 },
233 py::arg("prompts"),
234 py::arg("steps") = 128,
235 py::arg("temperature") = 0.1f,
236 py::arg("top_k") = 40,
237 py::arg("top_p") = 0.9f,
238 py::arg("system_prompt") = "",
239 py::arg("apply_q_a_format") = true,
240 R"pbdoc(
241 Generate text for multiple prompts in parallel (batch processing).
242
243 This method processes multiple independent prompts simultaneously, providing
244 significant efficiency gains over sequential generate() calls. Each prompt
245 maintains its own KV cache state and is processed independently.
246
247 Args:
248 prompts (List[str]): List of input prompts to process in batch
249 steps (int, optional): Number of tokens to generate per prompt. Defaults to 128.
250 temperature (float, optional): Sampling temperature applied to all prompts.
251 Defaults to 0.1.
252 top_k (int, optional): Top-K sampling parameter for all prompts. Defaults to 40.
253 top_p (float, optional): Nucleus sampling parameter for all prompts. Defaults to 0.9.
254 system_prompt (str, optional): System prompt applied to all prompts.
255 Defaults to empty string.
256 apply_q_a_format (bool, optional): Apply Q:A formatting to all prompts.
257 Defaults to True.
258
259 Returns:
260 List[str]: List of generated text strings, one for each input prompt
261
262 Raises:
263 RuntimeError: If batch generation fails or prompts list is empty.
264
265 Example:
266 prompts = [
267 "What is machine learning?",
268 "Explain neural networks",
269 "How does backpropagation work?"
270 ]
271
272 responses = session.generate_batch(
273 prompts,
274 steps=100,
275 temperature=0.2
276 )
277
278 for prompt, response in zip(prompts, responses):
279 print(f"Q: {prompt}")
280 print(f"A: {response}\n")
281 )pbdoc"
282 )
284 py::return_value_policy::reference_internal,
285 R"pbdoc(
286 Get the model configuration.
287
288 Returns:
289 ModelConfig: Reference to the session's model configuration containing
290 architecture parameters, tokenizer info, and metadata.
291
292 Example:
293 config = session.get_config()
294 print(f"Model has {config.num_hidden_layers} layers")
295 print(f"Vocabulary size: {config.vocab_size}")
296 print(f"Hidden size: {config.hidden_size}")
297 )pbdoc"
298 );
299}
PYBIND11_MODULE(tinyllama_bindings, m)
Definition bindings.cpp:12
Represents an active TinyLlama session holding the loaded model and tokenizer.
Definition api.h:85
const ModelConfig & get_config() const
Definition api.h:165
node out
size_t j
Constants used throughout the TinyLlama model implementation.
std::string utf8_valid(const std::string &s)
Definition utf8_text.h:74
Model configuration structure holding architecture and hyperparameters.
Definition model.h:82
int hidden_size
Definition model.h:83
int vocab_size
Definition model.h:88
std::string chat_template_string
Definition model.h:102
std::string pre_tokenizer_type
Definition model.h:101
std::string architecture
Definition model.h:98
std::string model_name
Definition model.h:99
float rms_norm_eps
Definition model.h:90
int num_attention_heads
Definition model.h:85
std::string chat_template_type
Definition model.h:100
int intermediate_size
Definition model.h:84
int eos_token_id
Definition model.h:95
std::string torch_dtype
Definition model.h:93
bool is_gguf_file_loaded
Definition model.h:103
float rope_theta
Definition model.h:91
int num_hidden_layers
Definition model.h:87
int num_key_value_heads
Definition model.h:86
int bos_token_id
Definition model.h:94
std::string hidden_act
Definition model.h:92
TokenizerFamily tokenizer_family
Definition model.h:123
int max_position_embeddings
Definition model.h:89