Converted QwQ notebooks to .py files

This commit is contained in:
Niels Geens
2025-04-01 10:41:24 +02:00
parent 642c5181bb
commit 6f3d414d17
5 changed files with 368 additions and 558 deletions

View File

@@ -1,121 +1,120 @@
from aiohttp import web from aiohttp import web
import asyncio import asyncio
from .auto_approver import AutoApprover from .auto_approver import AutoApprover
from .config import Config from .config import Config
from .iteration_logger import IterationLogger from .iteration_logger import IterationLogger
from .llm_engine.hf_llm_engine import HfLlmEngine from .llm_engine.hf_llm_engine import HfLlmEngine
from .llm_engine.local_llm_engine import LocalLlmEngine from .llm_engine.local_llm_engine import LocalLlmEngine
from .llm_engine.mistral_llm_engine import MistralLlmEngine from .llm_engine.mistral_llm_engine import MistralLlmEngine
from .llm_engine.openai_llm_engine import OpenAILlmEngine from .llm_engine.openai_llm_engine import OpenAILlmEngine
from .llm_engine.qwq_llm_engine import QwQLlmEngine from .llm_engine.qwq_llm_engine import QwQLlmEngine
from .response_parser import ResponseParser from .response_parser import ResponseParser
from .system_metrics import SystemMetrics from .system_metrics import SystemMetrics
from .web.api import Api from .web.api import Api
from .web.static import Static from .web.static import Static
from .web.websockts import Websockets from .web.websockts import Websockets
from .web_agent import WebAgent from .web_agent import WebAgent
from .web_io_buffer import WebIOBuffer from .web_io_buffer import WebIOBuffer
from .working_memory import WorkingMemory from .working_memory import WorkingMemory
from .xml_validator import XMLValidator from .xml_validator import XMLValidator
class Main: class Main:
@classmethod @classmethod
async def create(cls, config: Config): async def create(cls, config: Config):
self = cls() self = cls()
self._config = config self._config = config
self._system_prompt = self._config.system_prompt.read_text() self._system_prompt = self._config.system_prompt.read_text()
self._action_schema = self._config.action_schema.read_text() self._action_schema = self._config.action_schema.read_text()
# Initialize LLM engines based on config # Initialize LLM engines based on config
self._llms = {} self._llms = {}
if config.local_enabled: if config.local_enabled:
self._llms['local'] = LocalLlmEngine( self._llms['local'] = LocalLlmEngine(
config.local_model, config.local_model,
config.local_temperature, config.local_temperature,
config.local_token_limit, config.local_token_limit,
config.local_api_key, config.local_api_key,
) )
if config.openai_enabled: if config.openai_enabled:
self._llms['openai'] = OpenAILlmEngine( self._llms['openai'] = OpenAILlmEngine(
config.openai_model, config.openai_model,
config.openai_temperature, config.openai_temperature,
config.openai_token_limit, config.openai_token_limit,
config.openai_api_key, config.openai_api_key,
) )
if config.hf_enabled: if config.hf_enabled:
self._llms['hf'] = HfLlmEngine( self._llms['hf'] = HfLlmEngine(
config.hf_model, config.hf_model,
config.hf_temperature, config.hf_temperature,
config.hf_api_key, config.hf_api_key,
) )
if config.mistral_enabled: if config.mistral_enabled:
self._llms['mistral'] = MistralLlmEngine( self._llms['mistral'] = MistralLlmEngine(
config.mistral_model, config.mistral_model,
config.mistral_temperature, config.mistral_temperature,
config.mistral_token_limit, config.mistral_token_limit,
config.mistral_api_key, config.mistral_api_key,
) )
if config.qwq_enabled: if config.qwq_enabled:
self._llms['qwq'] = QwQLlmEngine( self._llms['qwq'] = QwQLlmEngine(
config.qwq_model, config.qwq_model,
config.qwq_temperature, config.qwq_temperature,
config.qwq_token_limit, config.qwq_token_limit,
config.hf_api_key, )
)
if not self._llms:
if not self._llms: raise ValueError("No LLM engines enabled in configuration")
raise ValueError("No LLM engines enabled in configuration")
self._io_buffer = WebIOBuffer()
self._io_buffer = WebIOBuffer() self._working_memory = WorkingMemory()
self._working_memory = WorkingMemory() self._agent = WebAgent(
self._agent = WebAgent( system_prompt=self._system_prompt,
system_prompt=self._system_prompt, action_schema=self._action_schema,
action_schema=self._action_schema, working_memory=self._working_memory,
working_memory=self._working_memory, metrics=SystemMetrics(),
metrics=SystemMetrics(), llms=self._llms,
llms=self._llms, validator=XMLValidator(self._action_schema),
validator=XMLValidator(self._action_schema), parser=ResponseParser(config.work_dir, self._io_buffer),
parser=ResponseParser(config.work_dir, self._io_buffer), iteration_logger=IterationLogger(self._config.iterations_dir, self._system_prompt, self._action_schema),
iteration_logger=IterationLogger(self._config.iterations_dir, self._system_prompt, self._action_schema), )
) self._auto_approver = AutoApprover(self._agent)
self._auto_approver = AutoApprover(self._agent)
self._app = web.Application()
self._app = web.Application() self._api = Api(config.work_dir, self._app, self._agent, self._io_buffer, self._working_memory, self._auto_approver)
self._api = Api(config.work_dir, self._app, self._agent, self._io_buffer, self._working_memory, self._auto_approver) self._websockets = Websockets(self._app, self._agent, self._io_buffer, self._auto_approver, self._working_memory)
self._websockets = Websockets(self._app, self._agent, self._io_buffer, self._auto_approver, self._working_memory) self._static = Static(self._app, self._config)
self._static = Static(self._app, self._config)
return self
return self
@property
@property def app(self):
def app(self): return self._app
return self._app
async def _serve_index(self, request: web.Request) -> web.Response:
async def _serve_index(self, request: web.Request) -> web.Response: """Serve the React application HTML for any unmatched routes."""
"""Serve the React application HTML for any unmatched routes.""" index_path = self._config.static_files / "index.html"
index_path = self._config.static_files / "index.html" if not index_path.exists():
if not index_path.exists(): raise web.HTTPNotFound()
raise web.HTTPNotFound()
with open(index_path, "r") as f:
with open(index_path, "r") as f: html_content = f.read()
html_content = f.read()
return web.Response(
return web.Response( text=html_content,
text=html_content, content_type="text/html"
content_type="text/html" )
)
def main():
def main(): loop = asyncio.new_event_loop()
loop = asyncio.new_event_loop() config = Config()
config = Config() main_instance = loop.run_until_complete(Main.create(config))
main_instance = loop.run_until_complete(Main.create(config)) print(f"Web server started at http://localhost:{config.port}")
print(f"Web server started at http://localhost:{config.port}") web.run_app(main_instance.app, loop=loop, host=config.host, port=config.port)
web.run_app(main_instance.app, loop=loop, host=config.host, port=config.port)
return 0 return 0

