Download scripts/compare_loss.py from zhicao/dreamzero: direct link, hf CLI and curl.
- Browser
- Download file 3.68 kB
-
https://huggingface.co/zhicao/dreamzero/resolve/main/scripts/compare_loss.py
- Command line
-
hf download hf://zhicao/dreamzero/scripts/compare_loss.py
-
curl -L -o compare_loss.py https://huggingface.co/zhicao/dreamzero/resolve/main/scripts/compare_loss.py
3.68 kB
| #!/usr/bin/env python3 | |
| """Compare loss curves between LoRA and full fine-tuning runs. | |
| Usage: | |
| python scripts/compare_loss.py \ | |
| --lora-log ./checkpoints/dreamzero_droid_lora/loss_log.jsonl \ | |
| --full-log ./checkpoints/dreamzero_droid_full_finetune/loss_log.jsonl \ | |
| [--plot loss_comparison.png] | |
| """ | |
| import argparse | |
| import json | |
| def load_loss_log(path): | |
| entries = [] | |
| with open(path) as f: | |
| for line in f: | |
| line = line.strip() | |
| if line: | |
| entries.append(json.loads(line)) | |
| return entries | |
| def print_comparison_table(lora_entries, full_entries): | |
| # Index by step | |
| lora_by_step = {e["step"]: e for e in lora_entries} | |
| full_by_step = {e["step"]: e for e in full_entries} | |
| all_steps = sorted(set(lora_by_step.keys()) | set(full_by_step.keys())) | |
| header = f"{'Step':>6} {'LoRA Loss':>10} {'Full Loss':>10} {'LoRA Dyn':>10} {'Full Dyn':>10} {'LoRA Act':>10} {'Full Act':>10}" | |
| print(header) | |
| print("-" * len(header)) | |
| for step in all_steps: | |
| lora = lora_by_step.get(step, {}) | |
| full = full_by_step.get(step, {}) | |
| def fmt(d, key): | |
| v = d.get(key) | |
| return f"{v:10.4f}" if v is not None else f"{'—':>10}" | |
| print( | |
| f"{step:>6} " | |
| f"{fmt(lora, 'loss')} {fmt(full, 'loss')} " | |
| f"{fmt(lora, 'dynamics_loss_avg')} {fmt(full, 'dynamics_loss_avg')} " | |
| f"{fmt(lora, 'action_loss_avg')} {fmt(full, 'action_loss_avg')}" | |
| ) | |
| def plot_comparison(lora_entries, full_entries, output_path): | |
| try: | |
| import matplotlib.pyplot as plt | |
| except ImportError: | |
| print("matplotlib not installed, skipping plot generation.") | |
| print("Install with: pip install matplotlib") | |
| return | |
| metrics = [ | |
| ("loss", "Total Loss"), | |
| ("dynamics_loss_avg", "Dynamics Loss"), | |
| ("action_loss_avg", "Action Loss"), | |
| ] | |
| fig, axes = plt.subplots(1, len(metrics), figsize=(5 * len(metrics), 4)) | |
| if len(metrics) == 1: | |
| axes = [axes] | |
| for ax, (key, title) in zip(axes, metrics): | |
| lora_steps = [e["step"] for e in lora_entries if key in e] | |
| lora_vals = [e[key] for e in lora_entries if key in e] | |
| full_steps = [e["step"] for e in full_entries if key in e] | |
| full_vals = [e[key] for e in full_entries if key in e] | |
| if lora_steps: | |
| ax.plot(lora_steps, lora_vals, label="LoRA", marker="o", markersize=3) | |
| if full_steps: | |
| ax.plot(full_steps, full_vals, label="Full FT", marker="s", markersize=3) | |
| ax.set_title(title) | |
| ax.set_xlabel("Step") | |
| ax.set_ylabel("Loss") | |
| ax.legend() | |
| ax.grid(True, alpha=0.3) | |
| fig.tight_layout() | |
| fig.savefig(output_path, dpi=150) | |
| print(f"Plot saved to {output_path}") | |
| def main(): | |
| parser = argparse.ArgumentParser(description="Compare LoRA vs full fine-tuning loss curves") | |
| parser.add_argument("--lora-log", required=True, help="Path to LoRA run loss_log.jsonl") | |
| parser.add_argument("--full-log", required=True, help="Path to full FT run loss_log.jsonl") | |
| parser.add_argument("--plot", default=None, help="Output path for comparison plot (e.g., loss_comparison.png)") | |
| args = parser.parse_args() | |
| lora_entries = load_loss_log(args.lora_log) | |
| full_entries = load_loss_log(args.full_log) | |
| print(f"LoRA: {len(lora_entries)} log entries") | |
| print(f"Full: {len(full_entries)} log entries") | |
| print() | |
| print_comparison_table(lora_entries, full_entries) | |
| if args.plot: | |
| plot_comparison(lora_entries, full_entries, args.plot) | |
| if __name__ == "__main__": | |
| main() | |