Spaces:
Runtime error
Runtime error
| from config import SHARE, MODELS, TRAINING_PARAMS, LORA_TRAINING_PARAMS, GENERATION_PARAMS | |
| import os | |
| import gradio as gr | |
| import random | |
| from trainer import Trainer | |
| LORA_DIR = 'lora' | |
| def random_name(): | |
| fruits = [ | |
| "dragonfruit", "kiwano", "rambutan", "durian", "mangosteen", | |
| "jabuticaba", "pitaya", "persimmon", "acai", "starfruit" | |
| ] | |
| return '-'.join(random.sample(fruits, 3)) | |
| class UI(): | |
| def __init__(self): | |
| self.trainer = Trainer() | |
| def load_loras(self): | |
| loaded_model_name = self.trainer.model_name | |
| if os.path.exists(LORA_DIR) and loaded_model_name is not None: | |
| loras = [f for f in os.listdir(LORA_DIR)] | |
| sanitized_model_name = loaded_model_name.replace('/', '_').replace('.', '_') | |
| loras = [f for f in loras if f.startswith(sanitized_model_name)] | |
| loras.insert(0, 'None') | |
| return gr.Dropdown.update(choices=loras) | |
| else: | |
| return gr.Dropdown.update(choices=['None'], value='None') | |
| def training_params_block(self): | |
| with gr.Row(): | |
| with gr.Column(): | |
| self.max_seq_length = gr.Slider( | |
| interactive=True, | |
| minimum=1, maximum=4096, value=TRAINING_PARAMS['max_seq_length'], | |
| label="Max Sequence Length", | |
| ) | |
| self.micro_batch_size = gr.Slider( | |
| minimum=1, maximum=100, step=1, value=TRAINING_PARAMS['micro_batch_size'], | |
| label="Micro Batch Size", | |
| ) | |
| self.gradient_accumulation_steps = gr.Slider( | |
| minimum=1, maximum=128, step=1, value=TRAINING_PARAMS['gradient_accumulation_steps'], | |
| label="Gradient Accumulation Steps", | |
| ) | |
| self.epochs = gr.Slider( | |
| minimum=1, maximum=100, step=1, value=TRAINING_PARAMS['epochs'], | |
| label="Epochs", | |
| ) | |
| self.learning_rate = gr.Slider( | |
| minimum=0.00001, maximum=0.01, value=TRAINING_PARAMS['learning_rate'], | |
| label="Learning Rate", | |
| ) | |
| with gr.Column(): | |
| self.lora_r = gr.Slider( | |
| minimum=1, maximum=64, step=1, value=LORA_TRAINING_PARAMS['lora_r'], | |
| label="LoRA R", | |
| ) | |
| self.lora_alpha = gr.Slider( | |
| minimum=1, maximum=128, step=1, value=LORA_TRAINING_PARAMS['lora_alpha'], | |
| label="LoRA Alpha", | |
| ) | |
| self.lora_dropout = gr.Slider( | |
| minimum=0, maximum=1, step=0.01, value=LORA_TRAINING_PARAMS['lora_dropout'], | |
| label="LoRA Dropout", | |
| ) | |
| def load_model(self, model_name, progress=gr.Progress(track_tqdm=True)): | |
| if model_name == '': return '' | |
| if model_name is None: return self.trainer.model_name | |
| progress(0, desc=f'Loading {model_name}...') | |
| self.trainer.load_model(model_name) | |
| return self.trainer.model_name | |
| def base_model_block(self): | |
| self.model_name = gr.Dropdown(label='Base Model', choices=MODELS) | |
| def training_data_block(self): | |
| training_text = gr.TextArea( | |
| lines=20, | |
| label="Training Data", | |
| info='Paste training data text here. Sequences must be separated with 2 blank lines' | |
| ) | |
| examples_dir = os.path.join(os.getcwd(), 'example-datasets') | |
| def load_example(filename): | |
| with open(os.path.join(examples_dir, filename) , 'r', encoding='utf-8') as f: | |
| return f.read() | |
| example_filename = gr.Textbox(visible=False) | |
| example_filename.change(fn=load_example, inputs=example_filename, outputs=training_text) | |
| gr.Examples("./example-datasets", inputs=example_filename) | |
| self.training_text = training_text | |
| def training_launch_block(self): | |
| with gr.Row(): | |
| with gr.Column(): | |
| self.new_lora_name = gr.Textbox(label='New PEFT Adapter Name', value=random_name()) | |
| with gr.Column(): | |
| train_button = gr.Button('Train', variant='primary') | |
| def train( | |
| training_text, | |
| new_lora_name, | |
| max_seq_length, | |
| micro_batch_size, | |
| gradient_accumulation_steps, | |
| epochs, | |
| learning_rate, | |
| lora_r, | |
| lora_alpha, | |
| lora_dropout, | |
| progress=gr.Progress(track_tqdm=True) | |
| ): | |
| self.trainer.unload_lora() | |
| self.trainer.train( | |
| training_text, | |
| new_lora_name, | |
| max_seq_length=max_seq_length, | |
| micro_batch_size=micro_batch_size, | |
| gradient_accumulation_steps=gradient_accumulation_steps, | |
| epochs=epochs, | |
| learning_rate=learning_rate, | |
| lora_r=lora_r, | |
| lora_alpha=lora_alpha, | |
| lora_dropout=lora_dropout | |
| ) | |
| return new_lora_name | |
| train_button.click( | |
| fn=train, | |
| inputs=[ | |
| self.training_text, | |
| self.new_lora_name, | |
| self.max_seq_length, | |
| self.micro_batch_size, | |
| self.gradient_accumulation_steps, | |
| self.epochs, | |
| self.learning_rate, | |
| self.lora_r, | |
| self.lora_alpha, | |
| self.lora_dropout, | |
| ], | |
| outputs=[self.new_lora_name] | |
| ).then( | |
| fn=lambda x: self.trainer.load_model(x, force=True), | |
| inputs=[self.model_name], | |
| outputs=[] | |
| ) | |
| def inference_block(self): | |
| with gr.Row(): | |
| with gr.Column(): | |
| self.lora_name = gr.Dropdown( | |
| interactive=True, | |
| choices=['None'], | |
| value='None', | |
| label='LoRA', | |
| ) | |
| def load_lora(lora_name, progress=gr.Progress(track_tqdm=True)): | |
| if lora_name == 'None': | |
| self.trainer.unload_lora() | |
| else: | |
| self.trainer.load_lora(f'{LORA_DIR}/{lora_name}') | |
| return lora_name | |
| self.lora_name.change( | |
| fn=load_lora, | |
| inputs=self.lora_name, | |
| outputs=self.lora_name | |
| ) | |
| self.prompt = gr.Textbox( | |
| interactive=True, | |
| lines=5, | |
| label="Prompt", | |
| value="Human: How is cheese made?\nAssistant:" | |
| ) | |
| self.generate_btn = gr.Button('Generate', variant='primary') | |
| with gr.Row(): | |
| with gr.Column(): | |
| self.max_new_tokens = gr.Slider( | |
| minimum=0, maximum=4096, step=1, value=GENERATION_PARAMS['max_new_tokens'], | |
| label="Max New Tokens", | |
| ) | |
| with gr.Column(): | |
| self.do_sample = gr.Checkbox( | |
| interactive=True, | |
| label="Enable Sampling (leave off for greedy search)", | |
| value=True, | |
| ) | |
| with gr.Row(): | |
| with gr.Column(): | |
| self.num_beams = gr.Slider( | |
| minimum=1, maximum=10, step=1, value=GENERATION_PARAMS['num_beams'], | |
| label="Num Beams", | |
| ) | |
| with gr.Column(): | |
| self.repeat_penalty = gr.Slider( | |
| minimum=0, maximum=4.5, step=0.01, value=GENERATION_PARAMS['repetition_penalty'], | |
| label="Repetition Penalty", | |
| ) | |
| with gr.Row(): | |
| with gr.Column(): | |
| self.temperature = gr.Slider( | |
| minimum=0.01, maximum=1.99, step=0.01, value=GENERATION_PARAMS['temperature'], | |
| label="Temperature", | |
| ) | |
| self.top_p = gr.Slider( | |
| minimum=0, maximum=1, step=0.01, value=GENERATION_PARAMS['top_p'], | |
| label="Top P", | |
| ) | |
| self.top_k = gr.Slider( | |
| minimum=0, maximum=200, step=1, value=GENERATION_PARAMS['top_k'], | |
| label="Top K", | |
| ) | |
| with gr.Column(): | |
| self.output = gr.Textbox( | |
| interactive=True, | |
| lines=20, | |
| label="Output" | |
| ) | |
| def generate( | |
| prompt, | |
| do_sample, | |
| max_new_tokens, | |
| num_beams, | |
| repeat_penalty, | |
| temperature, | |
| top_p, | |
| top_k, | |
| progress=gr.Progress(track_tqdm=True) | |
| ): | |
| return self.trainer.generate( | |
| prompt, | |
| do_sample=do_sample, | |
| max_new_tokens=max_new_tokens, | |
| num_beams=num_beams, | |
| repetition_penalty=repeat_penalty, | |
| temperature=temperature, | |
| top_p=top_p, | |
| top_k=top_k | |
| ) | |
| self.generate_btn.click( | |
| fn=generate, | |
| inputs=[ | |
| self.prompt, | |
| self.do_sample, | |
| self.max_new_tokens, | |
| self.num_beams, | |
| self.repeat_penalty, | |
| self.temperature, | |
| self.top_p, | |
| self.top_k | |
| ], | |
| outputs=[self.output] | |
| ) | |
| def layout(self): | |
| with gr.Blocks() as demo: | |
| with gr.Row(): | |
| with gr.Column(): | |
| gr.HTML("""<h2> | |
| <a style="text-decoration: none;" href="https://github.com/lxe/simple-llama-finetuner">🦙 Simple LLM Finetuner</a> <a href="https://huggingface.co/spaces/lxe/simple-llama-finetuner?duplicate=true"><img | |
| src="https://img.shields.io/badge/-Duplicate%20Space-blue?labelColor=white&style=flat&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAP5JREFUOE+lk7FqAkEURY+ltunEgFXS2sZGIbXfEPdLlnxJyDdYB62sbbUKpLbVNhyYFzbrrA74YJlh9r079973psed0cvUD4A+4HoCjsA85X0Dfn/RBLBgBDxnQPfAEJgBY+A9gALA4tcbamSzS4xq4FOQAJgCDwV2CPKV8tZAJcAjMMkUe1vX+U+SMhfAJEHasQIWmXNN3abzDwHUrgcRGmYcgKe0bxrblHEB4E/pndMazNpSZGcsZdBlYJcEL9Afo75molJyM2FxmPgmgPqlWNLGfwZGG6UiyEvLzHYDmoPkDDiNm9JR9uboiONcBXrpY1qmgs21x1QwyZcpvxt9NS09PlsPAAAAAElFTkSuQmCC&logoWidth=14" style="display:inline"> | |
| </a></h2><p>Finetune an LLM on your own text. Duplicate this space onto a GPU-enabled space to run.</p>""") | |
| with gr.Column(): | |
| self.base_model_block() | |
| with gr.Tab('Finetuning'): | |
| with gr.Row(): | |
| with gr.Column(): | |
| self.training_data_block() | |
| with gr.Column(): | |
| self.training_params_block() | |
| self.training_launch_block() | |
| with gr.Tab('Inference') as inference_tab: | |
| with gr.Row(): | |
| with gr.Column(): | |
| self.inference_block() | |
| inference_tab.select( | |
| fn=self.load_loras, | |
| inputs=[], | |
| outputs=[self.lora_name] | |
| ) | |
| self.model_name.change( | |
| fn=self.load_model, | |
| inputs=[self.model_name], | |
| outputs=[self.model_name] | |
| ).then( | |
| fn=self.load_loras, | |
| inputs=[], | |
| outputs=[self.lora_name] | |
| ) | |
| return demo | |
| def run(self): | |
| self.ui = self.layout() | |
| self.ui.queue().launch(show_error=True, share=SHARE) | |
| if (__name__ == '__main__'): | |
| ui = UI() | |
| ui.run() | |