Skip to content

Commit

Permalink
fix broken stuff and test implement custom scheduler
Browse files Browse the repository at this point in the history
  • Loading branch information
christianazinn committed Apr 15, 2024
1 parent 8a42668 commit b4648d8
Show file tree
Hide file tree
Showing 12 changed files with 63 additions and 101 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ llama.cpp/*
logs/*
.vscode/*
TODO.md
testing/*
testing/*
util/*.txt
2 changes: 1 addition & 1 deletion Homepage.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
Page("pages/Docs.py", "Docs", ":books:"),
Section("Manually convert models", icon=":arrows_counterclockwise:"),
Page("pages/Hugging_Face_Downloader.py", "Download model", ":inbox_tray:"),
Page("pages/Convert_Safetensors.py", "Convert Safetensors to High Precision", ":gem:"),
Page("pages/Convert_Safetensors.py", "Safetensors to GGUF", ":gem:"),
Page("pages/Create_IMatrix.py", "Create Importance Matrix", ":chart_with_upwards_trend:"),
Page("pages/Quantize_GGUF.py", "Quantize GGUF", ":heavy_plus_sign:" ),
Page("pages/Upload_Converted_To_HF.py", "Upload model to HuggingFace", ":outbox_tray:"),
Expand Down
29 changes: 21 additions & 8 deletions pages/Convert_Safetensors.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# IMPORTS ---------------------------------------------------------------------------------
import subprocess, threading, queue, streamlit as st
from pathlib import Path
from apscheduler.schedulers.background import BackgroundScheduler
from st_pages import add_indentation
from util.constants import config
from util.find import find_llama_models_dir
from util.scheduler import *

# FUNCTIONS ---------------------------------------------------------------------------------

"""
# Initialize queue
command_queue = queue.Queue()
Expand All @@ -23,8 +25,13 @@ def process_queue():
scheduler.start()
# Initialize queue and start a background thread for processing commands
"""

def run_command(model_folder, out_type):
# TODO fix this up and add a different command for each outtype
def run_command(model_folder, q):
for option in q:
if q[option]:
out_type = option.lower()
base_dir = Path("llama.cpp/models")
input_dir = base_dir / model_folder
target_dir = input_dir / "High-Precision-Quantization"
Expand All @@ -40,7 +47,10 @@ def run_command(model_folder, out_type):
"--outfile", str(target_dir / output_file),
"--outtype", out_type.lower()
]
print("First statement", target_dir)
return command
return f"python3 {str(convert_script_path)} {str(input_dir)} --outfile {str(target_dir / output_file)} --outtype {out_type.lower()}"

"""
try:
subprocess.run(command, check=True)
return "Command completed successfully."
Expand All @@ -55,6 +65,7 @@ def trigger_command(model_folder, options):
if options[option]:
command_queue.put((model_folder, option.lower()))
return "Commands queued. They will run sequentially."
"""


# UI CODE ---------------------------------------------------------------------------------
Expand All @@ -63,18 +74,20 @@ def trigger_command(model_folder, options):

st.title("High Precision Quantization")

models_dir = Path("llama.cpp/models/")
models_dir = Path("llama.cpp/models")
model_folders = [f.name for f in models_dir.iterdir() if f.is_dir()] if models_dir.exists() else ["Directory not found"]

model_folder = st.selectbox("Select a Model Folder", model_folders)
options = {option: st.checkbox(label=option) for option in config['checkbox_high_options']}
options = {option: st.checkbox(label=option) for option in config['conversion_quants']}

if st.button("Run Commands"):
if not any(options.values()):
st.error("Please select at least one quantization type before running commands.")
else:
status = trigger_command(model_folder, options)
st.text(status)
# status = trigger_command(model_folder, options)
schedule = scheduler()
schedule.add_job(run_command(model_folder, options))
# st.text(status)


with st.expander("Step One: Model Conversion with High Precision", expanded=False):
Expand All @@ -94,4 +107,4 @@ def trigger_command(model_folder, options):
""")

# Start the thread to process commands
threading.Thread(target=process_queue, daemon=True).start()
# threading.Thread(target=process_queue, daemon=True).start()
32 changes: 9 additions & 23 deletions pages/Quantize_GGUF.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from pathlib import Path
from st_pages import add_indentation
from util.constants import config
from util.find import find_llama_cpp_dir

# FUNCTIONS ---------------------------------------------------------------------------------

Expand All @@ -30,12 +29,12 @@ def schedule_quantize_task(command):
except subprocess.CalledProcessError as e:
return f"Error in task execution: {e}"

def trigger_command(modelpath, options, use_docker):
def trigger_command(modelpath, options):
if not any(options.values()):
return "Error: Please select at least one quantization option."

debug_output = ""
llama_cpp_dir = find_llama_cpp_dir()
llama_cpp_dir = Path("llama.cpp")
if llama_cpp_dir:
base_dir = llama_cpp_dir / 'models'
gguf_files = list_gguf_files(base_dir)
Expand Down Expand Up @@ -63,22 +62,10 @@ def trigger_command(modelpath, options, use_docker):
output_path = medium_precision_dir / f"{modified_model_file}-{option.upper()}.GGUF"
absolute_path = os.getcwd().replace('\\', '/')


if use_docker:

docker_image = "luxaplexx/convert-compaan-ollama"

output_path_in_docker = f"/models/{model_name_only}/Medium-Precision-Quantization/{modified_model_file}-{option.upper()}.GGUF"
command = [
"docker", "run", "--rm",
"-v", f"{absolute_path}/{base_dir}:/models",
docker_image, "quantize", f"/models/{model_name_only}/High-Precision-Quantization/{model_file}",
str(output_path_in_docker), option
]
if sys.platform == "linux":
command = [str(base_dir.parent / 'quantize'), str(source_path), str(output_path), option]
else:
command = [str(base_dir / 'quantize'), str(source_path), str(output_path), option]
# if sys.platform == "linux":
# command = [str(base_dir.parent / 'quantize'), str(source_path), str(output_path), option]
# else:
command = [str(llama_cpp_dir / 'quantize'), str(source_path), str(output_path), option]

print(command)

Expand All @@ -98,8 +85,7 @@ def trigger_command(modelpath, options, use_docker):
gguf_files = list_gguf_files(models_dir)

selected_gguf_file = st.selectbox("Select a GGUF File", gguf_files)
options = {option: st.checkbox(label=option) for option in shared['checkbox_options']}
use_docker = st.checkbox("Use Docker Container")
options = {option: st.checkbox(label=option) for option in config['quantization_I'] + config['quantization_K']}

run_commands = st.button("Run Selected Commands")

Expand All @@ -108,8 +94,8 @@ def trigger_command(modelpath, options, use_docker):
if not any(options.values()):
st.error("Please select at least one quantization type before running commands.")
# Proceed only if at least one quantization type is selected or if Docker is selected with a type
elif any(options.values()) or (use_docker and any(options.values())):
status = trigger_command(selected_gguf_file, options, use_docker)
elif any(options.values()):
status = trigger_command(selected_gguf_file, options)
st.text_area("Debug Output", status, height=300)
else:
# This should not happen, but we include it for robustness
Expand Down
10 changes: 10 additions & 0 deletions pages/Queue_GUI.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import streamlit as st
from st_pages import add_indentation
from util.scheduler import *

# UI CODE ---------------------------------------------------------------------------------

add_indentation()

if st.button('Run'):
scheduler().toggle()
3 changes: 1 addition & 2 deletions pages/Upload_Converted_To_HF.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,12 @@
from huggingface_hub import HfApi
from requests.exceptions import HTTPError
from pathlib import Path # Import pathlib
from util.find import find_llama_cpp_dir
from util.key import decrypt_token

# FUNCTIONS ---------------------------------------------------------------------------------

# Search for the llama.cpp directory
llama_cpp_dir, models_dir = find_llama_cpp_dir()
llama_cpp_dir, models_dir = Path("llama.cpp"), Path("llama.cpp/models")
if not llama_cpp_dir:
st.error("llama.cpp directory not found. Please check the file structure.")

Expand Down
Binary file added util/__pycache__/constants.cpython-310.pyc
Binary file not shown.
Binary file modified util/__pycache__/find.cpython-310.pyc
Binary file not shown.
Binary file added util/__pycache__/key.cpython-310.pyc
Binary file not shown.
Binary file added util/__pycache__/scheduler.cpython-310.pyc
Binary file not shown.
52 changes: 0 additions & 52 deletions util/find.py

This file was deleted.

33 changes: 19 additions & 14 deletions util/scheduler.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# IMPORTS ---------------------------------------------------------------------------------
from pathlib import Path
from datetime import datetime
import subprocess, streamlit as st
import subprocess, streamlit as st, os

# FUNCTIONS ---------------------------------------------------------------------------------

Expand All @@ -10,19 +10,21 @@
def scheduler():
return Scheduler()

# TODO commands are actually lists of strings so you may need to refactor to handle that

# the scheduler singleton class (do i need st.cache_resource here?)
@st.cache_resource
class Scheduler:

# constructor: set up basic attributes
def __init__(self):
path = Path(__file__)
self.queuePath = path + "/queue.txt"
self.outPath = path + "/completed.txt"
self.active = True
thispath = Path(__file__).parent
self.queuePath = os.path.join(thispath, "queue.txt")
self.outPath = os.path.join(thispath, "completed.txt")
self.active = False
self.job = None
self.command = ""
self.mostRecentError = ""
self.lastLog = ""

# toggle active status (i.e. pause/unpause)
def toggle(self):
Expand All @@ -36,7 +38,7 @@ def add_job(self, job, position=-1):
# the simple one
if position == -1:
with open(self.queuePath, "a") as f:
f.write(job + "\n")
f.write(''.join(job + ["\n"]))
# the slightly less simple one
else:
with open(self.queuePath, "r") as f:
Expand All @@ -46,7 +48,7 @@ def add_job(self, job, position=-1):
f.writelines(lines)

# remove a job from the queue
def remove_job(self, job, position=-1):
def remove_job(self, position=-1):
with open(self.queuePath, "r") as f:
lines = f.readlines()
lines.pop(position)
Expand Down Expand Up @@ -74,8 +76,8 @@ def get_completed(self):
return f.readlines()

# return the most recent error
def get_error(self):
return self.mostRecentError
def get_log(self):
return self.log

# pop the next job in the queue
def get_next_job(self):
Expand All @@ -85,7 +87,7 @@ def get_next_job(self):
job = lines.pop(0)
with open(self.queuePath, "w") as f:
f.writelines(lines)
return job
return job.strip().split(" ")
return None

# switch the jobs at index posiiton1 and position2
Expand All @@ -105,14 +107,16 @@ def run_next_job(self):
self.job = subprocess.run(self.command, check=True)
# log the job as completed if it works
with open(self.outPath, "a") as f:
f.write(f"Task executed successfully at {self.time()}: {self.command}\n")
self.log = f"Task executed successfully at {self.time()}: {self.command}\n"
f.write(self.log)
# log errors
except subprocess.CalledProcessError as e:
self.mostRecentError = f"Error in task execution: {e}"
self.active = False
# log the job as failed
with open(self.outPath, "a") as f:
f.write(f"Error in task execution for task {self.command} at {self.time()}: {e}\n")
self.log = f"Error in task execution for task {self.command} at {self.time()}: {e}\n"
f.write(self.log)

# automatically loop through the jobs while active but only while there are jobs
# else you're wasting compute
Expand All @@ -128,7 +132,8 @@ def terminate(self, requeue=False):
# log the job as terminated if not requeue
if not requeue:
with open(self.outPath, "a") as f:
f.write(f"Terminated task {self.command} at {self.time()}\n")
self.log = f"Terminated task {self.command} at {self.time()}\n"
f.write(self.log)
# if requeue, add the job back to the queue
else:
self.add_job(self.command, 0)
Expand Down

0 comments on commit b4648d8

Please sign in to comment.