Runtime
Safetensors-to-SLM Conversion Architecture: Tensor Mapping and Binary Serialization for Xenova/llama2.c-stories15M
Report summary
The paradigm of natural language processing has experienced a profound structural and operational shift with the advent of Small Language Models (SLMs). While Large Language Models (LLMs) comprising hundreds of billions or even trillions of parameters dominate centralized, hyperscale cloud infrastru
Key topics
- Runtime
- AI
- .NET
- Python
- Rust
- GGUF
- Physics
- Semantic Systems
Research provenance
For citation, use the report title and canonical URL. Archival presence does not establish authorship or promote report statements into portfolio evidence.
This page renders the archived Markdown as safe, formatted HTML. It is background research and does not become a portfolio claim without evidence review.
Full report
On this page
1. Introduction to Small Language Model Architecture and Binary Serialization
The paradigm of natural language processing has experienced a profound structural and operational shift with the advent of Small Language Models (SLMs). While Large Language Models (LLMs) comprising hundreds of billions or even trillions of parameters dominate centralized, hyperscale cloud infrastructure, SLMs offer a streamlined, highly efficient alternative engineered specifically for resource-constrained environments, mobile computing architectures, and localized edge devices.1 Ranging in capacity from a few million to approximately ten billion parameters, SLMs are fundamentally designed to retain the core reasoning, text generation, and semantic comprehension capabilities of their larger architectural counterparts while radically reducing memory footprints, active power consumption, and computational latency.3 This miniaturization allows organizations to bypass expensive GPU server provisioning and execute private, real-time natural language tasks directly on local central processing units (CPUs), System-on-Chips (SoCs), or WebAssembly and WebGPU instances embedded within standard consumer web browsers.5 A critical operational bottleneck in deploying SLMs to edge environments is the precise format in which the neural network weights are serialized, stored, and loaded into active memory. Within the standard deep learning ecosystem, developers rely heavily on formats such as PyTorch .bin checkpoints or Hugging Face's Safetensors specification.7 Safetensors provides a secure, fast-loading, zero-copy mechanism within the Python, Rust, and Go ecosystems, acting as a direct replacement for vulnerable pickle payloads.7 However, Safetensors is inherently tied to high-level tensor libraries and relies on a JSON header dictionary to map tensor names to byte offsets dynamically.7 For embedded systems, microcontrollers, or bare-metal pure C/C++ inference engines, the overhead of parsing JSON headers, maintaining dynamic multidimensional array representations, and allocating memory through standard library calls introduces unacceptable latency and library dependency bloat.10 To achieve maximum inference efficiency in constrained computing topologies, models like Xenova/llama2.c-stories15M are programmatically exported from their native Hugging Face Safetensors format into a highly optimized, flat binary file format.10 Within the context of custom inference engines, this format is often generically referred to as the .slm or .bin binary map.13 This specific architecture mandates a rigid, predefined binary header containing core architectural hyperparameters, immediately followed by a contiguous, pre-aligned sequence of raw neural weight data.15 This deliberate serialization design enables the C or C++ application to utilize POSIX memory mapping (mmap) to directly map the model weights from the solid-state drive or disk into the virtual address space of the CPU.17 Consequently, the system achieves near-instantaneous load times and executes zero-copy inference without the need to allocate massive blocks of system RAM to duplicate the tensor arrays.10 This report provides an exhaustive, granular analysis of the conversion pipeline specifically designed for the Xenova/llama2.c-stories15M model, originally trained by Andrej Karpathy and ported by Xenova. It dissects the exact tensor-name mappings required to translate the Hugging Face Safetensors format into the contiguous C-struct expected by the target inference engine. Furthermore, the analysis comprehensively examines the treatment of JSON configuration fields, the serialization of tied versus untied output embeddings, customized tokenization structures, and the mathematical implementation of architectural nuances including Rotary Positional Embeddings (RoPE), Root Mean Square Normalization (RMSNorm), and the SwiGLU activation function.
2. Architectural Specifications of Xenova/llama2.c-stories15M
Before detailing the serialization map and byte-level translations, it is imperative to establish the exact topological dimensions of the target neural network. The Xenova/llama2.c-stories15M model is a custom-trained, radically miniaturized instantiation of the Meta LLaMA 2 architecture, originally optimized for the TinyStories dataset.13 The TinyStories dataset contains a synthetically generated corpus of short, vocabulary-restricted narratives designed to prove that language models can learn coherent grammar and logical reasoning without requiring billions of parameters.13 The model's behavior, parameter count, and resulting physical memory layout are strictly governed by specific hyperparameters defined within its config.json file, which is distributed alongside the model.safetensors binary on the Hugging Face hub.21 These parameters dictate the precise mathematical strides and byte offsets required when the conversion script (typically export.py in the llama2.c repository framework) serializes the isolated Safetensors arrays into the flattened binary structure.14 The config.json for Xenova/llama2.c-stories15M defines a compact, dense transformer topology specifically tailored for rapid, localized inference on consumer hardware.22 The core hyperparameters are detailed in the following table.
| Configuration Parameter | JSON Key (config.json) | Target Value | Architectural Implication |
|---|---|---|---|
| Vocabulary Size | vocab\_size | [Figure omitted from source export] | Matches the standard LLaMA 2 tokenizer, projecting dense vectors into a highly dimensional lexical space despite the small core network.22 |
| Embedding Dimension | hidden\_size | [Figure omitted from source export] | The width of the dense vector representation allocated for each token as it propagates through the transformer blocks.22 |
| Intermediate Size | intermediate\_size | [Figure omitted from source export] | The expansion dimension utilized within the Feed-Forward Network (FFN). Aligns with the standard LLaMA scaling ratio of [Figure omitted from source export] relative to the hidden size ([Figure omitted from source export]).13 |
| Transformer Layers | num\_hidden\_layers | [Figure omitted from source export] | The depth of the neural network, dictating that the attention and FFN blocks are repeated six consecutive times.13 |
| Attention Heads | num\_attention\_heads | [Figure omitted from source export] | Dictates the number of parallel representation subspaces. With an embedding dimension of [Figure omitted from source export], each head operates mathematically on a subspace of [Figure omitted from source export] dimensions ([Figure omitted from source export]).13 |
| Key-Value Heads | num\_key\_value\_heads | [Figure omitted from source export] | Because this value equals the number of attention heads, the model utilizes standard Multi-Head Attention (MHA) rather than the Grouped-Query Attention (GQA) used in massive variants.13 |
| Sequence Length | max\_position\_embeddings | [Figure omitted from source export] | The strict context window trained into the model, optimized for highly constrained memory tracking and short narrative generation.13 |
| RMSNorm Epsilon | rms\_norm\_eps | [Figure omitted from source export] | A mathematical constant added to the layer variance to prevent division by zero during normalization routines.22 |
| Tied Embeddings | tie\_word\_embeddings | false | Explicitly dictates that the input embedding matrix and the final output language model head do not share identical memory addresses.22 |
| RoPE Scaling | rope\_scaling | null | The model relies on baseline rotary frequencies without complex dynamic interpolation algorithms to artificially extend the context window.22 |
These specific topological dimensions do not merely represent abstract neural architecture; they explicitly dictate the exact byte-by-byte memory layout of the resulting serialized binary file. Every tensor extracted from the Safetensors container is computationally verified against these dimensions before being flattened, optionally quantized, and appended to the raw binary output stream.14
3. Safetensors Extraction versus Bare-Metal Binary Alignment
The model.safetensors file is an ecosystem-standard, highly secure serialization format.7 Structurally, a Safetensors file initializes with an 8-byte unsigned integer indicating the total byte length of the ensuing JSON header. This JSON header contains a dictionary mapping the hierarchical string names of the model's tensors to their exact starting and ending byte offsets within the file. The remainder of the file is a contiguous buffer of raw tensor byte data.7 While Safetensors is heavily optimized for loading into dynamically typed environments like PyTorch via Python, deploying Xenova/llama2.c-stories15M in a pure C environment necessitates bypassing dynamic dictionary lookups and string hashing entirely.10 In a bare-metal context, the inference engine cannot expend cycles searching for "model.layers.3.self\_attn.q\_proj.weight" within a JSON header to find the memory offset. Instead, it expects the entire file to mirror a predefined, static C-struct where physical data alignment implicitly communicates the topological function.18 The conversion script (export.py) bridges this systemic divide by loading the Safetensors file into host RAM using the Hugging Face transformers and safetensors libraries, extracting each tensor by its canonical string identifier, detaching it from any computational graphs, optionally casting the tensors from hardware-accelerated types like bfloat16 or float16 down to standard IEEE 754 float32 (or performing symmetric quantization to int8), and writing them sequentially to the output binary file.14 Concurrently, the C inference engine (run.c) defines a master memory structure, TransformerWeights, composed entirely of raw floating-point pointers.16 Upon programmatic initialization, the C program invokes the POSIX mmap() system call to map the physical binary file into the kernel's virtual memory address space. Subsequent execution relies on deterministic pointer arithmetic to assign each pointer in the TransformerWeights struct to the correct offset in the mapped file.18 This architectural handshake relies absolutely on the conversion script writing the tensors in the exact chronological order dictated by the C struct.
4. The Binary Header Specification
The precise serialization of the extracted data into the final binary file begins with a meticulously formatted header. The header of the serialized model acts as the architectural blueprint, dictating to the C execution engine how the subsequent gigabytes or megabytes of floating-point data must be partitioned, strided, and addressed by the pointer logic.16 In the standard llama2.c binary format employed for models like stories15M, the header is typically constructed through Python's struct.pack mechanism to ensure strict endianness and byte alignment.14
- Magic Number Validation: To ensure file integrity and prevent the execution of corrupted or incompatible binaries, the header begins with a 32-bit unsigned integer identifier. Commonly, this is written as 0x616b3432 (representing the ASCII string "ak42"), or in derivative GGUF-adjacent local implementations, 0x67676d66.16 If the C engine reads this 4-byte signature and fails to match it against its internal constant, the execution halts immediately to prevent segmentation faults.27
- Version Identifier: A 32-bit integer denoting the structural version of the serialization protocol, allowing the inference engine to dynamically adjust its parsing logic for legacy files.14
- Hyperparameter Block: Seven contiguous 32-bit integers (encoded as iiiiiii in struct.pack) are sequentially written into the header buffer.14 These directly mirror the values extracted from config.json and are mandated as follows:
- dim ([Figure omitted from source export])
- hidden\_dim ([Figure omitted from source export])
- n\_layers ([Figure omitted from source export])
- n\_heads ([Figure omitted from source export])
- n\_kv\_heads ([Figure omitted from source export])
- vocab\_size ([Figure omitted from source export])
- max\_seq\_len ([Figure omitted from source export]).13
- Architectural Configuration Flags: Modern iterations of the conversion format write additional single-byte or integer flags to communicate nuanced architectural states. Chief among these is a boolean byte flag (B) indicating shared\_classifier. For the Xenova/llama2.c-stories15M model, because the embeddings are untied, this value is explicitly written as [Figure omitted from source export].26 Furthermore, an integer indicating the group\_size is written if the model utilizes block-wise symmetric quantization.26
- Memory Alignment Padding: To maximize the performance of CPU caching mechanisms, the header is intentionally padded with null bytes out to a fixed length (typically [Figure omitted from source export] bytes). This ensures that the primary weight vectors begin exactly on a 256-byte aligned memory boundary, which is structurally critical for maximizing the throughput of Single Instruction, Multiple Data (SIMD) execution units and Advanced Vector Extensions (AVX2) during subsequent matrix multiplication routines.10
5. Safetensors-to-SLM Exact Tensor Mappings
Following the 256-byte header, the export.py script traverses the Safetensors dictionary object and serializes the multidimensional arrays using functions like serialize\_fp32.14 This function detaches the tensor from the PyTorch computation graph, forces it to host CPU memory, flattens it from an N-dimensional matrix to a contiguous 1D vector (using the .view(-1) operation), casts it to standard 32-bit floating point, and writes the raw sequential bytes (struct.pack(f'{len(d)}f', \*d)) directly to the disk.14 To enable flawless mmap() alignment, the tensors must be extracted from the Hugging Face layout and written to the binary file in the exact programmatic sequence expected by the C inference engine. The exhaustive mapping protocol for Xenova/llama2.c-stories15M is structurally defined across several discrete neural components.
5.1 The Input Embedding Matrix
The foremost data block in the neural network is the token embedding matrix. This tensor is responsible for projecting discrete integer token IDs (ranging from [Figure omitted from source export] to [Figure omitted from source export]) into the dense, continuous vector space where the transformer architecture performs spatial reasoning.3
| Safetensors Canonical Name | SLM C-Struct Pointer Assignment | Shape Mathematics | Total Scalar Elements |
|---|---|---|---|
| model.embed\_tokens.weight | w-\>token\_embedding\_table | vocab\_size [Figure omitted from source export] dim | [Figure omitted from source export] |
During conversion, the script extracts the model.embed\_tokens.weight payload, flattens it into a 1D array of exactly 9,216,000 floats, and writes it to the binary stream immediately following the header padding.16 In a 32-bit floating-point execution, this single matrix occupies [Figure omitted from source export] megabytes of the file architecture.
5.2 Attention Normalization Blocks
The core of the LLaMA 2 framework is predicated upon repeating transformer layers, of which the stories15M model dictates six.13 To maintain cache locality, the export script iterates sequentially through each layer index ([Figure omitted from source export] from [Figure omitted from source export] to [Figure omitted from source export]) and extracts the tensors for that layer in a strict sub-sequence.16 Prior to executing the self-attention mathematical mechanism, the transformer hidden states are normalized using Root Mean Square Normalization (RMSNorm).29 LLaMA architectures eschew traditional LayerNorm in favor of RMSNorm because it normalizes the input variance without requiring the computationally expensive step of mean centering.29
| Safetensors Canonical Name | SLM C-Struct Pointer Assignment | Shape Mathematics | Total Scalar Elements |
|---|---|---|---|
| model.layers.{i}.input\_layernorm.weight | w-\>rms\_att\_weight | n\_layers [Figure omitted from source export] dim | [Figure omitted from source export] |
Crucially, in the flattened C-struct, the engine does not allocate six distinct arrays for these weights. Instead, rms\_att\_weight is a single contiguous array spanning all layers. The conversion script extracts layer 0, writes 288 floats, extracts layer 1, writes 288 floats, and so on. The runtime C code then accesses the specific weights for layer [Figure omitted from source export] utilizing linear pointer arithmetic: w-\>rms\_att\_weight \+ i \* dim.18 The Safetensors file stores only the learned scaling weights ([Figure omitted from source export]).29 During C inference, the engine mathematically calculates the sum of the squared elements of the activation vector, divides by the dimension, adds the rms\_norm\_eps ([Figure omitted from source export]) defined in the config.json, calculates the inverse square root, and scales the output using this memory-mapped vector.22
5.3 Self-Attention Linear Projections
The self-attention mechanism relies on heavily optimized linear projections to generate Queries (Q), Keys (K), Values (V), and the final output aggregation (O). Because Xenova/llama2.c-stories15M defines n\_heads equal to n\_kv\_heads ([Figure omitted from source export]), it relies on standard Multi-Head Attention, meaning the Q, K, and V projections all possess identical geometric shapes.13
| Safetensors Canonical Name | SLM C-Struct Pointer Assignment | Shape Mathematics | Total Scalar Elements per Layer |
|---|---|---|---|
| model.layers.{i}.self\_attn.q\_proj.weight | w-\>wq | dim [Figure omitted from source export] dim | [Figure omitted from source export] |
| model.layers.{i}.self\_attn.k\_proj.weight | w-\>wk | dim [Figure omitted from source export] dim | [Figure omitted from source export] |
| model.layers.{i}.self\_attn.v\_proj.weight | w-\>wv | dim [Figure omitted from source export] dim | [Figure omitted from source export] |
| model.layers.{i}.self\_attn.o\_proj.weight | w-\>wo | dim [Figure omitted from source export] dim | [Figure omitted from source export] |
The serialization script allocates massive contiguous blocks for wq, wk, wv, and wo. Across all 6 transformer layers, each of these projection types aggregates to [Figure omitted from source export] contiguous elements.16 The LLaMA framework explicitly omits bias vectors in these attention projections, further simplifying the serialization stream to pure weight matrices.
5.4 Feed-Forward Normalization
Following the completion of the self-attention block and the addition of its residual connection, the output vectors are normalized a second time prior to entering the dense Feed-Forward Network.3
| Safetensors Canonical Name | SLM C-Struct Pointer Assignment | Shape Mathematics | Total Scalar Elements |
|---|---|---|---|
| model.layers.{i}.post\_attention\_layernorm.weight | w-\>rms\_ffn\_weight | n\_layers [Figure omitted from source export] dim | [Figure omitted from source export] |
Mirroring the attention normalization strategy, these vectors are sequentially mapped and accessed via the pointer arithmetic offset i \* dim during the inference loop.16
5.5 Feed-Forward Network and SwiGLU Activation
A major architectural divergence in the LLaMA 2 framework from earlier transformer models is the replacement of the standard ReLU-based multilayer perceptron with a SwiGLU (Swish Gated Linear Unit) activation network.16 The execution of SwiGLU mathematically requires three distinct, parallel projection matrices rather than two: a gate projection, an up projection, and a down projection.
| Safetensors Canonical Name | SLM C-Struct Pointer Assignment | Shape Mathematics | Total Scalar Elements per Layer |
|---|---|---|---|
| model.layers.{i}.mlp.gate\_proj.weight | w-\>w1 | dim [Figure omitted from source export] hidden\_dim | [Figure omitted from source export] |
| model.layers.{i}.mlp.down\_proj.weight | w-\>w2 | hidden\_dim [Figure omitted from source export] dim | [Figure omitted from source export] |
| model.layers.{i}.mlp.up\_proj.weight | w-\>w3 | dim [Figure omitted from source export] hidden\_dim | [Figure omitted from source export] |
In the runtime binary execution, the forward pass calculates the activation using the mapped pointers as follows: [Figure omitted from source export] Where [Figure omitted from source export] denotes element-wise multiplication, and [Figure omitted from source export] represents the SiLU (Sigmoid Linear Unit) function. The highly dimensional intermediate result is subsequently projected back down to the baseline dimension via [Figure omitted from source export] (down\_proj). Because hidden\_dim expands the vector space significantly to 768 parameters, the .slm binary format accommodates massive contiguous blocks of memory for w1, w2, and w3.16 Across all 6 layers, the serialization logic writes [Figure omitted from source export] parameters per SwiGLU tensor category. Organizing these matrices with strict spatial locality ensures that vector-matrix multiplications—which are routinely optimized using OpenMP multithreading pragmas (\#pragma omp parallel for) and intrinsic SIMD instructions in C—operate on tightly packed cache lines without inducing memory stalls.10
5.6 Output Normalization and Untied Classifier Head
After the sequence traverses all six transformer layers, the output vectors undergo a final normalization pass before being mathematically projected back into the vast probability space of the vocabulary to predict the next sequential token.32
| Safetensors Canonical Name | SLM C-Struct Pointer Assignment | Shape Mathematics | Total Scalar Elements |
|---|---|---|---|
| model.norm.weight | w-\>rms\_final\_weight | dim | [Figure omitted from source export] |
| lm\_head.weight | w-\>wcls | vocab\_size [Figure omitted from source export] dim | [Figure omitted from source export] |
The treatment of the Language Modeling Head (lm\_head.weight) represents a critical architectural juncture governed directly by the config.json specifications.22 In many highly compressed neural network architectures, the token embedding matrix and the final output language modeling head are "tied".32 This parameter-sharing technique dictates that the network uses the exact same weight values to project tokens into embeddings as it uses to project the final embeddings back into probabilities.32 By physically sharing the same memory block, the network avoids duplicating a massive tensor (in this case, over 9 million parameters), which drastically reduces the total memory payload—a highly desirable trait for edge deployments where RAM is heavily constrained.26 However, the configuration for Xenova/llama2.c-stories15M explicitly dictates "tie\_word\_embeddings": false.22 The export.py script parses this parameter flag during the initial conversion phase and fundamentally alters its binary serialization strategy.26 Because the embeddings are untied in the 15M model, the exporter writes shared\_classifier \= 0 to the aforementioned binary header.26 In legacy iterations of the conversion format, this untied state was occasionally signaled via a hack involving a positive vocab\_size integer, while tied embeddings forced a negative integer into the header.15 Because the architecture requires untied weights, the C inference engine is signaled to allocate separate virtual memory space for the wcls pointer, and the conversion script must physically extract and serialize the distinct [Figure omitted from source export] floating-point elements of lm\_head.weight to the absolute end of the binary file.26 This architectural decision expands the model's footprint by approximately 36.8 megabytes, essentially doubling the memory required for the vocabulary interface, but provides the network with demonstrably greater mathematical expressivity and accuracy at the final output layer.15
6. The Non-Serialized Dynamic Physics of Rotary Positional Embeddings (RoPE)
Unlike legacy transformer models that rely on absolute positional embeddings—which are learned during training and stored directly as discrete weight matrices in the Safetensors file—positional awareness in the LLaMA 2 framework is governed by Rotary Positional Embeddings (RoPE). RoPE dictates spatial relationships dynamically by rotating the self-attention Query and Key vectors within the complex plane based on their absolute sequence position.12 A critical characteristic of the Safetensors-to-SLM conversion process is how it handles the RoPE mechanism. The config.json for llama2.c-stories15M dictates "rope\_scaling": null, signifying that standard rotary frequencies must be applied mathematically without invoking advanced dynamic interpolations to artificially stretch the 256-token context window.22 In the llama2.c binary inference engine, the precomputed trigonometric values necessary for this complex rotation are tracked in the TransformerWeights struct via specialized pointers.31
| SLM C-Struct Pointer Assignment | Shape Mathematics | Underlying Function |
|---|---|---|
| w-\>freq\_cis\_real | max\_seq\_len [Figure omitted from source export] (head\_size / [Figure omitted from source export]) | Real components of the RoPE trigonometric angles.31 |
| w-\>freq\_cis\_imag | max\_seq\_len [Figure omitted from source export] (head\_size / [Figure omitted from source export]) | Imaginary components of the RoPE trigonometric angles.31 |
For a maximum context length of 256 and an attention head size of 48, the inference engine requires 24 pairs of real and imaginary floating-point values for every sequence position.13 However, these values are entirely absent from the original Hugging Face Safetensors file.14 During the serialization phase, export.py does not write RoPE weights into the .slm binary because they are entirely deterministic and mathematically unlearned.14 Instead, during the initialization boot sequence of the C program, the freq\_cis tables are dynamically allocated in host RAM.31 The engine executes a mathematical loop utilizing the standard inverse frequency formulation to generate the complex angles on-the-fly, ensuring that the necessary spatial relationships between generated tokens are maintained computationally during the self-attention phase without needlessly expanding the static binary file size.31
7. Mathematical Quantization and Data Compression Topologies
While Xenova/llama2.c-stories15M is considered diminutive relative to hyperscale models, executing 15 million 32-bit floating-point (FP32) operations still incurs a memory cost of roughly 60 megabytes and stresses the memory bandwidth limits of highly constrained SoCs and edge processors.4 To alleviate this physical bottleneck, the export.py script integrates aggressive quantization subroutines, directly transforming high-precision formats into significantly denser integer formats.3 During the conversion process to formats like INT8, the script invokes a quantization pipeline (such as the quantize\_q80 function) across the vast majority of the projection tensors extracted from the Safetensors file.14 This pipeline mathematically compresses the model via symmetric block-wise scaling.
- Block Chunking: The high-precision weight data is divided into contiguous, smaller arrays defined by a specific group\_size (commonly set to 64 or 128 elements to balance precision retention with memory density).23
- Scale Formulation: For each block, the script identifies the maximum absolute floating-point value (wmax). It then calculates an independent, block-specific scale factor using the formula: scale \= wmax / 127.0.14
- Integer Projection: Every original floating-point value within the group is mathematically divided by the scaling factor, clamped, and then rounded to the nearest 8-bit signed integer (int8\_t).14
Within the compiled binary .slm format, these quantized structures are no longer mapped as simple floating-point blocks. Instead, they correspond to a specialized QuantizedTensor C-struct, which encapsulates pointers to both the heavily compressed int8\_t array (q) and the smaller auxiliary array of floating-point scaling factors (s) necessary for dynamic dequantization during the inference forward pass.29 The deployment of models like Xenova/llama2.c-stories15M heavily leverages these quantizations. In environments utilizing WebGPU or WebAssembly through libraries like transformers.js, the Safetensors baseline is alternatively exported to heavily quantized ONNX architectures, producing variants such as decoder\_model\_merged\_quantized.onnx or model\_q4f16.onnx.5 Within the pure C environment, reducing the weights from FP32 to Q8\_0 transforms the active memory footprint of the stories15M model from approximately 60 megabytes down to an agile 15 megabytes. This radical reduction vastly mitigates the memory-bandwidth wall and allows the entire neural network to comfortably reside within the higher tiers of the CPU cache hierarchy, dramatically accelerating inference tokens-per-second on standalone Raspberry Pi systems or offline mobile environments.13
8. Tokenizer Conversion Protocol and Vocabulary Serialization
A small language model functions purely as a mathematical engine and is fundamentally incapable of parsing raw ASCII or UTF-8 text strings; it must rely entirely on an external tokenizer to segment human-readable characters into the discrete integer tokens mapped by its embedding table.28 The Xenova/llama2.c-stories15M architecture utilizes a Byte Pair Encoding (BPE) tokenizer comprising [Figure omitted from source export] distinct semantic tokens.22 Within the standard Hugging Face ecosystem, this vocabulary map is typically defined via complex JSON dictionary files (tokenizer.json and tokenizer\_config.json) or via a Google SentencePiece protobuf binary (tokenizer.model).21 To preserve the zero-dependency, bare-metal nature of the C inference engine, these highly formatted ecosystem files must be aggressively converted into a bespoke, contiguous binary format, canonically named tokenizer.bin.13 A dedicated conversion script (tokenizer.py) parses the JSON or SentencePiece configurations and serializes the vocabulary dictionary utilizing a strict sequence of bytes 13:
- Global Vocabulary Count: The script initiates the file by writing the total number of recognized tokens ([Figure omitted from source export]) as an unpadded 32-bit integer, providing the C program with its primary loop constraint.18
- Sequential Token Definitions: The script iterates chronologically through all [Figure omitted from source export] token definitions. For each respective entry, it commits three critical components to the binary stream:
- Merge Score: A 32-bit floating-point value representing the mathematical merge score or empirical frequency of the token string. The BPE decoding algorithm utilizes this float during the inference loop to heuristically resolve overlaps and determine merge priorities when constructing outputs.39
- Byte Length Header: A discrete 32-bit integer (len) specifying the precise byte length of the ensuing token string payload.18
- String Data: The raw UTF-8 byte array of the token string itself, unpadded and unpackaged.
During active inference generation, the C program executes an initialization sequence where it dynamically allocates an array of string pointers, ingests tokenizer.bin, and structures a fast-lookup array.13 As the neural network classifier head produces raw logit probabilities and selects integer IDs, the execution engine uses these IDs as direct indices into the array, instantly mapping the integers back into human-readable text via the cached UTF-8 strings. The structural matching of vocab\_size between the .slm binary header and the external tokenizer file is strictly enforced; a fatal assertion failure will halt execution if the binary model expects 32,000 tokens but the tokenizer.bin provides an incongruent count.39 Interestingly, while the TinyStories dataset used to train stories15M is highly constrained and likely only utilizes a small subset of words, the model retains the full 32,000-token capacity of the LLaMA 2 architecture.13 While a custom vocabulary size of [Figure omitted from source export] could compress the embedding tables and classifier heads even further, maintaining the [Figure omitted from source export] size ensures the model remains compatible with standard, universally deployed tokenization algorithms.13
9. System-Level Implications of Mmap Execution
The comprehensive re-architecting of the data format—moving from a fragmented, dynamically hashed Safetensors dictionary structure into a single, cohesive, flattened binary file—is the fundamental engineering mechanism that unlocks the true potential of SLMs in highly constrained edge environments.4 When the custom run.c engine initializes to execute the llama2.c-stories15M model, it avoids utilizing standard heap allocations or fread() buffering techniques for the model weights.15 Instead, it relies extensively on POSIX memory-mapped file I/O operations (mmap()).17 Because the statically defined C-struct TransformerWeights perfectly mirrors the exact byte-offsets established during the export.py conversion process, the host operating system can be instructed to map the physical sectors of the storage drive directly to the virtual memory space of the executing process without user-space duplication.18 This architectural alignment achieves several highly optimized computational outcomes: First, it enables near zero-copy initialization. The application loads instantaneously because the central processor is never required to execute expensive buffer transfers or physically duplicate the [Figure omitted from source export] megabytes of floating-point weights from storage into the active system RAM.10 Second, it leverages kernel-level demand paging. The operating system handles memory management natively, paging in discrete [Figure omitted from source export]KB blocks of the serialized model weights from disk to the L1 or L2 CPU caches only at the exact microsecond when the matrix multiplication inner loops attempt to access them.17 This precise on-demand memory access severely restricts the active memory footprint and mathematically prevents Out-Of-Memory (OOM) faults on devices like standard web browser tabs, localized edge gateways, or specialized embedded systems with highly constrained physical RAM capacities.20 Finally, the rigid, 1D sequential flattening of the attention, SwiGLU, and normalization tensors ensures a profound degree of spatial locality of reference.10 As the inner loops of the self-attention and Feed-Forward matrix multiplications iterate sequentially over the data space, the hardware's predictive prefetcher recognizes the linear memory access pattern. It can proactively stream contiguous, uninterrupted blocks of memory directly into the CPU's vector execution registers. This alignment ensures that highly parallelized computational instructions—such as those dictated by OpenMP (\#pragma omp parallel for) and intrinsic SIMD architectures—operate at maximum theoretical bandwidth, drastically improving the tokens-per-second generation speed of the SLM even on severely underpowered, passively cooled hardware targets.10
Works cited
- What Are Small Language Models (SLMs)? \- Microsoft Azure, accessed June 29, 2026, https://azure.microsoft.com/en-us/resources/cloud-computing-dictionary/what-are-small-language-models
- accessed June 29, 2026, https://docs.lm-kit.com/lm-kit-net/guides/glossary/SLM.html\#:\~:text=A%20Small%20Language%20Model%20(SLM)%20offers%20a%20streamlined%20approach%20to,Large%20Language%20Models%20(LLMs).
- What are Small Language Models (SLM)? \- IBM, accessed June 29, 2026, https://www.ibm.com/think/topics/small-language-models
- Small Language Models (SLM): A Comprehensive Overview \- Hugging Face, accessed June 29, 2026, https://huggingface.co/blog/jjokah/small-language-model
- Web Browsers as a New Home for Language Models? | by Andrii Chumak | GoodData.AI Developers | Medium, accessed June 29, 2026, https://medium.com/gooddata-developers/web-browsers-as-a-new-home-for-language-models-c2024a3f011b
- Unleashing the Power of Small Language Models: Running SLMs on Your Browser, accessed June 29, 2026, https://codezen.medium.com/unleashing-the-power-of-self-learning-machines-running-slms-on-your-browser-2ed3f3a3496e
- Post-Quantization for SLMs: Accelerating CPU Inference | by Jaswanth Sabbineni \- Medium, accessed June 29, 2026, https://medium.com/the-ai-mindscape/post-quantization-optimization-for-slms-accelerating-cpu-inference-44380758d986
- Safe & Stable: Conversion Tool for Safer Stable Diffusion Models Distribution \- Reddit, accessed June 29, 2026, https://www.reddit.com/r/StableDiffusion/comments/zcbcr8/safe\_stable\_conversion\_tool\_for\_safer\_stable/
- paiml/apr-cookbook: Examples of .apr format models \- GitHub, accessed June 29, 2026, https://github.com/paiml/apr-cookbook
- pierrel55/llama\_st: Load and run Llama from safetensors files in C \- GitHub, accessed June 29, 2026, https://github.com/pierrel55/llama\_st
- How to run Llama 2 LLM in C \- by Kevin Haritmonds \- Medium, accessed June 29, 2026, https://medium.com/@mckev/how-to-run-llama-2-llm-in-c-843b462daed9
- Understanding Llama2.c And ChatGPT Inferencing – A Visual Design Walkthrough, accessed June 29, 2026, https://www.signalpop.com/2024/02/10/understanding-llama2-c-and-chatgpt-a-visual-design-walkthrough/
- GitHub \- karpathy/llama2.c: Inference Llama 2 in one file of pure C, accessed June 29, 2026, https://github.com/karpathy/llama2.c
- export.py · teragron/LlamaReviews at main \- Hugging Face, accessed June 29, 2026, https://huggingface.co/spaces/teragron/LlamaReviews/blob/main/export.py
- llama2.c/run.c at master · karpathy/llama2.c · GitHub, accessed June 29, 2026, https://github.com/karpathy/llama2.c/blob/master/run.c
- 探索llama2.c:纯C语言实现的Llama 2推理引擎 \- CSDN博客, accessed June 29, 2026, https://blog.csdn.net/gitblog\_00043/article/details/139038758
- Build a Small Language Model (SLM) From Scratch | by Shravan Kumar | Medium, accessed June 29, 2026, https://medium.com/@shravankoninti/build-a-small-language-model-slm-from-scratch-3ddd13fa6470
- RahulSChand/llama2.c-for-dummies \- GitHub, accessed June 29, 2026, https://github.com/RahulSChand/llama2.c-for-dummies
- warmcat/libclamma: Improved llama2.c \- GitHub, accessed June 29, 2026, https://github.com/warmcat/libclamma
- Building a Small Language Model(SLM) from Scratch \- GitHub, accessed June 29, 2026, https://github.com/ChaitanyaK77/Building-a-Small-Language-Model-SLM-
- Xenova/llama2.c-stories15M \- ONNX 模型库, accessed June 29, 2026, https://onnx.bimant.com/models/Xenova/llama2.c-stories15M
- config.json · Xenova/llama2.c-stories15M at ... \- Hugging Face, accessed June 29, 2026, https://huggingface.co/Xenova/llama2.c-stories15M/blob/9397aa7180a7b88fa20a0197da2a0601973373e9/config.json
- llama2.c/export.py at master · karpathy/llama2.c · GitHub, accessed June 29, 2026, https://github.com/karpathy/llama2.c/blob/master/export.py
- Converting LLaMa 2 bin files to safetensors changes the output \- Hugging Face Forums, accessed June 29, 2026, https://discuss.huggingface.co/t/converting-llama-2-bin-files-to-safetensors-changes-the-output/59034
- model.safetensors · aiversezone/my-custom-slm at main \- Hugging Face, accessed June 29, 2026, https://huggingface.co/aiversezone/my-custom-slm/blob/main/model.safetensors
- Upload 21 files · teragron/TinyStories at 233119d \- Hugging Face, accessed June 29, 2026, https://huggingface.co/spaces/teragron/TinyStories/commit/233119d4973907e01db21718b5fe6285e3b338f3
- All-in-One (AIO) Image \- Models are not loading due to "grpc service not ready" · Issue \#2103 · mudler/LocalAI \- GitHub, accessed June 29, 2026, https://github.com/mudler/LocalAI/issues/2103
- Small Language Models Explained. What are SLMs? | by Siddharth Prothia \- Medium, accessed June 29, 2026, https://medium.com/@sprothia935/small-language-models-explained-d9a557b66bbc
- qwen3.c/runq.c at main · adriancable/qwen3.c · GitHub, accessed June 29, 2026, https://github.com/adriancable/qwen3.c/blob/main/runq.c
- bdzwillo/llama\_walkthrough: Llama2 transformer walkthrough with code examples \- GitHub, accessed June 29, 2026, https://github.com/bdzwillo/llama\_walkthrough
- Running on GPU with OpenMP offloading by RahulSChand · Pull Request \#166 · karpathy/llama2.c \- GitHub, accessed June 29, 2026, https://github.com/karpathy/llama2.c/pull/166/changes
- Building a Small Language Model (SLM) from Scratch: A Complete Guide | by ashwin g, accessed June 29, 2026, https://medium.com/@ashwingadam/building-a-small-language-model-slm-from-scratch-a-complete-guide-95f9c000b713
- Vocabulary Trimming: An Easy and Effective Method for SLM Acceleration \- SqueezeBits, accessed June 29, 2026, https://blog.squeezebits.com/vocabulary-trimming-methods
- SMART SLM: Structured Memory and Reasoning Transformer, A Small Language Model for Accurate Document Assistance \- arXiv, accessed June 29, 2026, https://arxiv.org/html/2512.21280v1
- llama \
tie\_word\_embeddings\ignored on cpu and with auto dtype only · Issue \#33689 · huggingface/transformers \- GitHub, accessed June 29, 2026, https://github.com/huggingface/transformers/issues/33689 - What does freq\_cis mean? · Issue \#113 · karpathy/llama2.c · GitHub, accessed June 29, 2026, https://github.com/karpathy/llama2.c/issues/113
- Running Small Language Models (SLMs) on CPUs: A Practical Guide \- Towards AI, accessed June 29, 2026, https://towardsai.net/p/machine-learning/running-small-language-models-slms-on-cpus-a-practical-guide
- Small Language Models (SLM) – Edge AI Engineering \- GitHub Pages, accessed June 29, 2026, https://mjrovai.github.io/EdgeML\_Made\_Ease\_ebook/raspi/llm/slm\_intro.html
- Questions about converting models and tokenizers downloaded from huggingface · Issue \#431 · karpathy/llama2.c \- GitHub, accessed June 29, 2026, https://github.com/karpathy/llama2.c/issues/431
- Error: Unable to open tokenizer file tokenizer.bin · Issue \#66 · karpathy/llama2.c \- GitHub, accessed June 29, 2026, https://github.com/karpathy/llama2.c/issues/66
- malloc failed\! on stories260 model · Issue \#510 · karpathy/llama2.c \- GitHub, accessed June 29, 2026, https://github.com/karpathy/llama2.c/issues/510
- Optimizing SLMs on Intel® Xeon® Processors: A llama.cpp Performance Study, accessed June 29, 2026, https://community.intel.com/t5/Blogs/Tech-Innovation/Artificial-Intelligence-AI/Optimizing-SLMs-on-Intel-Xeon-Processors-A-llama-cpp-Performance/post/1734305