View File

@@ -1,121 +1,121 @@
from threading import Thread from threading import Thread
from typing import Iterator, Optional, Callable from typing import Iterator, Optional, Callable
from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline, TextIteratorStreamer from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline, TextIteratorStreamer
import torch import torch
from . import LlmEngine from . import LlmEngine
from .. import util from .. import util
class LocalLlmEngine(LlmEngine): class LocalLlmEngine(LlmEngine):
def __init__( def __init__(
self, self,
model_path: str, model_path: str,
temperature: float, temperature: float,
token_limit: int, token_limit: int,
api_token: Optional[str], api_token: Optional[str],
): ):
""" """
Initialize the LLM Engine with a model path. Initialize the LLM Engine with a model path.
Args: Args:
model_path: Path to the model weights to be used. model_path: Path to the model weights to be used.
temperature: Temperature for sampling temperature: Temperature for sampling
api_token: Huggingface API key token_limit: Maximum number of tokens to generate
token_limit: Maximum number of tokens to generate api_token: Huggingface API key
""" """
self._temperature = temperature self._temperature = temperature
self._token_limit = token_limit self._token_limit = token_limit
self._tokenizer = AutoTokenizer.from_pretrained(model_path, token=api_token) self._tokenizer = AutoTokenizer.from_pretrained(model_path, token=api_token)
model = AutoModelForCausalLM.from_pretrained( model = AutoModelForCausalLM.from_pretrained(
model_path, model_path,
return_dict=True, return_dict=True,
low_cpu_mem_usage=True, low_cpu_mem_usage=True,
torch_dtype=torch.bfloat16, torch_dtype=torch.bfloat16,
device_map="auto", device_map="auto",
trust_remote_code=True, trust_remote_code=True,
token=api_token, token=api_token,
) )
if self._tokenizer.pad_token_id is None: if self._tokenizer.pad_token_id is None:
self._tokenizer.pad_token_id = self._tokenizer.eos_token_id self._tokenizer.pad_token_id = self._tokenizer.eos_token_id
if model.config.pad_token_id is None: if model.config.pad_token_id is None:
model.config.pad_token_id = model.config.eos_token_id model.config.pad_token_id = model.config.eos_token_id
self._pipeline = pipeline( self._pipeline = pipeline(
"text-generation", "text-generation",
model=model, model=model,
tokenizer=self._tokenizer, tokenizer=self._tokenizer,
torch_dtype=torch.bfloat16, torch_dtype=torch.bfloat16,
device_map="auto", device_map="auto",
return_full_text=False, return_full_text=False,
) )
def infer(self, system_prompt: str, main_context: str, should_stop: Callable[[], bool] = lambda: False) -> Iterator[str]: 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. Run inference using the system prompt and main context.
Args: Args:
system_prompt: The system prompt string system_prompt: The system prompt string
main_context: The main context string after templating main_context: The main context string after templating
should_stop: Callback that returns True when inference should stop should_stop: Callback that returns True when inference should stop
Returns: Returns:
Iterator[str]: An iterator that yields the generated text. Iterator[str]: An iterator that yields the generated text.
""" """
messages = [ messages = [
{"role": "system", "content": system_prompt}, {"role": "system", "content": system_prompt},
{"role": "user", "content": main_context} {"role": "user", "content": main_context}
] ]
prompt = self._tokenizer.apply_chat_template( prompt = self._tokenizer.apply_chat_template(
messages, tokenize=False, add_generation_prompt=True messages, tokenize=False, add_generation_prompt=True
) )
streamer = TextIteratorStreamer( streamer = TextIteratorStreamer(
self._tokenizer, self._tokenizer,
skip_prompt=True skip_prompt=True
) )
generation_thread = Thread(target=self._pipeline, kwargs=dict( generation_thread = Thread(target=self._pipeline, kwargs=dict(
text_inputs=prompt, text_inputs=prompt,
do_sample=True, do_sample=True,
temperature=self._temperature, temperature=self._temperature,
max_new_tokens=self.token_limit(), max_new_tokens=self.token_limit(),
streamer=streamer streamer=streamer
)) ))
generation_thread.start() generation_thread.start()
for text in util.stop_before_value(streamer, '<|eot_id|>'): for text in util.stop_before_value(streamer, '<|eot_id|>'):
yield text yield text
if should_stop(): if should_stop():
break break
generation_thread.join() generation_thread.join()
def token_count(self, system_prompt: str, main_context: str) -> int: def token_count(self, system_prompt: str, main_context: str) -> int:
""" """
Count tokens for the given system prompt and main context. Count tokens for the given system prompt and main context.
Args: Args:
system_prompt: The system prompt string system_prompt: The system prompt string
main_context: The main context string main_context: The main context string
Returns: Returns:
int: Total number of tokens int: Total number of tokens
""" """
messages = [ messages = [
{"role": "system", "content": system_prompt}, {"role": "system", "content": system_prompt},
{"role": "user", "content": main_context} {"role": "user", "content": main_context}
] ]
prompt = self._tokenizer.apply_chat_template( prompt = self._tokenizer.apply_chat_template(
messages, tokenize=False, add_generation_prompt=True messages, tokenize=False, add_generation_prompt=True
) )
return len(self._tokenizer.encode(prompt)) return len(self._tokenizer.encode(prompt))
def token_limit(self) -> int: def token_limit(self) -> int:
""" """
Get the model's context window size. Get the model's context window size.
Returns: Returns:
int: Maximum number of tokens the model can process int: Maximum number of tokens the model can process
""" """
if self._token_limit is not None: if self._token_limit is not None:
return self._token_limit return self._token_limit
else: else:
return self._pipeline.model.config.max_position_embeddings return self._pipeline.model.config.max_position_embeddings

