2023-05-02 23:25:28 +02:00
|
|
|
'''
|
|
|
|
Based on
|
|
|
|
https://github.com/abetlen/llama-cpp-python
|
2023-04-01 02:18:05 +02:00
|
|
|
|
2023-05-02 23:25:28 +02:00
|
|
|
Documentation:
|
|
|
|
https://abetlen.github.io/llama-cpp-python/
|
|
|
|
'''
|
|
|
|
|
2023-05-16 01:19:55 +02:00
|
|
|
import logging
|
|
|
|
import re
|
|
|
|
|
2023-05-02 23:25:28 +02:00
|
|
|
from llama_cpp import Llama, LlamaCache
|
2023-03-19 07:42:10 +01:00
|
|
|
|
2023-04-01 02:18:05 +02:00
|
|
|
from modules import shared
|
2023-03-31 19:27:01 +02:00
|
|
|
from modules.callbacks import Iteratorize
|
|
|
|
|
2023-03-19 07:42:10 +01:00
|
|
|
|
|
|
|
class LlamaCppModel:
|
|
|
|
def __init__(self):
|
|
|
|
self.initialized = False
|
|
|
|
|
2023-05-16 00:51:23 +02:00
|
|
|
def __del__(self):
|
|
|
|
self.model.__del__()
|
|
|
|
|
2023-03-19 07:42:10 +01:00
|
|
|
@classmethod
|
|
|
|
def from_pretrained(self, path):
|
|
|
|
result = self()
|
|
|
|
|
2023-05-16 01:19:55 +02:00
|
|
|
cache_capacity = 0
|
|
|
|
if shared.args.cache_capacity is not None:
|
|
|
|
if 'GiB' in shared.args.cache_capacity:
|
|
|
|
cache_capacity = int(re.sub('[a-zA-Z]', '', shared.args.cache_capacity)) * 1000 * 1000 * 1000
|
|
|
|
elif 'MiB' in shared.args.cache_capacity:
|
|
|
|
cache_capacity = int(re.sub('[a-zA-Z]', '', shared.args.cache_capacity)) * 1000 * 1000
|
|
|
|
else:
|
|
|
|
cache_capacity = int(shared.args.cache_capacity)
|
|
|
|
|
|
|
|
logging.info("Cache capacity is " + str(cache_capacity) + " bytes")
|
|
|
|
|
2023-05-02 23:25:28 +02:00
|
|
|
params = {
|
|
|
|
'model_path': str(path),
|
|
|
|
'n_ctx': 2048,
|
|
|
|
'seed': 0,
|
|
|
|
'n_threads': shared.args.threads or None,
|
|
|
|
'n_batch': shared.args.n_batch,
|
|
|
|
'use_mmap': not shared.args.no_mmap,
|
2023-05-15 03:58:11 +02:00
|
|
|
'use_mlock': shared.args.mlock,
|
|
|
|
'n_gpu_layers': shared.args.n_gpu_layers
|
2023-05-02 23:25:28 +02:00
|
|
|
}
|
|
|
|
self.model = Llama(**params)
|
2023-05-16 01:19:55 +02:00
|
|
|
if cache_capacity > 0:
|
|
|
|
self.model.set_cache(LlamaCache(capacity_bytes=cache_capacity))
|
2023-05-02 23:25:28 +02:00
|
|
|
|
|
|
|
# This is ugly, but the model and the tokenizer are the same object in this library.
|
|
|
|
return result, result
|
|
|
|
|
|
|
|
def encode(self, string):
|
|
|
|
if type(string) is str:
|
|
|
|
string = string.encode()
|
|
|
|
return self.model.tokenize(string)
|
2023-03-19 07:42:10 +01:00
|
|
|
|
2023-03-31 19:27:01 +02:00
|
|
|
def generate(self, context="", token_count=20, temperature=1, top_p=1, top_k=50, repetition_penalty=1, callback=None):
|
2023-05-16 01:19:55 +02:00
|
|
|
context = context if type(context) is str else context.decode()
|
|
|
|
completion_chunks = self.model.create_completion(
|
|
|
|
prompt=context,
|
|
|
|
max_tokens=token_count,
|
|
|
|
temperature=temperature,
|
|
|
|
top_p=top_p,
|
|
|
|
top_k=top_k,
|
|
|
|
repeat_penalty=repetition_penalty,
|
|
|
|
stream=True
|
|
|
|
)
|
|
|
|
output = ""
|
|
|
|
for completion_chunk in completion_chunks:
|
|
|
|
text = completion_chunk['choices'][0]['text']
|
2023-05-02 23:25:28 +02:00
|
|
|
output += text
|
|
|
|
if callback:
|
2023-05-16 01:19:55 +02:00
|
|
|
callback(text)
|
|
|
|
return output
|
2023-03-19 07:42:10 +01:00
|
|
|
|
|
|
|
def generate_with_streaming(self, **kwargs):
|
|
|
|
with Iteratorize(self.generate, kwargs, callback=None) as generator:
|
2023-03-31 19:27:01 +02:00
|
|
|
reply = ''
|
2023-03-19 07:42:10 +01:00
|
|
|
for token in generator:
|
|
|
|
reply += token
|
|
|
|
yield reply
|