def get_dfs(desed_dataset, nb_files=None, separated_sources=False): log = create_logger(__name__ + "/" + inspect.currentframe().f_code.co_name, terminal_level=cfg.terminal_level) audio_weak_ss = None audio_unlabel_ss = None audio_validation_ss = None audio_synthetic_ss = None if separated_sources: audio_weak_ss = cfg.weak_ss audio_unlabel_ss = cfg.unlabel_ss audio_validation_ss = cfg.validation_ss audio_synthetic_ss = cfg.synthetic_ss weak_df = desed_dataset.initialize_and_get_df(cfg.weak, audio_dir_ss=audio_weak_ss, nb_files=nb_files) unlabel_df = desed_dataset.initialize_and_get_df( cfg.unlabel, audio_dir_ss=audio_unlabel_ss, nb_files=nb_files) # Event if synthetic not used for training, used on validation purpose synthetic_df = desed_dataset.initialize_and_get_df( cfg.synthetic, audio_dir_ss=audio_synthetic_ss, nb_files=nb_files, download=False) log.debug(f"synthetic: {synthetic_df.head()}") validation_df = desed_dataset.initialize_and_get_df( cfg.validation, audio_dir=cfg.audio_validation_dir, audio_dir_ss=audio_validation_ss, nb_files=nb_files) # Divide synthetic in train and valid filenames_train = synthetic_df.filename.drop_duplicates().sample( frac=0.8, random_state=26) train_synth_df = synthetic_df[synthetic_df.filename.isin(filenames_train)] valid_synth_df = synthetic_df.drop( train_synth_df.index).reset_index(drop=True) # Put train_synth in frames so many_hot_encoder can work. # Not doing it for valid, because not using labels (when prediction) and event based metric expect sec. train_synth_df.onset = train_synth_df.onset * cfg.sample_rate // cfg.hop_size // pooling_time_ratio train_synth_df.offset = train_synth_df.offset * cfg.sample_rate // cfg.hop_size // pooling_time_ratio log.debug(valid_synth_df.event_label.value_counts()) # Eval 2018 to report results eval2018 = pd.read_csv(cfg.eval2018, sep="\t") eval_2018_df = validation_df[validation_df.filename.isin( eval2018.filename)] log.debug(f"eval2018 len: {len(eval_2018_df)}") data_dfs = { "weak": weak_df, "unlabel": unlabel_df, "synthetic": synthetic_df, "train_synthetic": train_synth_df, "valid_synthetic": valid_synth_df, "validation": validation_df, "eval2018": eval_2018_df } return data_dfs
def train(train_loader, model, optimizer, c_epoch, ema_model=None, mask_weak=None, mask_strong=None, adjust_lr=False): """ One epoch of a Mean Teacher model Args: train_loader: torch.utils.data.DataLoader, iterator of training batches for an epoch. Should return a tuple: ((teacher input, student input), labels) model: torch.Module, model to be trained, should return a weak and strong prediction optimizer: torch.Module, optimizer used to train the model c_epoch: int, the current epoch of training ema_model: torch.Module, student model, should return a weak and strong prediction mask_weak: slice or list, mask the batch to get only the weak labeled data (used to calculate the loss) mask_strong: slice or list, mask the batch to get only the strong labeled data (used to calcultate the loss) adjust_lr: bool, Whether or not to adjust the learning rate during training (params in config) """ log = create_logger(__name__ + "/" + inspect.currentframe().f_code.co_name, terminal_level=cfg.terminal_level) class_criterion = nn.BCELoss() consistency_criterion = nn.MSELoss() class_criterion, consistency_criterion = to_cuda_if_available( class_criterion, consistency_criterion) meters = AverageMeterSet() log.debug("Nb batches: {}".format(len(train_loader))) start = time.time() for i, ((batch_input, ema_batch_input), target) in enumerate(train_loader): global_step = c_epoch * len(train_loader) + i rampup_value = ramps.exp_rampup(global_step, cfg.n_epoch_rampup * len(train_loader)) if adjust_lr: adjust_learning_rate(optimizer, rampup_value) meters.update('lr', optimizer.param_groups[0]['lr']) batch_input, ema_batch_input, target = to_cuda_if_available( batch_input, ema_batch_input, target) # Outputs strong_pred_ema, weak_pred_ema = ema_model(ema_batch_input) strong_pred_ema = strong_pred_ema.detach() weak_pred_ema = weak_pred_ema.detach() strong_pred, weak_pred = model(batch_input) loss = None # Weak BCE Loss target_weak = target.max(-2)[0] # Take the max in the time axis if mask_weak is not None: weak_class_loss = class_criterion(weak_pred[mask_weak], target_weak[mask_weak]) ema_class_loss = class_criterion(weak_pred_ema[mask_weak], target_weak[mask_weak]) loss = weak_class_loss if i == 0: log.debug( f"target: {target.mean(-2)} \n Target_weak: {target_weak} \n " f"Target weak mask: {target_weak[mask_weak]} \n " f"Target strong mask: {target[mask_strong].sum(-2)}\n" f"weak loss: {weak_class_loss} \t rampup_value: {rampup_value}" f"tensor mean: {batch_input.mean()}") meters.update('weak_class_loss', weak_class_loss.item()) meters.update('Weak EMA loss', ema_class_loss.item()) # Strong BCE loss if mask_strong is not None: strong_class_loss = class_criterion(strong_pred[mask_strong], target[mask_strong]) meters.update('Strong loss', strong_class_loss.item()) strong_ema_class_loss = class_criterion( strong_pred_ema[mask_strong], target[mask_strong]) meters.update('Strong EMA loss', strong_ema_class_loss.item()) if loss is not None: loss += strong_class_loss else: loss = strong_class_loss # Teacher-student consistency cost if ema_model is not None: consistency_cost = cfg.max_consistency_cost * rampup_value meters.update('Consistency weight', consistency_cost) # Take consistency about strong predictions (all data) consistency_loss_strong = consistency_cost * consistency_criterion( strong_pred, strong_pred_ema) meters.update('Consistency strong', consistency_loss_strong.item()) if loss is not None: loss += consistency_loss_strong else: loss = consistency_loss_strong meters.update('Consistency weight', consistency_cost) # Take consistency about weak predictions (all data) consistency_loss_weak = consistency_cost * consistency_criterion( weak_pred, weak_pred_ema) meters.update('Consistency weak', consistency_loss_weak.item()) if loss is not None: loss += consistency_loss_weak else: loss = consistency_loss_weak assert not (np.isnan(loss.item()) or loss.item() > 1e5), 'Loss explosion: {}'.format( loss.item()) assert not loss.item() < 0, 'Loss problem, cannot be negative' meters.update('Loss', loss.item()) # compute gradient and do optimizer step optimizer.zero_grad() loss.backward() optimizer.step() global_step += 1 if ema_model is not None: update_ema_variables(model, ema_model, 0.999, global_step) epoch_time = time.time() - start log.info(f"Epoch: {c_epoch}\t Time {epoch_time:.2f}\t {meters}") return loss, meters
"weak": weak_df, "unlabel": unlabel_df, "synthetic": synthetic_df, "train_synthetic": train_synth_df, "valid_synthetic": valid_synth_df, "validation": validation_df, } return data_dfs if __name__ == '__main__': torch.manual_seed(2020) np.random.seed(2020) logger = create_logger(__name__ + "/" + inspect.currentframe().f_code.co_name, terminal_level=cfg.terminal_level) logger.info("Baseline 2020") logger.info(f"Starting time: {datetime.datetime.now()}") parser = argparse.ArgumentParser(description="") parser.add_argument( "-s", '--subpart_data', type=int, default=None, dest="subpart_data", help= "Number of files to be used. Useful when testing on small number of files." ) parser.add_argument("-n",
import numpy as np import pandas as pd from data_utils.DataLoad import DataLoadDf from data_utils.Desed import DESED from evaluation_measures import psds_score, get_predictions, \ compute_psds_from_operating_points, compute_metrics from utilities.utils import to_cuda_if_available, generate_tsv_wav_durations, meta_path_to_audio_dir from utilities.ManyHotEncoder import ManyHotEncoder from utilities.Transforms import get_transforms from utilities.Logger import create_logger from utilities.Scaler import Scaler, ScalerPerAudio from models.CRNN import CRNN import config as cfg logger = create_logger(__name__) torch.manual_seed(2020) def _load_crnn(state, model_name="model"): crnn_args = state[model_name]["args"] crnn_kwargs = state[model_name]["kwargs"] crnn = CRNN(*crnn_args, **crnn_kwargs) crnn.load_state_dict(state[model_name]["state_dict"]) crnn.eval() crnn = to_cuda_if_available(crnn) logger.info("Model loaded at epoch: {}".format(state["epoch"])) logger.info(crnn) return crnn
import sed_eval import numpy as np import pandas as pd import torch from psds_eval import plot_psd_roc, PSDSEval import config as cfg from utilities.Logger import create_logger from utilities.utils import to_cuda_if_available from utilities.ManyHotEncoder import ManyHotEncoder from librosa.sequence import viterbi_discriminative, transition_loop logger = create_logger(__name__, terminal_level=cfg.terminal_level) def get_event_list_current_file(df, fname): """ Get list of events for a given filename :param df: pd.DataFrame, the dataframe to search on :param fname: the filename to extract the value from the dataframe :return: list of events (dictionaries) for the given filename """ event_file = df[df["filename"] == fname] if len(event_file) == 1: if pd.isna(event_file["event_label"].iloc[0]): event_list_for_current_file = [{"filename": fname}] else: event_list_for_current_file = event_file.to_dict('records')