Skip to content

Commit c3b1d10

Browse files
authored
Merge pull request #6 from xadupre/copilot/add-unit-test-tiny-llm
Add offline unit test for arnir0/Tiny-LLM with random weights
2 parents 61a53f3 + c0cf4f5 commit c3b1d10

1 file changed

Lines changed: 88 additions & 0 deletions

File tree

tests/test_tiny_llm.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"""
1111

1212
import os
13+
import tempfile
1314
import unittest
1415

1516
MODEL_NAME = "arnir0/Tiny-LLM"
@@ -54,6 +55,93 @@ def test_tiny_llm_fp32_cpu(self):
5455

5556
onnxruntime.InferenceSession(onnx_path, providers=["CPUExecutionProvider"])
5657

58+
def test_tiny_llm_fp32_cpu_random_weights(self):
59+
"""
60+
Convert a model with the same architecture as arnir0/Tiny-LLM but with
61+
randomly initialised weights to an fp32 ONNX model targeting the CPU
62+
execution provider.
63+
64+
Using random weights avoids downloading the pretrained weights from
65+
Hugging Face, making this test completely offline and suitable for CI
66+
environments without internet access. The full 8-layer config is saved
67+
locally, but only one hidden layer is materialised during conversion
68+
(via the ``num_hidden_layers`` extra option passed to ``create_model``)
69+
to keep the test fast.
70+
71+
The test verifies that:
72+
* ``create_model`` completes without error when given a local model directory.
73+
* The expected ``model.onnx`` file is written to the output directory.
74+
* The produced ONNX file can be loaded by ``onnxruntime``.
75+
"""
76+
from tokenizers import Tokenizer
77+
from tokenizers.models import WordLevel
78+
from transformers import AutoModelForCausalLM, LlamaConfig, PreTrainedTokenizerFast
79+
80+
from modelbuilder.builder import create_model
81+
82+
# Config matching the arnir0/Tiny-LLM architecture (LlamaForCausalLM,
83+
# ~10M parameters). These values are hardcoded so the test runs
84+
# completely offline without downloading any files from Hugging Face.
85+
config = LlamaConfig(
86+
architectures=["LlamaForCausalLM"],
87+
bos_token_id=1,
88+
eos_token_id=2,
89+
hidden_act="silu",
90+
hidden_size=512,
91+
intermediate_size=1376,
92+
max_position_embeddings=2048,
93+
model_type="llama",
94+
num_attention_heads=8,
95+
num_hidden_layers=8,
96+
num_key_value_heads=4,
97+
rms_norm_eps=1e-05,
98+
rope_theta=10000.0,
99+
vocab_size=32000,
100+
)
101+
102+
with tempfile.TemporaryDirectory() as model_dir:
103+
# Create a model with random weights from the config and save it.
104+
model = AutoModelForCausalLM.from_config(config)
105+
model.save_pretrained(model_dir)
106+
107+
# Create and save a minimal tokenizer so that save_processing()
108+
# inside create_model() can load and copy it to the output folder.
109+
vocab = {"<unk>": 0, "<s>": 1, "</s>": 2}
110+
tokenizer = PreTrainedTokenizerFast(
111+
tokenizer_object=Tokenizer(WordLevel(vocab=vocab, unk_token="<unk>")),
112+
bos_token="<s>",
113+
eos_token="</s>",
114+
unk_token="<unk>",
115+
)
116+
tokenizer.save_pretrained(model_dir)
117+
118+
output_dir = os.path.join(model_dir, "onnx_output")
119+
cache_dir = os.path.join(model_dir, "cache")
120+
os.makedirs(output_dir, exist_ok=True)
121+
os.makedirs(cache_dir, exist_ok=True)
122+
123+
create_model(
124+
model_name=MODEL_NAME,
125+
input_path=model_dir,
126+
output_dir=output_dir,
127+
precision="fp32",
128+
execution_provider="cpu",
129+
cache_dir=cache_dir,
130+
num_hidden_layers=1,
131+
)
132+
133+
onnx_path = os.path.join(output_dir, "model.onnx")
134+
assert os.path.exists(
135+
onnx_path
136+
), f"Expected ONNX model not found at {onnx_path}"
137+
138+
# Validate that the ONNX model can be loaded by the runtime.
139+
import onnxruntime
140+
141+
onnxruntime.InferenceSession(
142+
onnx_path, providers=["CPUExecutionProvider"]
143+
)
144+
57145

58146
if __name__ == "__main__":
59147
unittest.main(verbosity=2)

0 commit comments

Comments
 (0)