View File

@@ -1,303 +1,124 @@
from typing import Callable, Iterator, Optional from pathlib import Path
import torch from threading import Thread
from transformers import AutoTokenizer, AutoModelForCausalLM, TextIteratorStreamer from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline, TextIteratorStreamer, BitsAndBytesConfig
from threading import Thread from typing import Callable, Iterator
from pathlib import Path import torch
import sys
import gc from . import LlmEngine
import os from .. import util
import re
class QwQLlmEngine(LlmEngine):
from . import LlmEngine
from .. import util def __init__(
self,
class QwQLlmEngine(LlmEngine): model_path: Path,
""" temperature: float,
LLM Engine implementation for QwQ models. token_limit: int = None,
):
QwQ is a reasoning-based model with <think> capabilities. This engine handles: """
1. Proper initialization with recommended parameters Initialize the QwQ LLM Engine.
2. Processing outputs to extract reasoning and actions
3. Converting QwQ's format to SIA-compatible action schemas Args:
""" model_path: Local path to the model
temperature: Sampling temperature
def __init__( token_limit: Maximum tokens to generate
self, """
model_path: str, self._temperature = temperature
temperature: float = 0.6, # QwQ recommended default self._token_limit = token_limit
token_limit: Optional[int] = None,
api_key: Optional[str] = None, quantization_config = BitsAndBytesConfig(
): load_in_4bit=True,
""" bnb_4bit_compute_dtype=torch.bfloat16,
Initialize the QwQ LLM Engine. bnb_4bit_quant_type="nf4",
bnb_4bit_use_double_quant=True
Args: )
model_path: Local path to the model or HF model ID
temperature: Sampling temperature (0.6 default as recommended for QwQ) model = AutoModelForCausalLM.from_pretrained(
token_limit: Maximum tokens to generate or context length override model_path,
api_key: HuggingFace API token if needed return_dict=True,
""" device_map="auto",
self._model_path = Path(model_path) if os.path.exists(model_path) else model_path attn_implementation="flash_attention_2",
self._temperature = temperature use_cache=True,
self._token_limit = token_limit quantization_config=quantization_config,
)
# QwQ-specific parameters
self._top_p = 0.95 # QwQ recommended self._tokenizer = AutoTokenizer.from_pretrained(model_path)
self._min_p = 0.0 # QwQ recommended
self._top_k = 40 # QwQ recommended self._pipline = pipeline(
"text-generation",
try: model=model,
# Free memory before loading tokenizer=self._tokenizer,
gc.collect() return_full_text=False,
)
print(f"Loading QwQ tokenizer from {self._model_path}...")
self._tokenizer = AutoTokenizer.from_pretrained(
self._model_path, def infer(self, system_prompt: str, main_context: str, should_stop: Callable[[], bool] = lambda: False) -> Iterator[str]:
token=api_key, """
trust_remote_code=True, Run inference using the system prompt and main context.
)
Args:
# Set padding token to avoid warnings system_prompt: The system prompt string
if self._tokenizer.pad_token is None: main_context: The main context string after templating
self._tokenizer.pad_token = self._tokenizer.eos_token should_stop: Callback that returns True when inference should stop
# Device configuration Returns:
if torch.cuda.is_available(): Iterator[str]: An iterator that yields the generated text.
print(f"Loading QwQ model on GPU...") """
device_map = "auto" messages = [
dtype = torch.bfloat16 {"role": "system", "content": system_prompt},
else: {"role": "user", "content": main_context}
print(f"Loading QwQ model on CPU...") ]
device_map = "cpu"
dtype = torch.float32 text = self._tokenizer.apply_chat_template(
messages,
# Load model with appropriate settings tokenize=False,
self._model = AutoModelForCausalLM.from_pretrained( add_generation_prompt=True,
self._model_path, )
device_map=device_map,
torch_dtype=dtype, streamer = TextIteratorStreamer(
trust_remote_code=True, self._tokenizer,
return_dict=True, skip_prompt=True,
token=api_key, )
)
generation_thread = Thread(
# Ensure model is in evaluation mode target=self._pipline,
self._model.eval() kwargs=dict(
print("QwQ model loaded successfully.") text_inputs=text,
do_sample=True,
# Clear cache after loading temperature=self._temperature,
gc.collect() max_new_tokens=self._token_limit,
streamer=streamer,
except Exception as e: )
print(f"Failed to initialize QwQ model: {e}") )
import traceback
traceback.print_exc() generation_thread.start()
raise RuntimeError(f"Failed to initialize QwQ model: {e}")
for text in util.stop_before_value(streamer, '<|eot_id|>'):
def infer(self, system_prompt: str, main_context: str, should_stop: Callable[[], bool] = lambda: False) -> Iterator[str]: yield text
""" if should_stop():
Run inference using the system prompt and main context. break
Args: generation_thread.join()
system_prompt: The system prompt string
main_context: The main context string after templating def token_count(self, system_prompt: str, main_context: str) -> int:
should_stop: Callback that returns True when inference should stop """
Count tokens for the given system prompt and main context.
Returns:
Iterator[str]: An iterator that yields the generated text. Args:
""" system_prompt: The system prompt string
try: main_context: The main context string
# Format as messages for chat template
messages = [ Returns:
{"role": "system", "content": system_prompt}, int: Total number of tokens
{"role": "user", "content": main_context} """
] messages = [
{"role": "system", "content": system_prompt},
# Apply chat template - DO NOT add <think> token as it will be handled by the model {"role": "user", "content": main_context}
text = self._tokenizer.apply_chat_template( ]
messages, prompt = self._tokenizer.apply_chat_template(
tokenize=False, messages, tokenize=False, add_generation_prompt=True
add_generation_prompt=True, )
) return len(self._tokenizer.encode(prompt))
# Tokenize input def token_limit(self) -> int:
print("Tokenizing input...") return self._token_limit
inputs = self._tokenizer(text, return_tensors="pt").to(self._model.device)
# Create streamer for token-by-token generation
print("Starting generation...")
streamer = TextIteratorStreamer(
self._tokenizer,
skip_prompt=True,
skip_special_tokens=True,
timeout=60.0
)
# Configure generation with QwQ's recommended parameters
generation_kwargs = {
"input_ids": inputs.input_ids,
"attention_mask": inputs.attention_mask,
"max_new_tokens": self.token_limit(),
"temperature": self._temperature,
"top_p": self._top_p,
"top_k": self._top_k,
"min_p": self._min_p,
"do_sample": True,
"streamer": streamer,
"repetition_penalty": 1.1,
"pad_token_id": self._tokenizer.pad_token_id,
"use_cache": True,
}
print("Starting generation thread...")
generation_thread = Thread(target=self._model.generate, kwargs=generation_kwargs)
generation_thread.start()
# Accumulate raw output and track think mode
raw_output = ""
action_extracted = False
# Process thinking and extract actions
try:
for text in streamer:
raw_output += text
# Check if we should stop
if should_stop():
print("Generation stopped by caller")
break
# Extract action if available
action = self._extract_action(raw_output)
if action and not action_extracted:
# We've found an action tag - yield it
action_extracted = True
yield action
elif not action_extracted:
# Still in thinking phase or no action yet - yield tokens
yield text
# Process remaining output
if raw_output and not action_extracted:
final_action = self._process_final_output(raw_output)
if final_action:
yield final_action
finally:
# Ensure thread is properly joined even if iteration is interrupted
generation_thread.join()
# Force garbage collection after generation
gc.collect()
except Exception as e:
print(f"QwQ inference error: {e}")
import traceback
traceback.print_exc()
# Re-raise to make the failure visible
raise RuntimeError(f"QwQ inference failed: {e}")
def _extract_action(self, text: str) -> Optional[str]:
"""
Extract SIA-compatible action from QwQ output.
Returns the action if found, None if still in thinking mode.
"""
# Check if we have a complete think block followed by an action
think_pattern = r'<think>(.*?)</think>\s*(<\w+.*?>)'
match = re.search(think_pattern, text, re.DOTALL)
if match:
# Found a think block followed by an action tag
action_start = match.group(2)
# Return the action part
action_idx = text.index(action_start)
return text[action_idx:]
# Check for direct action (no thinking)
action_pattern = r'^(<(?:single|repeat|delete|stop|reasoning|read_stdin|write_stdout).*?>)'
match = re.search(action_pattern, text)
if match:
return text
return None
def _process_final_output(self, text: str) -> str:
"""
Process final output if no action was extracted.
Converts thinking content to reasoning if needed.
"""
# Check if there's thinking content
think_pattern = r'<think>(.*?)</think>'
match = re.search(think_pattern, text, re.DOTALL)
if match:
# Extract thinking content
thinking = match.group(1).strip()
if thinking:
# Convert to reasoning
return f"<reasoning>\n{thinking}\n</reasoning>"
# If the response has no XML tags but isn't empty, make it reasoning
if text.strip() and not re.search(r'<\w+.*?>', text):
return f"<reasoning>\n{text.strip()}\n</reasoning>"
# Return as-is if it already has valid XML tags
return text
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}
]
text = self._tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True,
)
return len(self._tokenizer.encode(text))
def token_limit(self) -> int:
"""
Get the model's context window size.
Returns:
int: Maximum number of tokens the model can process
"""
if self._token_limit is not None:
return self._token_limit
# Try to detect model size from config
try:
if isinstance(self._model_path, Path):
config_file = self._model_path / "config.json"
if config_file.exists():
import json
with open(config_file, 'r') as f:
config = json.load(f)
else:
config = self._model.config.to_dict()
else:
config = self._model.config.to_dict()
# Check for context length in different possible fields
if 'max_position_embeddings' in config:
return config['max_position_embeddings']
if 'model_max_length' in config:
return config['model_max_length']
# Safe fallback for QwQ - it supports up to 8192 by default
return 8192
except Exception as e:
print(f"Warning: Failed to read model config: {e}")
# Default fallback
return 4096

