def activate_model(model_name=None, debug=0): """ Active le modèle choisi en l'installant depuis le model store vers grobid Pour l'instant n'est jamais utilisé dans les scénarios ligne de commande mais peut-être très utile en usages avancés """ model_object = CRFModel(model_type, existing_mid=model_name) # crée le symlink + enregistre les changements # de paramètres dans le store (sous 'last') ET # chez grobid (dans config/grobid.properties) model_object.push_to_gb(debug_lvl=debug)
def eval_model(model_names=[], eval_set=None, save_tab=True, do_graphs=False, debug = 0): """ Stats et eval proprement dites 1 - balisage initial d'un sample GOLD 2 - lancement indirect de eval_xml_refbibs.pl (si pas de model_names, on évalue le dernier modèle) commande équivalente: eval_xml_refbibs.pl -x evaluations/temp.output_bibs.dir/ -r corpora/EVAL_CORPUS/data/C-goldxmltei/ """ # (0) trouver le script d'évaluation dès avant le balisage which_eval_script = CONF['eval']['SCRIPT_PATH'] # si usage de la variable spéciale relative au fichier bako.py if search("<BAKO_INSTALL_DIR>", which_eval_script): bako_script_dir = path.dirname(path.realpath(__file__)) which_eval_script = sub("<BAKO_INSTALL_DIR>",bako_script_dir, which_eval_script) # si le script n'est pas là ? if not path.exists(which_eval_script): print("EVAL_MODEL: warning => can't find evaluation script in configured path %s" % which_eval_script) # on tente ../eval/eval_xml_refbibs.pl stack_default_path = path.join(path.abspath(__file__),"..","bib-eval","eval_xml_refbibs.pl") if path.exists(stack_default_path): print("EVAL_MODEL: warning => using refbibs-stack default path %s for evaluation script" % stack_default_path) which_eval_script = stack_default_path else: print("EVAL_MODEL: please set correct path to eval_xml_refbibs.pl in config file ('%s')" % CONF_PATH) exit(1) # (1) récupération du corpus --------------------------- if eval_set is None: eval_set = CONF['eval']['CORPUS_NAME'] eval_corpus = take_set(eval_set) # (2) préparer eval_id et activer le ou les modèles ---- # suivi local changed_models = { 'bibzone':None, 'biblines':None, 'bibfields':None, 'authornames':None } # cf. anciennement dans CoLTrAnE/eval # ${CORPUS_SHORTNAME}-${GB_NAME}_avec_${MY_NEW_SAMP} mon_eval_id = "" # cas où l'on évalue les modèles courants # => aucune substitution entre le store et les modèles actifs if not len(model_names): # use case courant: une eval vanilla qui est fréquente # pour "calibrer" les attentes print('/!\\ EVALUATING CURRENT MODELS /!\\', file=stderr) # juste modèles courants (= vanilla) mon_eval_id = eval_corpus.name+'-BASELINE-'+GB_VERSION+'_avec_vanillas' # cas avec un ou des modèle(s) donné(s) else: all_models_str = "-".join(model_names) mon_eval_id = eval_corpus.name+'--'+GB_VERSION+'_avec_'+all_models_str for model_name in model_names: # £TODO à remplacer avec un changement dans l'init de CRFModel() model_type = search(r'^([^-]+)-', model_name).groups()[0] model_object = CRFModel(model_type, existing_mid=model_name) model_object.push_to_gb(debug_lvl=debug) # suivi changed_models[model_object.mtype] = True # (3) lancer balisage ----------------------------------------------- evals_dir = path.join(CONF['workshop']['HOME'], CONF['workshop']['EVALS_HOME']) # pour l'instant les refbibs résultantes sont toujours au même endroit newbibs_path = path.join(evals_dir,"temp.output_bibs.dir") if not path.isdir(newbibs_path): makedirs(newbibs_path) # £TODO corriger bug grobid sur les xml:id ou reprendre bib-get jarfile = 'grobid-core-'+GB_RAW_VERSION+'.one-jar.jar' print ('vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv', file = stderr) print ('--- Balisage en cours sur %s ---' % eval_corpus.name , file = stderr) baliseur = call( ['java', '-Xmx1024m', '-jar', path.join(CONF['grobid']['GROBID_DIR'], 'grobid-core','target', jarfile), '-gH', path.join(CONF['grobid']['GROBID_DIR'],'grobid-home'), '-gP', path.join(CONF['grobid']['GROBID_DIR'],'grobid-home','config','grobid.properties'), '-exe', 'processReferences', '-dIn',eval_corpus.shelf_path('PDF0'), '-dOut',newbibs_path ] ) print ('--- Balisage terminé (=>dossier %s)---' % newbibs_path, file = stderr) print ('^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^', file = stderr) # (4) évaluer # NB si table existe >> append résultats report_table = CONF['eval']['TABLE_PATH'] # resultat_eval sera rempli par une grande table pour # chaque paire (bib gold - bib évaluée) de chaque doc resultat_eval = bytes() # >>> appel basique perl <<< eval_call_elts = ['perl', which_eval_script, '-x', newbibs_path, '-g', eval_corpus.shelf_path('GTEI'), '-e', 'references.tei.xml'] # option debug if debug > 0: eval_call_elts += ["-d"] # option save tab if save_tab: # initialisation si nécessaire... if not path.exists(report_table): evals_tab = open(report_table, "w") print("NDOCS\tnbibs_gold\tRappel\tPrécision\t match_tit\tmatch_vol\tmatch_au+date\tmatchs_TOTAL\tEVAL_ID", file=evals_tab) evals_tab.close() # ...et passage aux arguments du script perl eval_call_elts += ['--logreport',report_table,'--regreport', mon_eval_id] if debug > 1: print("APPEL eval:", eval_call_elts) # ---------- run eval ----------------------- resultat_eval = check_output(eval_call_elts) # STDOUT: TSV en str depuis bytes resultat_eval = resultat_eval.decode("UTF-8") # (5) stocker this_eval_dir = path.join(evals_dir,mon_eval_id) if not path.isdir(this_eval_dir): makedirs(this_eval_dir) output = open(path.join(this_eval_dir, 'tableau_detail_eval.tab'), 'w') output.write(resultat_eval) output.close() # (6) remettre les modèles comme avant (si nécessaire) if len(model_names): print("EVAL_MODEL: restauration des modèles précédents") for model_type in changed_models: if changed_models[model_type]: gb_vanilla_restore(model_type)
def run_training(model_type, corpora, debug=0): """ Entraînement proprement dit /!\ Ici un seul model_type, plusieurs corpus potentiels /!\ (appel de grobid-trainer) - appel système - commande shell équivalente mvn generate-resources -P train_<model_type> Chaîne d'invocation réelle: bako => shell => maven => grobid-trainer => wapiti /!\ La commande shell ne renvoit pas le modèle mais va aller l'écrire directement dans grobid-home/models Quant à nous, on le récupère a posteriori pour le ranger. """ # cas vanilla: on entraîne sur les dataset existants if corpora is None: # use case rare (ex: pour comparer avec repository) # (contrairement à une eval vanilla qui est fréquente) print("/!\\ RE-TRAINING VANILLA MODEL /!\\", file=stderr) # juste modèle new_model = CRFModel(model_type,debug_lvl=debug) # cas normal avec liste de corpus à reprendre else: corpora_objs = [] # (1) vérif existence for c_name in corpora: try: corpora_objs.append(TrainingCorpus(c_name)) except FileNotFoundError as e: print("ERR: Le corpus '%s' n'existe pas." % e.corpus_name,file=stderr) exit(1) # (2) vérif étagère(s) requise(s) for c_obj in corpora_objs: for tgtdir in PREP_DATASET[model_type]: needed_sh = PREP_DATASET[model_type][tgtdir] if not c_obj.shelfs[needed_sh]: print("ERR: Le corpus '%s' n'a pas d'étagère %s pour %s" % (c_obj.name,needed_sh,model_type) ,file=stderr) exit(1) # (3) vérif doublons # dict de vérification local dedup_check = dict() for cobj in corpora_objs: # liste rattachée par objet cobj.temp_ignore = defaultdict(lambda: False) for filename in cobj.bnames: if filename not in dedup_check: # le premier arrivé à gagné dedup_check[filename] = cobj.name else: print("DOUBLON entre %s et %s: %s" % ( dedup_check[filename], cobj.name, filename ) ) # stockage temporaire cobj.temp_ignore[filename] = True # --- initialisation modele ----------------------------- new_model = CRFModel( model_type, # NB ce sont juste les noms mais à présent vérifiés the_samples=corpora, debug_lvl=debug ) # !! symlinks de substitution dossiers !! _prepare_dirs(new_model, corpora_objs, debug_lvl=debug) # 2) train_params = _call_grobid_trainer() # lancement grobid-trainer print("training new model %s" % new_model.mid) # ==================================================# # E N T R A I N E M E N T G R O B I D C R F # # ==================================================# (mvnlog, crflog) = new_model.call_grobid_trainer() # # ==================================================# # vérification simple # si le CRF n'a pas été lancé c'est que le maven a planté if not len(crflog.lines): print("!!!--------- ERREUR GROBID-TRAINER ---------!!!", file=stderr) print("\n".join(mvnlog.lines), file=stderr) exit(1) # cas normal ------------------------------------------------------ else: new_model.ran = True # 3) pick_n_store : récupération du modèle stored_location = new_model.pick_n_store(logs = [mvnlog, crflog]) print("new model %s stored into dir %s" % (new_model.mid, stored_location), file=stderr) # nouveau scénario prudent pour tout utilisateur: # on réactive chaque fois les vanilla ensuite # 4) restauration a posteriori du modèle vanilla restored_mid = gb_vanilla_restore(model_type) print("new model %s deactivated in grobid (restored previous: %s)" % (new_model.mid, restored_mid))