gguf-my-repo / ahjbpp.py
Ffftdtd5dtft's picture
Rename app.py to ahjbpp.py
dbff99b verified
import os
import shutil
import subprocess
import signal
import gradio as gr
from huggingface_hub import create_repo, HfApi, snapshot_download, whoami, ModelCard
from gradio_huggingfacehub_search import HuggingfaceHubSearch
from textwrap import dedent
# Obtener el token de Hugging Face desde el entorno
HF_TOKEN = os.getenv("HF_TOKEN", "")
def ensure_valid_token(oauth_token):
"""Verifica si el token es válido."""
if not oauth_token or not oauth_token.strip():
raise ValueError("Debe proporcionar un token válido.")
return oauth_token.strip()
def generate_importance_matrix(model_path, train_data_path):
"""Genera la matriz de importancia usando llama-imatrix."""
imatrix_command = f"./llama-imatrix -m ../{model_path} -f {train_data_path} -ngl 99 --output-frequency 10"
os.chdir("llama.cpp")
if not os.path.isfile(f"../{model_path}"):
raise FileNotFoundError(f"Archivo del modelo no encontrado: {model_path}")
process = subprocess.Popen(imatrix_command, shell=True)
try:
process.wait(timeout=60)
except subprocess.TimeoutExpired:
process.send_signal(signal.SIGINT)
try:
process.wait(timeout=5)
except subprocess.TimeoutExpired:
process.kill()
os.chdir("..")
def split_upload_model(model_path, repo_id, oauth_token, split_max_tensors=256, split_max_size=None):
"""Divide y sube el modelo en partes."""
if not oauth_token or not oauth_token.strip():
raise ValueError("Debe proporcionar un token válido.")
split_cmd = f"llama.cpp/llama-gguf-split --split --split-max-tensors {split_max_tensors}"
if split_max_size:
split_cmd += f" --split-max-size {split_max_size}"
split_cmd += f" {model_path} {model_path.split('.')[0]}"
result = subprocess.run(split_cmd, shell=True, capture_output=True, text=True)
if result.returncode != 0:
raise RuntimeError(f"Error al dividir el modelo: {result.stderr}")
sharded_model_files = [f for f in os.listdir('.') if f.startswith(model_path.split('.')[0])]
if sharded_model_files:
api = HfApi(token=oauth_token)
for file in sharded_model_files:
file_path = os.path.join('.', file)
try:
api.upload_file(
path_or_fileobj=file_path,
path_in_repo=file,
repo_id=repo_id,
)
except Exception as e:
raise RuntimeError(f"Error al subir el archivo {file_path}: {e}")
else:
raise FileNotFoundError("No se encontraron archivos divididos.")
def process_model(model_id, q_method, use_imatrix, imatrix_q_method, private_repo, train_data_file, split_model, split_max_tensors, split_max_size, oauth_token):
"""Procesa el modelo descargado y realiza la conversión y subida."""
token = ensure_valid_token(oauth_token)
model_name = model_id.split('/')[-1]
fp16 = f"{model_name}.fp16.gguf"
try:
api = HfApi(token=token)
dl_pattern = [
"*.safetensors", "*.bin", "*.pt", "*.onnx", "*.h5", "*.tflite",
"*.ckpt", "*.pb", "*.tar", "*.xml", "*.caffemodel",
"*.md", "*.json", "*.model"
]
pattern = (
"*.safetensors"
if any(
file.path.endswith(".safetensors")
for file in api.list_repo_tree(
repo_id=model_id,
recursive=True,
)
)
else "*.bin"
)
dl_pattern += pattern
snapshot_download(repo_id=model_id, local_dir=model_name, local_dir_use_symlinks=False, allow_patterns=dl_pattern)
print("Modelo descargado exitosamente!")
conversion_script = "convert_hf_to_gguf.py"
fp16_conversion = f"python llama.cpp/{conversion_script} {model_name} --outtype f16 --outfile {fp16}"
result = subprocess.run(fp16_conversion, shell=True, capture_output=True)
if result.returncode != 0:
raise RuntimeError(f"Error al convertir a fp16: {result.stderr}")
imatrix_path = "llama.cpp/imatrix.dat"
if use_imatrix:
if train_data_file:
train_data_path = train_data_file.name
else:
train_data_path = "groups_merged.txt"
if not os.path.isfile(train_data_path):
raise FileNotFoundError(f"Archivo de datos de entrenamiento no encontrado: {train_data_path}")
generate_importance_matrix(fp16, train_data_path)
quantized_gguf_name = f"{model_name.lower()}-{imatrix_q_method.lower()}-imat.gguf" if use_imatrix else f"{model_name.lower()}-{q_method.lower()}.gguf"
quantized_gguf_path = quantized_gguf_name
quantise_ggml = f"./llama.cpp/llama-quantize {'--imatrix ' + imatrix_path if use_imatrix else ''} {fp16} {quantized_gguf_path} {imatrix_q_method if use_imatrix else q_method}"
result = subprocess.run(quantise_ggml, shell=True, capture_output=True)
if result.returncode != 0:
raise RuntimeError(f"Error al cuantificar: {result.stderr}")
username = whoami(token)["name"]
new_repo_url = api.create_repo(repo_id=f"{username}/{model_name}-{imatrix_q_method if use_imatrix else q_method}-GGUF", exist_ok=True, private=private_repo)
new_repo_id = new_repo_url.repo_id
try:
card = ModelCard.load(model_id, token=token)
except:
card = ModelCard("")
if card.data.tags is None:
card.data.tags = []
card.data.tags.append("llama-cpp")
card.data.tags.append("gguf-my-repo")
card.data.base_model = model_id
card.text = dedent(
f"""
# {new_repo_id}
Este modelo fue convertido al formato GGUF desde [`{model_id}`](https://huggingface.co/{model_id}) usando llama.cpp a través del espacio GGUF-my-repo.
Consulta el [card del modelo original](https://huggingface.co/{model_id}) para más detalles.
## Uso con llama.cpp
Instala llama.cpp a través de brew (funciona en Mac y Linux)
```bash
brew install llama.cpp
```
Invoca el servidor llama.cpp o la CLI.
### CLI:
```bash
llama-cli --hf-repo {new_repo_id} --hf-file {quantized_gguf_name} -p "El sentido de la vida y el universo es"
```
### Servidor:
```bash
llama-server --hf-repo {new_repo_id} --hf-file {quantized_gguf_name} -c 2048
```
Nota: También puedes usar este punto de control directamente a través de los [pasos de uso](https://github.com/ggerganov/llama.cpp?tab=readme-ov-file#usage) listados en el repositorio llama.cpp.
"""
)
card.save(f"README.md")
if split_model:
split_upload_model(quantized_gguf_path, new_repo_id, token, split_max_tensors, split_max_size)
else:
try:
api.upload_file(
path_or_fileobj=quantized_gguf_path,
path_in_repo=quantized_gguf_name,
repo_id=new_repo_id,
)
except Exception as e:
raise RuntimeError(f"Error al subir el modelo cuantificado: {e}")
if os.path.isfile(imatrix_path):
try:
api.upload_file(
path_or_fileobj=imatrix_path,
path_in_repo="imatrix.dat",
repo_id=new_repo_id,
)
except Exception as e:
raise RuntimeError(f"Error al subir imatrix.dat: {e}")
api.upload_file(
path_or_fileobj=f"README.md",
path_in_repo=f"README.md",
repo_id=new_repo_id,
)
return (
f'Encuentra tu repositorio <a href=\'{new_repo_url}\' target="_blank" style="text-decoration:underline">aquí</a>',
"llama.png",
)
except Exception as e:
return (f"Error: {e}", "error.png")
finally:
shutil.rmtree(model_name, ignore_errors=True)
with gr.Blocks() as app:
gr.Markdown("# Procesamiento de Modelos")
gr.Markdown(
"""
Este panel permite procesar modelos de machine learning, convertirlos al formato GGUF, y cargarlos en un repositorio de Hugging Face.
Puedes seleccionar diferentes métodos de cuantización y personalizar la conversión usando matrices de importancia.
"""
)
with gr.Row():
model_id = gr.Textbox(
label="ID del Modelo",
placeholder="username/model-name",
info="Introduce el ID del modelo en Hugging Face que deseas procesar.",
)
q_method = gr.Dropdown(
["IQ3_M", "IQ3_XXS", "Q4_K_M", "Q4_K_S", "IQ4_NL", "IQ4_XS", "Q5_K_M", "Q5_K_S"],
label="Método de Cuantización",
info="Selecciona el método de cuantización que deseas aplicar al modelo."
)
use_imatrix = gr.Checkbox(
label="Usar Matriz de Importancia",
info="Marca esta opción si deseas usar una matriz de importancia para la cuantización."
)
imatrix_q_method = gr.Dropdown(
["IQ3_M", "IQ3_XXS", "Q4_K_M", "Q4_K_S", "IQ4_NL", "IQ4_XS", "Q5_K_M", "Q5_K_S"],
label="Método de Matriz de Importancia",
info="Selecciona el método de cuantización para la matriz de importancia.",
visible=False # Solo visible si se marca 'use_imatrix'
)
private_repo = gr.Checkbox(
label="Repositorio Privado",
info="Marca esta opción si deseas que el repositorio creado sea privado."
)
train_data_file = gr.File(
label="Archivo de Datos de Entrenamiento",
type="filepath",
info="Selecciona el archivo que contiene los datos de entrenamiento necesarios para generar la matriz de importancia.",
)
split_model = gr.Checkbox(
label="Dividir Modelo",
info="Marca esta opción para dividir el modelo en partes más pequeñas antes de subirlo."
)
split_max_tensors = gr.Number(
label="Max Tensors (para división)",
value=256,
info="Especifica el número máximo de tensores por parte si estás dividiendo el modelo.",
)
split_max_size = gr.Number(
label="Max Tamaño (para división)",
value=None,
info="Especifica el tamaño máximo de cada parte si estás dividiendo el modelo.",
)
oauth_token = gr.Textbox(
label="Token de Hugging Face",
type="password",
info="Introduce tu token de autenticación de Hugging Face. Asegúrate de que el token sea válido para acceder a los repositorios."
)
with gr.Row():
result = gr.HTML(label="Resultado")
img = gr.Image(label="Imagen")
process_button = gr.Button("Procesar Modelo")
process_button.click(
process_model,
inputs=[model_id, q_method, use_imatrix, imatrix_q_method, private_repo, train_data_file, split_model, split_max_tensors, split_max_size, oauth_token],
outputs=[result, img]
)
app.launch()