def showRanking(num_nets_to_show=-1): """ Muestra el ranking usando el gran json de entrenamientos realizados. En el futuro se usara un diccionario ordenado, no teniendo que ordenar al cargar el json. """ # Cargamos el gran json big_trained_json = info_handler.loadTheBigTrainedJson() # Transformamos a lista de CL_trainer net_list = [] for key in big_trained_json: net = info_handler.json2CL_trainer(big_trained_json[key]) net_list.append(net) # Ordenamos la lista sorted_net_list = sortNetPool(net_list) # Mostramos el ranking por pantalla con colores __printRanking(sorted_net_list, colored_text=True, num_nets_to_show=num_nets_to_show) # Obtenemos el ranking como str sin colores str_ranking = __printRanking(sorted_net_list, just_return_str=True, num_nets_to_show=num_nets_to_show, str_type="tab") # Enviamos ranking al admin sendMSG("Mostrando ranking de " + str(len(sorted_net_list)) + " redes:") sendMSG(str_ranking, dont_print=True)
def __obtenerDataLoader(self): """ Funcion que crea y devuelve un par de data loaders, uno de entrenamiento y otro de validacion. Los data loaders utilizan el dataset loader propio de ClasiLamb y contienen la cantidad de imagenes especificada por la variable de clase training_percent """ # Transformaciones transforms_list = [transforms.ToTensor(), transforms.Normalize((0),(2000)) ] transform = transforms.Compose(transforms_list) # dataset dataset = dynamic_dataset_loader.CLDL_b1(self.dataset_path, transform=transform) #sendMSG("Dataset:\n" + str(dataset)) # Data loader de entrenamiento y validacion t_number = int(len(dataset) * self.training_percent) v_number = len(dataset) - t_number sendMSG("img_entrenamiento: " + str(t_number) + " img_validacion: " + str(v_number)) train_set, validation_set = torch.utils.data.random_split(dataset,[t_number,v_number]) train_loader = DataLoader(dataset=train_set, shuffle=self.shuffle, batch_size=self.batch_size, num_workers=self.num_workers, pin_memory=self.pin_memory) validation_loader = DataLoader(dataset=validation_set, shuffle=self.shuffle, batch_size=self.batch_size, num_workers=self.num_workers, pin_memory=self.pin_memory) return train_loader, validation_loader
def readOneTask(): """ Carga el gran json de tareas, extrae una tarea y lo guarda. Devuelve la tarea transformada en CL_trainer. Si no quedan tareas, devuelve None """ # Cargamos el gran json de tareas big_task_json = info_handler.loadTheBigTaskJson() # Informamos de la cantidad de tareas que quedan sendMSG("Quedan " + str(len(big_task_json)) + " tareas por hacer.") # Comprobamos si quedan tareas para devolver if len(big_task_json) > 0: # Seleccionamos una tarea ret_key = list(big_task_json.keys())[0] # Extraemos la tarea (eliminandola del json) ret_jsoned_net = big_task_json.pop(ret_key) # Guardamos el json info_handler.saveTheBigTaskJson(big_task_json) # Devolvemos la tarea return info_handler.json2CL_trainer(ret_jsoned_net) else: sendMSG("No quedan tareas por hacer en el gran json de tareas", is_warning=True) return None
def generateTasks(num_tasks): """ Genera un numero dado de redes preparadas para iniciar su entrenamiento y las guarda como tareas en el gran json de tareas. """ # Generamos un pool de redes nets_list = createRandomNetPool(num_tasks) # Las transformamos a formato json json_list = [info_handler.CL_trainer2json(x) for x in nets_list] # Cargamos el gran json de tareas big_task_json = info_handler.loadTheBigTaskJson() # Acumulamos las tareas for jsoned_task in json_list: net_name = jsoned_task["model_name"] big_task_json[net_name] = jsoned_task # ¿hacemos copia antes? # Guardamos el gran json con las nuevas tareas acumuladas info_handler.saveTheBigTaskJson(big_task_json) # Enviamos mensaje de aviso if num_tasks == 1: sendMSG("Añadiendo 1 tarea al gran json") else: sendMSG("Añadiendo " + str(num_tasks) + " tareas al gran json")
def CtrlC_signal_handler(sig, frame): """ Esta funcion se ejecuta cada vez que el usuario utiliza la combinacion Ctrl+C """ print("\n\n\n") sendMSG("Ctrl+C o SIGINT detectado, cerrando programa... ", is_error=True) exit(0)
def obtenerValidationAccuracy(self, epoch=None): """ Devuelve el Validation Accuracy de una epoca. Si no se especifica ningun valor, devuelve el Validation Accuracy definitivo de la red. """ if self.trained: if epoch is None: return self.net_val_accuracy else: return self.history["val_accuracy"][-1] else: sendMSG("Aun no se ha entrenado este modelo.", is_warning=True)
def obtenerTrainLoss(self, epoch=None): """ Devuelve el Train Loss de una epoca. Si no se especifica ningun valor, devuelve el Train Loss definitivo de la red. """ if self.trained: if epoch is None: return self.net_train_loss else: return self.history["loss"][-1] else: sendMSG("Aun no se ha entrenado este modelo.", is_warning=True)
def obtenerFalsePositives(self, epoch=None): """ Devuelve los false negatives de una epoca. Si no se especifica ningun valor, devuelve los false negatives definitivos de la red. """ if self.trained: if epoch is None: return self.net_false_negatives else: return self.history["net_false_negatives"][epoch] else: sendMSG("Aun no se ha entrenado este modelo.", is_warning=True)
def sendStarMSG(): """ Realiza el envio de un mensaje inicial. """ msg = "" for i in range(6): msg += ":black_square_button:" msg += " Inicio de entrenamiento " for i in range(6): msg += ":black_square_button:" sendMSG(msg)
def sendFinalMSG(): """ realiza el envio y muestra el mensaje final. Indicando que todo ha finalizado correctamente. """ msg = "" for i in range(6): msg += ":white_large_square:" msg += " Ejecucion terminada " for i in range(6): msg += ":white_large_square:" sendMSG(msg)
def obtenerMetricasFinales(self): """ Devuelve todas las metricas en un dict. El dict contiene listas siguiendo la siguiente estructura: } "loss": [], "val_loss": [], "accuracy": [], "val_accuracy": [] } Donde cada lista contiene valores ordenados por epocas segun el indice. """ if self.trained: return self.history else: sendMSG("Aun no se ha entrenado este modelo.", is_warning=True)
def trainTask(): """ Obtiene una tarea del gran json de tareas y la entrena. Posteriormente guarda la red entrenada en el gran json de entrenamientos realizados. Si no quedan tareas por hacer, lanza un mensaje de advertencia y devuelve None. Devuelve 0 en otro caso. Si no se puede entrenar la red por que no cabe en la gpu, envia un mensaje y termina. Descarta la red. """ # Obtenemos una tarea task = readOneTask() if task is None: # Notificamos que no quedan tareas por hacer y paramos sendMSG("No quedan tareas por hacer", is_warning=True) return None # Entrenamos la tarea try: trainNetPool([task]) except: sendMSG("La red no cabe en la GPU. Descartando...", is_warning=True) sendMSG(traceback.format_exc(), is_error=True) return 0 # Si la red no tienen NaN o Inf, guardamos los resultados if task.nan_or_inf == False: saveOneDoneTask(task) return 0
def trainRemainingTasks(): """ Inicia el entrenamiento de todas las tareas que queden por realizar. """ # mientras queden tareas, entrenamos control = 0 i = 0 # Cantidad de cuadrados s = 6 while control is not None: sendMSG( getHashedSquares(i, s) + " RED " + str(i) + " " + getHashedSquares(i, s)) control = trainTask() # Si la red no tiene NaN if control == 0: sendMSG("Dando un descanso a la GPU de " + str(timedelta(seconds=GPU_BREAK_TIME)) + "\n\n") time.sleep(GPU_BREAK_TIME) i += 1 elif control == 1: # Una tarea ha sido NaN, por lo que creamos una nueva para compensar generateTasks(1) # No quedan tareas por realizar sendMSG("Se han acabado todas las tareas con exito.")
def iniciarEntrenamiento(self): """ Inicia el entrenamiento del modelo durante todas las epocas. Es bloqueante. """ # Obtenemos los data loaders train_loader, validation_loader = self.__obtenerDataLoader() # Construimos la red self.model = self.__construirRed(self.net_layer_struct) self.num_params = sum(p.numel() for p in self.model.parameters()) # Definimos la funcion de coste y el optimizador loss_fn, optimizer = self.__obtenerFuncionDeCosteYOptimizador( self.model) # Entrenamos el modelo (BLOQUEANTE!) sendMSG("Iniciando entrenamiento de la red...") self.__iniciarEntrenamiento(self.model, loss_fn, optimizer, train_loader, validation_loader) sendMSG("Entrenamiento de la red terminado.") # Guardamos la grafica del entrenamiento y el modelo self.guardarGrafica() self.guardarModelo() self.trained = True # Enviamos las metricas finales sendMSG(self.getTabuledSTR())
def trainRemainingTasks(): """ Inicia el entrenamiento de todas las tareas que queden por realizar. """ # mientras queden tareas, entrenamos control = 0 i = 0 # Cantidad de cuadrados s = 6 while control is not None: sendMSG( getHashedSquares(i, s) + " RED " + str(i) + " " + getHashedSquares(i, s)) control = trainTask() sendMSG("Dando un descanso a la GPU de " + str(timedelta(seconds=GPU_BREAK_TIME)) + "\n\n") time.sleep(GPU_BREAK_TIME) i += 1 # No quedan tareas por realizar sendMSG("Se han acabado todas las tareas con exito.")
import contest import telegram_debugger from telegram_debugger import sendMSG import traceback # PARAMETROS NUM_NETWORKS = 20 try: # Mensaje inicial contest.sendStarMSG() # Generamos las tareas #contest.generateTasks(NUM_NETWORKS) # Iniciamos el entrenamiento de las tareas contest.trainRemainingTasks() # Mostramos el ranking contest.showRanking() # Mensaje final contest.sendFinalMSG() except Exception as e: # Enviamos el error al admin sendMSG("ERROR", is_error=True) sendMSG(traceback.format_exc(), is_error=True)
def __iniciarEntrenamiento(self, model, loss_fn, optimizer, train_loader, validation_loader): """ Funcion privada que inicia el entrenamiento. La funcion es bloqueante y realiza el entrenamiento completo del modelo a traves de todas las epocas. Una vez el entrenamiento termina, se almacenan las metricas finales en la variable de clase history. """ # Todo lo que envueleve a donex es para poder ver los datos del dataset. # Poniendolo a True se quita dicha funcionalidad donex = True # Historial de metricas history = { "loss": [], "val_loss": [], "accuracy": [], "val_accuracy": [] } # Ponemos el modelo en modo entrenamiento model.train() bar_manager = enlighten.get_manager() epochs_bar = bar_manager.counter(total=self.epochs, desc="Epochs: ", unit='Epochs', position=2, leave=True, color=(150, 255, 0)) # Entrenamos!! ====================== loop ======================= for epoch in range(self.epochs): ent_loss_list = [] num_correct = 0 num_samples = 0 train_bar = bar_manager.counter(total=len(train_loader), desc="Training: ", unit='img', position=1, leave=False, color=(50, 150, 0)) for imgs, labels in train_loader: # Preparamso las imagenes imgs = imgs.to(device) labels = labels.to(device) if not donex: print( self.C + "--------------------------- Datos de los Tensores del Dataset ---------------------------\n\n" ) #print(torch.unique(imgs)) #print(imgs) print("dimensiones: ", imgs.size()) print("dtype: ", imgs.dtype, "\n\n") print("Label: ", labels, " dimensiones: ", labels.size(), " dtype: ", labels.dtype, "\n\n" + self.B) donex = True # Sacamos las predicciones outputs = model(imgs) predictions = torch.tensor( [1.0 if i >= 0.5 else 0.0 for i in outputs]).to(device) num_correct += (predictions == labels).sum() num_samples += predictions.size(0) # Obtenemos el error loss = loss_fn(outputs, labels) ent_loss_list.append(loss.item()) # Back-propagation y entrenamiento optimizer.zero_grad() loss.backward() optimizer.step() # Tick de la barra de entrenamiento loss_mean, loss_std = self.__acumAndGetMeanLoss(loss.item()) train_bar.desc = "Trainig: loss= " + str( round(loss_mean, 4)) + " std_dev= " + str( round(loss_std, 2)) + " " train_bar.update() # Guardamos las metricas de la epoca history["loss"].append(np.mean(ent_loss_list)) history["accuracy"].append(float(num_correct) / float(num_samples)) # Comprobamos si hay NaN o Inf en las metricas if isnan(history["loss"][-1]) or isinf(history["loss"][-1]): # Guardamos las metricas y paramos de entrenar, pues seria inutil continuar history["val_loss"].append(float("NaN")) history["val_accuracy"].append(float("NaN")) self.history = history bar_manager.remove(train_bar) self.nan_or_inf = True # Guardamos las stats de NaN self.net_train_loss = float("NaN") self.net_train_accuracy = float("NaN") self.net_val_loss = float("NaN") self.net_val_accuracy = float("NaN") sendMSG("La red contiene NaN", is_warning=True) break # Borramos la barra de entrenamiento bar_manager.remove(train_bar) self.__resetAcumLoss() # Tick de la barra de epocas prefix_epochs_bar = "Epochs: val_acc= " + str( self.__checkAccuracy(validation_loader, model, history, loss_fn)) + "% " epochs_bar.desc = prefix_epochs_bar epochs_bar.update() # Early stop. Guardamos la mejor epoca hasta ahora # Si esta epoca es la mejor: test_loss = history["val_loss"][-1] test_acc = history["val_accuracy"][-1] if test_loss < self.best_test_loss: # Guardamos su modelo temporalmente self.current_best_model = deepcopy(model) # Guardamos sus metricas self.net_train_loss = history["loss"][-1] self.net_train_accuracy = history["accuracy"][-1] self.net_val_loss = test_loss self.net_val_accuracy = test_acc # Actualizamos el mejor loss self.best_test_loss = test_loss # Mostramos las metricas colors = ["#ff6163", "#ff964f", "#20c073", "#b1ff65"] print("e " + str(epoch) + ":\t ", end="") for i, key in enumerate(history): print(str(key) + ": " + fg(colors[i]) + str(round(history[key][epoch], 4)) + self.B + " ", end="") print() # Guardamos el historial de metricas self.history = history # Destruimos las barras bar_manager.remove(epochs_bar) # Reestablecemos el modelo al modelo de la mejor epoca self.model = self.current_best_model