View File

@@ -6,7 +6,6 @@ Fine-tuning for QwQ model
# Unsloth should be imported before transformers to ensure all optimizations are applied. # Unsloth should be imported before transformers to ensure all optimizations are applied.
from unsloth import FastLanguageModel, is_bfloat16_supported from unsloth import FastLanguageModel, is_bfloat16_supported
from .dataset import Dataset
from dataclasses import dataclass from dataclasses import dataclass
from pathlib import Path from pathlib import Path
from transformers import TrainingArguments from transformers import TrainingArguments
@@ -15,6 +14,8 @@ from typing import Optional, List
import argparse import argparse
import os import os
from .dataset import Dataset
@dataclass @dataclass
class Args: class Args:
def __init__(self, args: Optional[List[str]]): def __init__(self, args: Optional[List[str]]):
@@ -78,7 +79,7 @@ def main():
load_in_4bit = True, # False for LoRA 16bit load_in_4bit = True, # False for LoRA 16bit
fast_inference = True, # Enable vLLM fast inference fast_inference = True, # Enable vLLM fast inference
max_lora_rank = lora_rank, max_lora_rank = lora_rank,
gpu_memory_utilization = 0.85, # Reduce if out of memory gpu_memory_utilization = 0.5, # Reduce if out of memory
) )
model = FastLanguageModel.get_peft_model( model = FastLanguageModel.get_peft_model(
@@ -97,12 +98,6 @@ def main():
loftq_config = None, # And LoftQ loftq_config = None, # And LoftQ
) )
response_template = tokenizer.apply_chat_template(
[{"role": "assistant", "content": ""}],
tokenize=False,
add_generation_prompt=True
)
training_args = TrainingArguments( training_args = TrainingArguments(
output_dir=str(args.output_dir), output_dir=str(args.output_dir),
num_train_epochs=3, num_train_epochs=3,
@@ -129,10 +124,6 @@ def main():
train_dataset=dataset.to_transformers_dataset(tokenizer), train_dataset=dataset.to_transformers_dataset(tokenizer),
dataset_text_field="messages", dataset_text_field="messages",
max_seq_length=max_seq_length, max_seq_length=max_seq_length,
data_collator=DataCollatorForCompletionOnlyLM(
response_template=response_template,
tokenizer=tokenizer
),
) )
trainer.train() trainer.train()
@@ -140,7 +131,6 @@ def main():
model.save_pretrained_merged( model.save_pretrained_merged(
str(args.output_dir), str(args.output_dir),
tokenizer=tokenizer, tokenizer=tokenizer,
save_method="merged_16bit"
) )
if __name__ == "__main__": if __name__ == "__main__":

View File

@@ -22,7 +22,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 2, "execution_count": null,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [