Spaces:
Running on Zero
Running on Zero
| from __future__ import annotations | |
| import gradio as gr | |
| from training.evaluation import ( | |
| attach_perplexity, | |
| compare_base_vs_tuned, | |
| default_prompt_cases, | |
| evaluate_responses, | |
| log_eval_report, | |
| ) | |
| from training.lora_trainer import build_lora_training_request, vision_finetuning_plan | |
| from training.planner import build_training_plan | |
| from ui.progress import CLICK_PROGRESS | |
| def build_train_tab() -> None: | |
| gr.Markdown("LoRA training is planned for the next implementation slice.") | |
| build_lora_plan_panel() | |
| build_vision_finetuning_panel() | |
| build_local_evaluation_panel() | |
| def build_lora_plan_panel() -> None: | |
| with gr.Row(): | |
| rank = gr.Slider(4, 64, value=16, step=4, label="LoRA rank") | |
| epochs = gr.Slider(1, 5, value=1, step=1, label="Epochs") | |
| dataset = gr.Textbox(label="Training dataset", placeholder="data/field_notes.jsonl") | |
| start = gr.Button("Prepare training plan", variant="primary") | |
| output = gr.Textbox(label="Plan", lines=8) | |
| lora_request = gr.JSON(label="LoRA trainer request") | |
| start.click( | |
| plan_training, | |
| [rank, epochs, dataset], | |
| output, | |
| show_progress=CLICK_PROGRESS, | |
| ) | |
| lora = gr.Button("Prepare LoRA trainer request") | |
| lora.click( | |
| plan_lora_request, | |
| [rank, epochs, dataset], | |
| lora_request, | |
| show_progress=CLICK_PROGRESS, | |
| ) | |
| def build_vision_finetuning_panel() -> None: | |
| gr.Markdown("### Vision fine-tuning") | |
| gr.JSON(vision_finetuning_plan(), label="SWIFT / LLaMA-Factory plan") | |
| def build_local_evaluation_panel() -> None: | |
| gr.Markdown("### Local evaluation") | |
| base_responses = gr.Textbox( | |
| label="Base responses", | |
| lines=4, | |
| placeholder="One response per default prompt case", | |
| ) | |
| tuned_responses = gr.Textbox( | |
| label="Tuned responses", | |
| lines=4, | |
| placeholder="One response per default prompt case", | |
| ) | |
| tuned_losses = gr.Textbox( | |
| label="Optional tuned losses", | |
| lines=2, | |
| placeholder="Optional negative log likelihood values, comma or newline separated", | |
| ) | |
| run_eval = gr.Button("Run local evaluation") | |
| eval_summary = gr.JSON(label="Evaluation summary") | |
| eval_table = gr.Dataframe( | |
| headers=["prompt", "expected", "actual", "exact_match", "notes"], | |
| label="Tuned qualitative table", | |
| interactive=False, | |
| ) | |
| run_eval.click( | |
| evaluate_local, | |
| [base_responses, tuned_responses, tuned_losses], | |
| [eval_summary, eval_table], | |
| show_progress=CLICK_PROGRESS, | |
| ) | |
| def plan_training(rank_value: int, epoch_value: int, dataset_path: str) -> str: | |
| plan = build_training_plan( | |
| dataset_path=dataset_path, | |
| rank=rank_value, | |
| epochs=epoch_value, | |
| ) | |
| return plan.as_text() | |
| def plan_lora_request(rank_value: int, epoch_value: int, dataset_path: str) -> dict: | |
| request = build_lora_training_request( | |
| model_id="minicpm5_1b", | |
| dataset_path=dataset_path, | |
| rank=rank_value, | |
| epochs=epoch_value, | |
| ) | |
| return request.as_dict() | |
| def evaluate_local( | |
| base_text: str, | |
| tuned_text: str, | |
| loss_text: str, | |
| ) -> tuple[dict, list[list[str]]]: | |
| cases = default_prompt_cases() | |
| base_report = evaluate_responses(cases, base_text.splitlines()) | |
| tuned_report = evaluate_responses(cases, tuned_text.splitlines()) | |
| tuned_report = attach_perplexity(tuned_report, parse_losses(loss_text)) | |
| comparison = compare_base_vs_tuned(base_report, tuned_report) | |
| log_eval_report(tuned_report) | |
| summary = comparison.as_dict() | |
| summary["tuned_perplexity"] = tuned_report.perplexity | |
| return summary, tuned_report.as_table() | |
| def parse_losses(loss_text: str) -> list[float]: | |
| cleaned = loss_text.replace(",", "\n") | |
| return [float(value.strip()) for value in cleaned.splitlines() if value.strip()] | |