llama.cpp/tests/test_llama.py

205 lines
6.3 KiB
Python
Raw Normal View History

2023-11-10 10:39:42 +00:00
import ctypes
import pytest
2023-11-10 10:39:42 +00:00
2023-04-05 07:23:15 +00:00
import llama_cpp
2023-08-24 05:01:20 +00:00
MODEL = "./vendor/llama.cpp/models/ggml-vocab-llama.gguf"
2023-04-05 07:23:15 +00:00
def test_llama_cpp_tokenization():
llama = llama_cpp.Llama(model_path=MODEL, vocab_only=True, verbose=False)
2023-04-05 07:23:15 +00:00
assert llama
2023-11-06 14:16:36 +00:00
assert llama._ctx.ctx is not None
2023-04-05 07:23:15 +00:00
text = b"Hello World"
tokens = llama.tokenize(text)
assert tokens[0] == llama.token_bos()
2023-08-27 16:59:20 +00:00
assert tokens == [1, 15043, 2787]
detokenized = llama.detokenize(tokens)
assert detokenized == text
tokens = llama.tokenize(text, add_bos=False)
assert tokens[0] != llama.token_bos()
2023-08-27 16:59:20 +00:00
assert tokens == [15043, 2787]
detokenized = llama.detokenize(tokens)
2023-08-27 16:59:20 +00:00
assert detokenized != text
2023-04-05 07:23:15 +00:00
text = b"Hello World</s>"
tokens = llama.tokenize(text)
assert tokens[-1] != llama.token_eos()
assert tokens == [1, 15043, 2787, 829, 29879, 29958]
tokens = llama.tokenize(text, special=True)
assert tokens[-1] == llama.token_eos()
2023-11-20 19:11:33 +00:00
assert tokens == [1, 15043, 2787, 2]
2023-11-21 04:23:18 +00:00
text = b""
tokens = llama.tokenize(text, add_bos=True, special=True)
assert tokens[-1] != llama.token_eos()
assert tokens == [llama.token_bos()]
assert text == llama.detokenize(tokens)
@pytest.fixture
def mock_llama(monkeypatch):
def setup_mock(llama: llama_cpp.Llama, output_text: str):
llama.reset()
n_vocab = llama.n_vocab()
output_tokens = llama.tokenize(
output_text.encode("utf-8"), add_bos=True, special=True
)
n = 0
last_n_tokens = 0
def mock_decode(ctx: llama_cpp.llama_context_p, batch: llama_cpp.llama_batch):
nonlocal n
nonlocal last_n_tokens
# Test some basic invariants of this mocking technique
assert ctx == llama._ctx.ctx
assert llama.n_tokens == n
assert batch.n_tokens > 0
n += batch.n_tokens
last_n_tokens = batch.n_tokens
return 0
def mock_get_logits(*args, **kwargs):
nonlocal last_n_tokens
size = n_vocab * last_n_tokens
return (llama_cpp.c_float * size)()
def mock_sample(*args, **kwargs):
nonlocal n
if n < len(output_tokens):
return output_tokens[n]
else:
return llama.token_eos()
monkeypatch.setattr("llama_cpp.llama_cpp.llama_decode", mock_decode)
monkeypatch.setattr("llama_cpp.llama_cpp.llama_get_logits", mock_get_logits)
monkeypatch.setattr("llama_cpp.llama_cpp.llama_sample_token", mock_sample)
return setup_mock
def test_llama_patch(mock_llama):
2023-11-10 10:39:42 +00:00
n_ctx = 128
llama = llama_cpp.Llama(model_path=MODEL, vocab_only=True, n_ctx=n_ctx)
2023-11-06 14:16:36 +00:00
n_vocab = llama_cpp.llama_n_vocab(llama._model.model)
2023-11-10 10:39:42 +00:00
assert n_vocab == 32000
2023-04-05 07:23:15 +00:00
2023-11-20 19:11:33 +00:00
text = "The quick brown fox"
2023-04-05 07:23:15 +00:00
output_text = " jumps over the lazy dog."
2023-11-21 04:23:18 +00:00
all_text = text + output_text
2023-04-05 07:23:15 +00:00
2023-11-21 04:23:18 +00:00
## Test basic completion from bos until eos
mock_llama(llama, all_text)
completion = llama.create_completion("", max_tokens=36)
assert completion["choices"][0]["text"] == all_text
assert completion["choices"][0]["finish_reason"] == "stop"
2023-04-05 07:23:15 +00:00
## Test basic completion until eos
2023-11-21 04:23:18 +00:00
mock_llama(llama, all_text)
2023-04-05 07:23:15 +00:00
completion = llama.create_completion(text, max_tokens=20)
assert completion["choices"][0]["text"] == output_text
assert completion["choices"][0]["finish_reason"] == "stop"
## Test streaming completion until eos
2023-11-21 04:23:18 +00:00
mock_llama(llama, all_text)
2023-10-19 06:55:29 +00:00
chunks = list(llama.create_completion(text, max_tokens=20, stream=True))
2023-04-05 07:23:15 +00:00
assert "".join(chunk["choices"][0]["text"] for chunk in chunks) == output_text
2023-10-19 06:56:45 +00:00
assert chunks[-1]["choices"][0]["finish_reason"] == "stop"
2023-04-05 07:23:15 +00:00
## Test basic completion until stop sequence
2023-11-21 04:23:18 +00:00
mock_llama(llama, all_text)
2023-04-05 07:23:15 +00:00
completion = llama.create_completion(text, max_tokens=20, stop=["lazy"])
assert completion["choices"][0]["text"] == " jumps over the "
assert completion["choices"][0]["finish_reason"] == "stop"
## Test streaming completion until stop sequence
2023-11-21 04:23:18 +00:00
mock_llama(llama, all_text)
chunks = list(
llama.create_completion(text, max_tokens=20, stream=True, stop=["lazy"])
)
2023-04-05 07:23:15 +00:00
assert (
"".join(chunk["choices"][0]["text"] for chunk in chunks) == " jumps over the "
)
2023-10-19 06:56:45 +00:00
assert chunks[-1]["choices"][0]["finish_reason"] == "stop"
2023-04-05 07:23:15 +00:00
## Test basic completion until length
2023-11-21 04:23:18 +00:00
mock_llama(llama, all_text)
2023-04-05 07:23:15 +00:00
completion = llama.create_completion(text, max_tokens=2)
2023-10-19 06:55:29 +00:00
assert completion["choices"][0]["text"] == " jumps"
2023-10-19 06:56:45 +00:00
assert completion["choices"][0]["finish_reason"] == "length"
2023-04-05 07:23:15 +00:00
## Test streaming completion until length
2023-11-21 04:23:18 +00:00
mock_llama(llama, all_text)
2023-10-19 06:55:29 +00:00
chunks = list(llama.create_completion(text, max_tokens=2, stream=True))
assert "".join(chunk["choices"][0]["text"] for chunk in chunks) == " jumps"
2023-10-19 06:56:45 +00:00
assert chunks[-1]["choices"][0]["finish_reason"] == "length"
def test_llama_pickle():
import pickle
import tempfile
2023-05-02 02:38:46 +00:00
fp = tempfile.TemporaryFile()
llama = llama_cpp.Llama(model_path=MODEL, vocab_only=True)
pickle.dump(llama, fp)
fp.seek(0)
llama = pickle.load(fp)
assert llama
assert llama.ctx is not None
text = b"Hello World"
assert llama.detokenize(llama.tokenize(text)) == text
2023-05-02 02:38:46 +00:00
2023-11-21 23:13:19 +00:00
def test_utf8(mock_llama):
2023-11-21 04:23:18 +00:00
llama = llama_cpp.Llama(model_path=MODEL, vocab_only=True, logits_all=True)
2023-11-21 04:23:18 +00:00
output_text = "😀"
## Test basic completion with utf8 multibyte
2023-11-21 23:13:19 +00:00
mock_llama(llama, output_text)
completion = llama.create_completion("", max_tokens=4)
assert completion["choices"][0]["text"] == output_text
## Test basic completion with incomplete utf8 multibyte
2023-11-21 23:13:19 +00:00
mock_llama(llama, output_text)
completion = llama.create_completion("", max_tokens=1)
assert completion["choices"][0]["text"] == ""
2023-04-29 06:26:07 +00:00
def test_llama_server():
from fastapi.testclient import TestClient
2023-05-02 02:38:46 +00:00
from llama_cpp.server.app import create_app, Settings
2023-05-02 02:41:54 +00:00
settings = Settings(
model=MODEL,
vocab_only=True,
)
2023-05-02 02:38:46 +00:00
app = create_app(settings)
2023-04-29 06:26:07 +00:00
client = TestClient(app)
response = client.get("/v1/models")
assert response.json() == {
"object": "list",
"data": [
{
"id": MODEL,
"object": "model",
"owned_by": "me",
"permissions": [],
}
],
}
2023-11-21 04:23:18 +00:00
def test_llama_cpp_version():
assert llama_cpp.__version__