mirror of
https://github.com/MartinGia/lora-analyzer.git
synced 2026-05-04 12:32:57 +02:00
Primera versión: LoRA Analyzer completo con CLI, Web App y API
This commit is contained in:
169
lora_cli.py
Normal file
169
lora_cli.py
Normal file
@@ -0,0 +1,169 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
LoRA Analyzer CLI
|
||||
Herramienta de línea de comandos para analizar archivos LoRA
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import json
|
||||
from pathlib import Path
|
||||
from lora_analyzer import LoRAAnalyzer, format_analysis_report
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Analiza archivos LoRA y extrae información técnica",
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""
|
||||
Ejemplos de uso:
|
||||
# Analizar un archivo
|
||||
python lora_cli.py mi_lora.safetensors
|
||||
|
||||
# Guardar resultado en JSON
|
||||
python lora_cli.py mi_lora.safetensors --output resultado.json
|
||||
|
||||
# Analizar múltiples archivos
|
||||
python lora_cli.py lora1.safetensors lora2.pt lora3.ckpt
|
||||
|
||||
# Modo verbose con más detalles
|
||||
python lora_cli.py mi_lora.safetensors --verbose
|
||||
"""
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"files",
|
||||
nargs="+",
|
||||
help="Archivo(s) LoRA a analizar (.safetensors, .pt, .ckpt)"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-o", "--output",
|
||||
help="Guardar resultado en archivo JSON",
|
||||
type=str
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-v", "--verbose",
|
||||
action="store_true",
|
||||
help="Mostrar información detallada"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--json",
|
||||
action="store_true",
|
||||
help="Salida en formato JSON"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--compare",
|
||||
action="store_true",
|
||||
help="Comparar múltiples LoRAs (requiere 2+ archivos)"
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Validar archivos
|
||||
files = [Path(f) for f in args.files]
|
||||
for f in files:
|
||||
if not f.exists():
|
||||
print(f"❌ Error: El archivo no existe: {f}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
results = []
|
||||
|
||||
# Analizar cada archivo
|
||||
for file_path in files:
|
||||
print(f"\n🔍 Analizando: {file_path.name}")
|
||||
print("-" * 70)
|
||||
|
||||
try:
|
||||
analyzer = LoRAAnalyzer(str(file_path))
|
||||
analysis = analyzer.analyze()
|
||||
results.append(analysis)
|
||||
|
||||
if args.json:
|
||||
print(json.dumps(analysis, indent=2, ensure_ascii=False))
|
||||
else:
|
||||
print(format_analysis_report(analysis))
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error al analizar {file_path.name}: {str(e)}", file=sys.stderr)
|
||||
if args.verbose:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
# Modo comparación
|
||||
if args.compare and len(results) > 1:
|
||||
print("\n" + "=" * 70)
|
||||
print("📊 COMPARACIÓN DE LORAS")
|
||||
print("=" * 70)
|
||||
compare_loras(results)
|
||||
|
||||
# Guardar en JSON si se especificó
|
||||
if args.output and results:
|
||||
output_path = Path(args.output)
|
||||
with open(output_path, 'w', encoding='utf-8') as f:
|
||||
json.dump(results, f, indent=2, ensure_ascii=False)
|
||||
print(f"\n✅ Resultados guardados en: {output_path}")
|
||||
|
||||
|
||||
def compare_loras(results):
|
||||
"""Compara múltiples LoRAs"""
|
||||
print("\n📋 Comparación de características:\n")
|
||||
|
||||
# Tabla comparativa
|
||||
headers = ["Característica"] + [r["file_info"]["nombre"] for r in results]
|
||||
|
||||
comparisons = []
|
||||
|
||||
# Tamaño
|
||||
row = ["Tamaño (MB)"]
|
||||
for r in results:
|
||||
row.append(f"{r['file_info'].get('tamaño_mb', 'N/A')}")
|
||||
comparisons.append(row)
|
||||
|
||||
# Rank
|
||||
row = ["Rank"]
|
||||
for r in results:
|
||||
rank_info = r.get("architecture", {}).get("rank_info", {})
|
||||
rank = rank_info.get("most_common_rank", "N/A")
|
||||
row.append(str(rank))
|
||||
comparisons.append(row)
|
||||
|
||||
# Capas
|
||||
row = ["Total capas"]
|
||||
for r in results:
|
||||
layers = r.get("architecture", {}).get("total_layers", "N/A")
|
||||
row.append(str(layers))
|
||||
comparisons.append(row)
|
||||
|
||||
# Imágenes de entrenamiento
|
||||
row = ["Imágenes entreno"]
|
||||
for r in results:
|
||||
num_images = r.get("metadata", {}).get("ss_num_train_images", "N/A")
|
||||
row.append(str(num_images))
|
||||
comparisons.append(row)
|
||||
|
||||
# Learning rate
|
||||
row = ["Learning rate"]
|
||||
for r in results:
|
||||
lr = r.get("metadata", {}).get("ss_learning_rate", "N/A")
|
||||
row.append(str(lr))
|
||||
comparisons.append(row)
|
||||
|
||||
# Imprimir tabla
|
||||
col_widths = [max(len(str(row[i])) for row in [headers] + comparisons) + 2
|
||||
for i in range(len(headers))]
|
||||
|
||||
# Header
|
||||
print(" ".join(h.ljust(w) for h, w in zip(headers, col_widths)))
|
||||
print("-" * sum(col_widths))
|
||||
|
||||
# Filas
|
||||
for row in comparisons:
|
||||
print(" ".join(str(cell).ljust(w) for cell, w in zip(row, col_widths)))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user