Files
SIA/sia/llm_engine/qwq_llm_engine.py
2025-04-04 08:54:06 +00:00

130 lines
3.9 KiB
Python

from pathlib import Path
from threading import Thread
from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline, TextIteratorStreamer, BitsAndBytesConfig
from typing import Callable, Iterator
import json
import torch
from . import LlmEngine
from .. import util
class QwQLlmEngine(LlmEngine):
def __init__(
self,
model_path: Path,
temperature: float,
token_limit: int = None,
):
"""
Initialize the QwQ LLM Engine.
Args:
model_path: Local path to the model
temperature: Sampling temperature
token_limit: Maximum tokens to generate
"""
self._temperature = temperature
self._token_limit = token_limit
with open('/root/sia/qwq_tokenizer_config.json', 'r') as f:
tokenizer_config = json.load(f)
quantization_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_compute_dtype=torch.bfloat16,
bnb_4bit_quant_type="nf4",
bnb_4bit_use_double_quant=True
)
model = AutoModelForCausalLM.from_pretrained(
model_path,
return_dict=True,
device_map="auto",
use_cache=True,
quantization_config=quantization_config,
)
self._tokenizer = AutoTokenizer.from_pretrained(
model_path,
tokenizer_config=tokenizer_config,
)
self._pipline = pipeline(
"text-generation",
model=model,
tokenizer=self._tokenizer,
return_full_text=False,
)
def infer(self, system_prompt: str, main_context: str, should_stop: Callable[[], bool] = lambda: False) -> Iterator[str]:
"""
Run inference using the system prompt and main context.
Args:
system_prompt: The system prompt string
main_context: The main context string after templating
should_stop: Callback that returns True when inference should stop
Returns:
Iterator[str]: An iterator that yields the generated text.
"""
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": main_context}
]
text = self._tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True,
)
streamer = TextIteratorStreamer(
self._tokenizer,
skip_prompt=True,
)
generation_thread = Thread(
target=self._pipline,
kwargs=dict(
text_inputs=text,
do_sample=True,
temperature=self._temperature,
max_new_tokens=self._token_limit,
streamer=streamer,
)
)
generation_thread.start()
for text in util.stop_before_value(streamer, self._tokenizer.eos_token):
yield text
if should_stop():
break
generation_thread.join()
def token_count(self, system_prompt: str, main_context: str) -> int:
"""
Count tokens for the given system prompt and main context.
Args:
system_prompt: The system prompt string
main_context: The main context string
Returns:
int: Total number of tokens
"""
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": main_context}
]
prompt = self._tokenizer.apply_chat_template(
messages, tokenize=False, add_generation_prompt=True
)
return len(self._tokenizer.encode(prompt))
def token_limit(self) -> int:
return self._token_limit