File size: 6,409 Bytes
f1d86e3
a2dd494
fce580f
f1d86e3
a2dd494
fce580f
 
 
a2dd494
fce580f
 
b79aa7a
 
f1d86e3
 
237774d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a2dd494
 
b79aa7a
 
 
 
 
 
 
 
 
 
 
 
 
7ba846b
 
 
 
 
 
b79aa7a
 
 
 
f1d86e3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a2dd494
 
 
 
 
 
 
 
b79aa7a
 
 
 
 
 
 
7ba846b
 
a2dd494
 
 
fce580f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a2dd494
fce580f
 
b79aa7a
 
fce580f
 
 
 
 
 
 
 
 
 
 
 
b79aa7a
 
 
 
 
 
7ba846b
 
 
 
b79aa7a
 
 
 
a2dd494
 
 
b79aa7a
 
 
 
a2dd494
b79aa7a
 
a2dd494
 
 
b79aa7a
 
 
 
 
 
 
 
 
a2dd494
 
b79aa7a
 
 
 
a2dd494
 
 
fce580f
a2dd494
 
 
 
fce580f
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
import hashlib
import json
import os
import re
from collections import Counter
import torch
from huggingface_hub import HfApi, hf_hub_download
from huggingface_hub.utils import EntryNotFoundError, RepositoryNotFoundError

LEADERBOARD_DATASET_REPO = "minoruskore/top"
LEADERBOARD_FILENAME = "leaderboard.json"
MODEL_TYPE_CLASIFICACION = "clasificacion"
MODEL_TYPE_SR = "sr"
PATRON_MATRICULA = re.compile(r"^\d{2}-[A-Z]{4,5}-\d-\d{3}$")
MENSAJE_ERROR_DATOS_ESTUDIANTE = "Error: rokugogosango"


def cargar_etiquetas():
    with open("etiquetas.txt", "r") as f:
        etiquetas = f.read().splitlines()[1:]
    num_clases = len(etiquetas)
    codigo = {etiqueta.lower(): i for i, etiqueta in enumerate(etiquetas)}

    return etiquetas, num_clases, codigo


def multiclass_accuracy(predictions, labels):
    # Obtén las clases predichas (la clase con la mayor probabilidad)
    _, predicted_classes = torch.max(predictions, 1)

    # Compara las clases predichas con las etiquetas verdaderas
    correct_predictions = (predicted_classes == labels).sum().item()

    # Calcula la precisión
    accuracy = correct_predictions / labels.size(0)

    return accuracy


def calcular_psnr(predictions, targets):
    predictions = predictions.clamp(0, 1)
    targets = targets.clamp(0, 1)
    mse = torch.mean((predictions - targets) ** 2)

    if mse <= 0:
        return 100.0

    return float((10 * torch.log10(torch.tensor(1.0, device=mse.device) / mse)).item())


def normalizar_tipo_modelo(model_type):
    value = (model_type or MODEL_TYPE_CLASIFICACION).strip().lower()
    if value in {
        MODEL_TYPE_SR,
        "superresolucion",
        "super-resolucion",
        "super resolution",
    }:
        return MODEL_TYPE_SR
    return MODEL_TYPE_CLASIFICACION


def normalizar_nombre(nombre):
    return " ".join((nombre or "").strip().split())


def validar_nombre_completo(nombre):
    nombre = normalizar_nombre(nombre)
    if len(nombre.split()) < 2:
        return MENSAJE_ERROR_DATOS_ESTUDIANTE
    return None


def validar_matricula(matricula):
    matricula = (matricula or "").strip()
    if not PATRON_MATRICULA.fullmatch(matricula):
        return MENSAJE_ERROR_DATOS_ESTUDIANTE
    return None


def validar_datos_estudiante(nombre, matricula):
    error_nombre = validar_nombre_completo(nombre)
    if error_nombre:
        return error_nombre
    return validar_matricula(matricula)


def obtener_sha256(ruta_archivo):
    sha256 = hashlib.sha256()
    with open(ruta_archivo, "rb") as archivo:
        for bloque in iter(lambda: archivo.read(8192), b""):
            sha256.update(bloque)
    return sha256.hexdigest()


