def do_feature_extraction(db, param, log, overwrite=False): """Feature extraction stage Parameters ---------- db : dcase_util.dataset.Dataset Dataset param : dcase_util.containers.DCASEAppParameterContainer Application parameters log : dcase_util.ui.FancyLogger Logging interface overwrite : bool Default value False Returns ------- nothing """ # Define processing chain (Multichannel audio reading + feature extraction for each channel) feature_processing_chain = get_processing_chain(param, chain_type='feature_processing_chain') # Loop over all audio files in the current dataset and extract acoustic features for each of them. for audio_filename in db.audio_files: # Get filename for feature data from audio filename feature_filename = dcase_util.utils.Path( path=audio_filename ).modify( path_base=param.get_path('path.application.feature_extractor'), filename_extension='.cpickle' ) if not os.path.isfile(feature_filename) or overwrite: log.line( data=os.path.split(audio_filename)[1], indent=2 ) # Extract features and store them into FeatureContainer, and save it to the disk feature_processing_chain.process(filename=audio_filename).save(filename=feature_filename)
def do_testing(db, folds, param, log, overwrite=False): """Testing stage Parameters ---------- db : dcase_util.dataset.Dataset Dataset folds : list of int List of active folds param : dcase_util.containers.DCASEAppParameterContainer Application parameters log : dcase_util.ui.FancyLogger Logging interface overwrite : bool Default value False Returns ------- nothing """ # Loop over all cross-validation folds and test for fold in folds: log.line( data='Fold [{fold}]'.format(fold=fold), indent=2 ) # Setup keras, run only once dcase_util.keras.setup_keras( seed=param.get_path('learner.parameters.random_seed'), profile=param.get_path('learner.parameters.keras_profile'), backend=param.get_path('learner.parameters.backend') ) import keras # Get results filename fold_results_filename = os.path.join( param.get_path('path.application.recognizer'), 'res_fold_{fold}.txt'.format(fold=fold) ) # check if results already processed if not os.path.isfile(fold_results_filename) or overwrite: # -- prepare learner -- # # Get model filename fold_model_filename = os.path.join( param.get_path('path.application.learner'), 'model_fold_{fold}.h5'.format(fold=fold) ) # load model keras_model = keras.models.load_model(fold_model_filename) # -- prepare data -- # # Get normalization factor filename fold_stats_filename = os.path.join( param.get_path('path.application.feature_normalizer'), 'norm_fold_{fold}.cpickle'.format(fold=fold) ) # Create processing chain for features data_processing_chain = get_processing_chain(param, fold_stats_filename=fold_stats_filename, chain_type='data_processing_chain') # Get label encoder label2num_enc = LabelEncoder() scene_labels_num = label2num_enc.fit_transform(db.scene_labels()) # Initialize results container res = dcase_util.containers.MetaDataContainer( filename=fold_results_filename ) # Loop through all test files from the current cross-validation fold for item in db.test(fold=fold): # Get feature filename feature_filename = dcase_util.utils.Path( path=item.filename ).modify( path_base=param.get_path('path.application.feature_extractor'), filename_extension='.cpickle' ) # do processing chain features = data_processing_chain.process(filename=feature_filename) # Get network output posteriors_all = keras_model.predict(x=features.data) # combine estimates/posteriors from different channels in a particular sensor node if param.get_path('recognizer.fusion.method') == 'mean': # mean rule posteriors = numpy.mean(posteriors_all, axis=0) elif param.get_path('recognizer.fusion.method') == 'none': # none (if channels are 'fed directly to/combined before the' classifier) posteriors = posteriors_all else: raise ValueError("Fusion not supported") estimated_scene_label = label2num_enc.inverse_transform(numpy.argmax(posteriors, axis=0)) # Store result into results container res.append( { 'filename': item.filename, 'scene_label': estimated_scene_label } ) # Save results container res.save()
def do_learning(db, folds, param, log, overwrite=False): """Learning stage Parameters ---------- db : dcase_util.dataset.Dataset Dataset folds : list of int List of active folds param : dcase_util.containers.DCASEAppParameterContainer Application parameters log : dcase_util.ui.FancyLogger Logging interface overwrite : bool Default value False Returns ------- nothing """ # Loop over all cross-validation folds and learn acoustic models for fold in folds: log.line(data='Fold [{fold}]'.format(fold=fold), indent=2) # Get model filename fold_model_filename = os.path.join( param.get_path('path.application.learner'), 'model_fold_{fold}.h5'.format(fold=fold) ) if not os.path.isfile(fold_model_filename) or overwrite: # -- prepare learner -- # # Setup keras, run only once dcase_util.keras.setup_keras( seed=param.get_path('learner.parameters.random_seed'), profile=param.get_path('learner.parameters.keras_profile'), backend=param.get_path('learner.parameters.backend') ) import keras # Create model keras_model = dcase_util.keras.create_sequential_model( model_parameter_list=param.get_path('learner.parameters.model.config'), constants=param.get_path('learner.parameters.model.constants') ) # Show model topology log.line( dcase_util.keras.model_summary_string(keras_model) ) # Create optimizer object param.set_path( path='learner.parameters.compile.optimizer', new_value=dcase_util.keras.create_optimizer( class_name=param.get_path('learner.parameters.optimizer.class_name'), config=param.get_path('learner.parameters.optimizer.config') ) ) # Compile model keras_model.compile(**param.get_path('learner.parameters.compile')) # -- data related -- # # Get validation files validationsplit_fold_filename = os.path.join(param.get_path('path.application.learner'),'validationsplit_fold_{fold}.pickle'.format(fold=fold)) if not os.path.isfile(validationsplit_fold_filename): training_files, validation_files = db.validation_split( fold=fold, split_type='balanced', validation_amount=param.get_path('learner.parameters.validation_amount'), verbose=True ) with open(validationsplit_fold_filename, 'wb') as f: pickle.dump([training_files,validation_files], f) else: with open(validationsplit_fold_filename, "rb") as f: [training_files,validation_files] = pickle.load(f) # load # get matching labels training_files, training_labels, validation_files, val_labels = get_label_from_filename(db.train(fold=fold), training_files, validation_files, param) # Get label encoder label2num_enc = LabelEncoder() scene_labels_num = label2num_enc.fit_transform(db.scene_labels()) # convert labels to numeric format training_labels_num = label2num_enc.transform(training_labels) val_labels_num = label2num_enc.transform(val_labels) # get amount of batches for training and validation if param.get_path('learner.parameters.fit.undersampling'): class_weight = skutils.compute_class_weight('balanced', numpy.unique(training_labels_num),training_labels_num) # get class weights train_batches = (sum(training_labels_num == numpy.argmax(class_weight)) * len(numpy.unique(training_labels_num))) // param.get_path('learner.parameters.fit.batch_size') else: train_batches = len(training_files) // param.get_path('learner.parameters.fit.batch_size') # get amount of batches val_batches = int(numpy.ceil(len(validation_files)/param.get_path('learner.parameters.fit.batch_size'))) # get amount of batches # get normalizer filename fold_stats_filename = os.path.join( param.get_path('path.application.feature_normalizer'), 'norm_fold_{fold}.cpickle'.format(fold=fold) ) # Create data processing chain for features data_processing_chain = get_processing_chain(param, fold_stats_filename=fold_stats_filename, chain_type = 'data_processing_chain') # Init data generators from task5_datagenerator import DataGenerator TrainDataGenerator = DataGenerator(training_files, training_labels_num, data_processing_chain=data_processing_chain, batches=train_batches, batch_size=param.get_path('learner.parameters.fit.batch_size'), undersampling=param.get_path('learner.parameters.fit.undersampling'), shuffle=True) ValidationDataGenerator = DataGenerator(validation_files, val_labels_num, data_processing_chain=data_processing_chain, batches=val_batches, batch_size=param.get_path('learner.parameters.fit.batch_size'), undersampling='None', shuffle=False) # -- train/epoch loop -- # prevmodelload = False val_scores = [] epoch_list = [] for epoch_start in range(-1, param.get_path('learner.parameters.fit.epochs')-1,param.get_path('learner.parameters.fit.processing_interval')): # for every epoch # update epoch information epoch_end = epoch_start + param.get_path('learner.parameters.fit.processing_interval') # specifiy epoch range if epoch_end > param.get_path('learner.parameters.fit.epochs'): # Make sure we have only specified amount of epochs epoch_end = param.get_path('learner.parameters.fit.epochs') - 1 model_fold_epoch_filename = os.path.join(param.get_path('path.application.learner'),'model_fold_{fold}_epoch_{epoch:d}.h5'.format(fold=fold,epoch=epoch_end)) val_fold_epoch_filename = os.path.join(param.get_path('path.application.learner'),'val_fold_{fold}_epoch_{epoch:d}.pickle'.format(fold=fold,epoch=epoch_end)) if not (os.path.isfile(model_fold_epoch_filename) & os.path.isfile(val_fold_epoch_filename)): # if model does not exist if prevmodelload: # if epoch already performed before log.line('Loaded model of fold {fold} epoch {epoch_start:d}'.format(fold=fold,epoch_start=epoch_start), indent=2) keras_model = keras.models.load_model(prev_model_fold_epoch_filename) # get model prevmodelload = False # train model keras_model.fit_generator( generator=TrainDataGenerator, initial_epoch=epoch_start, epochs=epoch_end, steps_per_epoch=train_batches, verbose=0 ) # evaluate model on validation set for each mic in each example, output is 4 channels * len(validation_files) long posteriors_all = keras_model.predict_generator( generator=ValidationDataGenerator, steps=val_batches ) # combine estimates/posteriors from different channels in a particular sensor node posteriors = numpy.empty((len(validation_files),len(db.scene_labels()))) for i in range(len(validation_files)): # for each validation file # mean rule if param.get_path('recognizer.fusion.method')=='mean': posteriors[i,:] = numpy.mean(posteriors_all[i*param.get_path('feature_extractor.channels'):(i+1)*param.get_path('feature_extractor.channels'),:],axis=0) # none elif param.get_path('recognizer.fusion.method')=='none': posteriors = posteriors_all else: raise ValueError("Fusion not supported") # get estimated labels val_labels_est_num = numpy.argmax(posteriors, axis=1) # get score F1_score = f1_score(val_labels_num, val_labels_est_num, labels = scene_labels_num, average='macro') log.line('Fold {fold} - Epoch {epoch:d}/{epochs:d} - validation set F1-score: {Fscore:f}'.format(fold=fold,epoch=epoch_end,epochs=param.get_path('learner.parameters.fit.epochs') - 1,Fscore=F1_score),indent=2) # save intermediate results keras_model.save(model_fold_epoch_filename) with open(val_fold_epoch_filename, 'wb') as f: pickle.dump([F1_score], f) else: # if already performed # update model loading and load performance prev model prevmodelload = True prev_model_fold_epoch_filename = model_fold_epoch_filename with open(val_fold_epoch_filename, "rb") as f: [F1_score] = pickle.load(f) # load # append scores val_scores.append(F1_score) epoch_list.append(epoch_end) # get best model epoch_best = epoch_list[numpy.argmax(val_scores)] log.line('Best performing model on epoch {epoch_best:d} with an F1-score of {Fscore:f}%'.format(epoch_best=epoch_best,Fscore=numpy.max(val_scores)*100), indent=2) # load best model model_fold_epoch_filename = os.path.join(param.get_path('path.application.learner'),'model_fold_{fold}_epoch_{epoch:d}.h5'.format(fold=fold,epoch=epoch_best)) keras_model = keras.models.load_model(model_fold_epoch_filename) # save best model keras_model.save(fold_model_filename)