def calcular_puntaje(metric_value, model_type=MODEL_TYPE_CLASIFICACION):
    model_type = normalizar_tipo_modelo(model_type)

    if model_type == MODEL_TYPE_SR:
        return max(0, int(metric_value - 10))

    accuracy_pct = metric_value * 100
    base = max(0, min(accuracy_pct - 50, 30))
    extra = 10 if accuracy_pct > 90 else 0
    return int(base + extra)


def _obtener_hf_token():
    for env_var in ("HFKEY", "HF_TOKEN", "HUGGINGFACEHUB_API_TOKEN"):
        token = os.environ.get(env_var)
        if token:
            return token

    raise RuntimeError(
        "No se encontró un token de Hugging Face en HFKEY, HF_TOKEN o "
        "HUGGINGFACEHUB_API_TOKEN."
    )


def _crear_cliente_hf():
    return HfApi()


def _subir_leaderboard(registros, commit_message):
    token = _obtener_hf_token()
    api = _crear_cliente_hf()
    payload = json.dumps(registros, indent=2, ensure_ascii=False).encode("utf-8")

    api.create_repo(
        repo_id=LEADERBOARD_DATASET_REPO,
        repo_type="dataset",
        private=True,
        exist_ok=True,
        token=token,
    )
    api.upload_file(
        path_or_fileobj=payload,
        path_in_repo=LEADERBOARD_FILENAME,
        repo_id=LEADERBOARD_DATASET_REPO,
        repo_type="dataset",
        token=token,
        commit_message=commit_message,
    )


def _descargar_leaderboard():
    token = _obtener_hf_token()

    try:
        ruta_local = hf_hub_download(
            repo_id=LEADERBOARD_DATASET_REPO,
            filename=LEADERBOARD_FILENAME,
            repo_type="dataset",
            token=token,
            force_download=True,
        )
    except (EntryNotFoundError, RepositoryNotFoundError):
        _subir_leaderboard([], "Initialize leaderboard storage")
        return []

    with open(ruta_local, "r", encoding="utf-8") as f:
        registros = json.load(f)

    if not isinstance(registros, list):
        raise ValueError(
            f"El archivo {LEADERBOARD_FILENAME} en el dataset "
            f"{LEADERBOARD_DATASET_REPO} debe contener una lista JSON."
        )

    return registros


def cargar_leaderboard():
    registros = _descargar_leaderboard()

    normalizados = []
    for entry in registros:
        registro = dict(entry)
        registro["model_type"] = normalizar_tipo_modelo(
            registro.get("model_type", MODEL_TYPE_CLASIFICACION)
        )
        if (
            registro["model_type"] == MODEL_TYPE_CLASIFICACION
            and "accuracy_pct" not in registro
        ):
            registro["accuracy_pct"] = registro.get("accuracy", 0) * 100
        normalizados.append(registro)

    return _marcar_duplicados(normalizados)


def _marcar_duplicados(registros):
    conteo = Counter(
        (normalizar_tipo_modelo(entry.get("model_type")), entry["sha256"])
        for entry in registros
    )
    for entry in registros:
        key = (normalizar_tipo_modelo(entry.get("model_type")), entry["sha256"])
        entry["duplicado"] = conteo[key] > 1
    return registros


def filtrar_leaderboard_por_tipo(registros, model_type):
    model_type = normalizar_tipo_modelo(model_type)
    return [
        entry
        for entry in registros
        if normalizar_tipo_modelo(entry.get("model_type")) == model_type
    ]


def guardar_registro_leaderboard(entry, max_entries=500):
    registros = cargar_leaderboard()
    entry = dict(entry)
    entry["model_type"] = normalizar_tipo_modelo(
        entry.get("model_type", MODEL_TYPE_CLASIFICACION)
    )
    registros.append(entry)
    registros = registros[-max_entries:]
    registros = _marcar_duplicados(registros)
    _subir_leaderboard(registros, "Update leaderboard")
    return registros


def limpiar_leaderboard():
    _subir_leaderboard([], "Reset leaderboard")