mercredi 25 mai 2011

Construire des modélisations du French Treebank pour le UIMA HMM Tagger

Mise à jour le 1 juin. Précision sur le traitement des mots composés du French Treebank

Ce post décrit la procédure que j'ai mise en place pour construire des modélisations de type HMM (Hidden Markov Model) utilisées par le Tagger de la UIMA sandbox à partir d'un corpus XML qui porte des annotations sur des tokens mots, à savoir le corpus French Treebank.

Ci-dessous je présente 
  • les données d'entraînement utilisées
  • la procédure d'entraînement et sa mise en oeuvre
  • les composants requis
  • le paramétrage des composants 
  • le contenu d'un projet Eclipse autonome que je distribue et qui illustre la phase d'entraînement de modélisations et la phase d'étiquetage à partir de modélisations construites.
  • les opérations à réaliser au sein du projet Eclipse pour entraîner une modélisation ou étiqueter des textes à partir d'une modélisation existante
  • des problèmes qu'il reste à rêgler pour améliorer les modélisations
  • une FAQ
Le projet Eclipse est téléchargeable ici. Il s'agit de l'importer dans Eclipse. La donnée d'entraînement n'est pas distribuée (consulter la page dédiée au corpus pour cela, seul un exemple que j'ai construit est distribué). Les modélisations construites à partir du corpus sont présentes et sont distribuées sous licence Apache v2. Toutes les dépendances requises à l'exécution sont présentes.

Corpus d'entraînement : le French Treebank (training data set)
J'ai utilisé une version UTF-8 de Juillet 2010 du corpus French Treebank. Ce corpus a été construit à l'Université de Paris 7. Consulter Abeille et al, 2003, Building a treebank for French, in Treebanks, Kluwer pour plus de détails. Contacter A. Abeille pour obtenir une version de ce corpus.

L'information annotée dans ce corpus permet de construire (entre autres) des modélisations pour l'analyse morphosyntaxique de token mots telles que de
  • l'étiquetage grammatical (part of speech (pos) tagging), 
  • de la morphologie flexionnelle (inflection analysis (mph)), 
  • de la sous-catégorisation grammaticale (subcategorization analysis (subcat)
  • et de la lemmatisation (lemmatization (lemma)).
Je précise que la procédure décrite ici est indépendante du format XML de la donnée d'entraînement dans la mesure où la seule contrainte soit que l'annotation à apprendre doit être décrite à l'aide d'un balisage en ligne XML (c'est-à-dire couvrant la zone de texte annotée). Le composant d'importation (uima-connectors) que j'utilise me permet cela.

Procédure de construction de modélisation (training process)
La procédure de construction de modélisation est la suivante
  1. importation des informations portées par les éléments et attributs XML en annotations génériques au sein d'un CAS représentant le document.
  2. entraînement d'une modélisation HMM à partir de ces annotations
La mise en oeuvre de la procédure
  • utilise un composant générique pour l'importation des informations XML -les informations sont importées sous la forme d'annotations génériques- et implique l'utilisation d'un composant assurant la transformation des annotations génériques en annotations à même d'être prise en compte par le composant suivant d'apprentissage.
  • utilise les paramètres des différents composants pour spécifier 
    • les vues sur lesquelles travailler : la vue dans laquelle est chargée le document XML et celle où se trouve seulement le contenu textuel avec les annotations importées
    • les featurePath qui pointent le trait de l'annotation dont il faut considérer la valeur pour l'apprentissage
Composants utilisés (components)
En pratique j'ai utilisé trois Analysis Engines (AE) appartenant à trois projets distincts pour la phase de construction 
  • le premier, XML2CAS de uima-connectors, permet de parcourir des documents XML et de transformer les éléments et attributs XML en annotations des zones de texte couvertes.
  • le second, annotationMapper de uima-type-mapper, permet de sélectionner et transformer les annotations produites par le uima-connectors en annotations que prendra en entrée le dernier composant d'entraînement (ce projet est aussi appelé uima-annotation-mapper)
  • le troisième, hmmModelTrainer de uima-tagger de la sandbox Apache UIMA, permet d'entraîner une modélisation.
Et j'ai utilisé deux AE distincts pour la phase d'étiquetage
  • le premier, whitespaceTokenizer de whitespace tokenizer, permet de découper un texte en phrases et mots.
  • le second, tagger de uima-tagger de la sandbox Apache UIMA, permet d'étiqueter un texte à l'aide d'une modélisation.
A propos de l'Apache UIMA Sandbox HMM Tagger
  • J'ai utilisé la version présente dans UIMA Annotator Addons 2.3.1 qui corrige une anomalie https://issues.apache.org/jira/browse/UIMA-2106 (rapport d'anomalie + correctif). Cette version qui applique le correctif n'est pas encore distribuée à l'heure de l'écriture de ce message, mais se trouve présente dans le répertoire subversion du Tagger dès la version 1088626. Une version compilée avec les sources est fournie.
  • La partie apprentissage portée par l'AE hmmModelTrainer permet de spécifier le trait de l'annotation (featurePath) à prendre en compte pour l'entraînement. Néanmoins celui-ci ne permet pas de spécifier des contraintes notamment sur la valeur d'autres traits présents dans l'annotation dont on a défini le featurePath. Or ici nous en avons besoin pour sélectionner seulement certaines des annotations produites par le XML2CAS
  • La partie étiquetage portée par l'AE tagger ne permet pas à l'heure actuelle de spécifier le trait à annoter. En l'état, quelle que soit la modélisation, le Tagger affecte la valeur prédite au featurePath suivant org.apache.uima.TokenAnnotation:posTag. Ce n'est pas très embêtant si l'on sait ce que l'on fait. Le patch https://issues.apache.org/jira/browse/UIMA-2110  soumis à Apache vise à rendre plus générique le Tagger et résoudre notamment cette limite. Entre autre il permet de spécifier sous forme d'un featurePath le trait de l'annotation auquel il faut donner la valeur prédite par la modélisation. Ce patch n'a pas encore accepté par Apache.
Paramétrage des composants utilisés (parameter settings)

L'AE XML2CASAE 
  • produit des annotations XMLElementAnnotation et XMLAttributeAnnotation pour chaque élément XML rencontré. 
    • Les traits de XMLElementAnnotation permettent de connaître le nom de l'élément XML et les noms et les valeurs de ses attributs. Deux structures de données sont disponibles pour cela, l'une d'elle est un tableau de référence vers des annotations XMLAttributeAnnotation correspondant à chacun de leurs attributs. Les XMLAttributeAnnotation correspondent à une annotation pour chaque attribut. Elles déclarent le nom de l'élément XML qu'elles caractérisent ainsi que le nom et la valeur de l'attribut.
  •  prend les paramètres suivants 
    • nom de la vue à créer avec seulement le contenu textuel du document XML (PlainTextOutputView). La vue où se trouve le document textuel peut aussi être spécifiée si elle est différente de celle par défaut. Ici PlainTextDocument
    • nom des éléments XML à transformer en annotations dans le CAS  (XmlTagsToTurnIntoAnnotation). Ici w, qui correspond à la balise du French Treebank pour mot.
L'AE annotationMapper 
  • prend en paramètre un fichier de règles qui assurent la transformation d'une annotation en une autre (RulesFile). 
  • Globalement ici la règle permet d'une part de sélectionner les annotations XMLAttributeAnnotation qui correspondent à des attributs de mots (balises w) et qui ont un attribut non nul dont on désire utiliser la valeur comme base d'apprentissage (cat, subcat, lemma, mph, ee, ...), et d'autre part de créer pour chacune de ces annotations une annotation manipulable par le composant d'apprentissage avec un trait initialisé à la valeur à apprendre.
  • Ici la règle crée des org.apache.uima.TokenAnnotation et instancie la valeur du trait posTag. On pourrait pour chaque caractéristique apprise changer le trait à considérer. Ce n'est pas très pertinent pour notre construction. Un même trait peut acceillir tour à tour les valeurs du corpus pour chaque entraînement.
  • A noter qu'il est possible de spécifier avec le hmmModelTrainer le featurePath à considérer comme base d'entraînement. Néanmoins celui-ci ne permet pas de spécifier des contraintes notamment sur la valeur d'autres traits présents dans l'annotation dont on a défini le featurePath. Or ici nous en avons besoin pour sélectionner un sous ensemble des XMLAttributeAnnotation parmi celles produites par le XML2CAS. C'est cette situation qui justifie notamment l'utilisation de l'annotationMapper.
L'AE  hmmModelTrainer 
  • prend en paramètre 
    • le  featurePath qui pointe le trait de l'annotation dont il faut considérer la valeur pour l'apprentissage (FeaturePathPOS)
    • le nom et chemin du fichier de modélisation à créer (ModelExportFile)
L'AE  tagger 
  • prend en paramètre 
    • le  featurePath qui pointe le trait de l'annotation qu'il faut instancier avec la valeur prédite par la modélisation (TokenFeaturePath)
    • le nom et chemin du fichier de modélisation à utiliser (ModelFile)
  • Le descripteur qui met en oeuvre cet AE l'utilise plusieurs fois consécutivement avec des jeux de valeurs différentes pour appliquer les différents modélisations. 
  • Nous avons étendu le type org.apache.uima.TokenAnnotation à cet effet. Consulter le fichier desc/FrenchTreebankTS.xml
Contenu du projet Eclipse (Eclipse project description)
Le projet Eclipse est globalement un projet java ayant la UIMA Nature et ses sous répertoires desc et resources  déclarés comme appartenant au build path. Le post suivant décrit comment créer un projet Eclipse en rajoutant dans le build path les dépendances minimales UIMA requises pour exécuter une chaîne de traitement UIMA.
  • Le répertoire lib contient toutes les dépendances requises, celles de uima, celles des AE de notre chaîne (uima-common, uima-connectors, jxpath et uima-type-mapper) avec notamment le whitespace tokenizer(uima-an-wst) de la UIMA Sandbox et la version patchée du HMMTagger (uima-an-tagger). Ces dépendances ont été déclarées dans le .classpath. Elles seront accessibles lors de l'import du projet.
  • Le répertoire data/input contient un sous répertoire FrenchTreebank avec un fichier exemple qui reprend la structure XML d'un fichier du corpus original. Ce fichier a en fait été construit a posteriori à partir d'analyses produites. Il peut dans le cas présent servir de base d'exemple de la chaîne d'entraînement. Le répertoire contient aussi un sous répertoire text-fr avec des textes en français qui peuvent servir pour tester l'étiquetage à partir des modélisations construites.
  • Le répertoire data/output accueille les résultats d'exécution des chaînes de traitement, aussi bien les xmi (xmi) que les modélisations (models).
  • Le répertoire resources/models contient les modélisations construites sur le corpus FrenchTreebank (les jeux d'étiquettes (ou tagset) sont décrits ici)
    • FrenchTreebankPosUimaHmmTaggerModel.dat: part of speech (pos) tagging ('cat' attribute in the French Treebank)
    • FrenchTreebankMphUimaHmmTaggerModel.dat: inflection analysis
    • FrenchTreebankSubcatUimaHmmTaggerModel.dat: subcategorization analysis
    • FrenchTreebankEeUimaHmmTaggerModel.dat: combination of part of speech (pos) tagging, subcategorization analysis and inflection analysis
    • FrenchTreebankLemmaUimaHmmTaggerModel.dat: lemmatization 
  • Le répertoire resources contient aussi un fichier de règle pour la transformation d'annotations en autres. Cela permet de faire le pont entre le composant d'importation et le HMMTrainer. Son nom ici est XML2CAS-to-HMMTagger_annotationMapperRules.xml
  • Le répertoire desc contient 
    • le descripteur de la chaîne utile pour la construction des modélisations à savoir XML2CAS-annotationMapper-HMMTrainModel-FrenchTreeBank-AAE.xml 
    • un descripteurs de chaîne pour l'étiquetage à partir d'une modélisation à savoir wst-FrenchTreebank-HmmTagger-AAE.xml. Celle disponible par défaut dans l'addon convient très bien mais requiert quelques manipulations pour spécifier le bon fichier de modélisation et étiquetera toujours le featurePath org.apache.uima.TokenAnnotation:posTag
    • un descripteur qui sert pour déclarer l'importation d'un Type System étendant le type TokenAnnotation avec de nouveaux attributs susceptibles d'accueillir le résultat d'étiquetage de différentes modélisations (morphologie, lemmatisation, ...) à savoir FrenchTreebankAE.xml qui importe FrenchTreebankTS.xml.
Réaliser la construction d'une modélisation (running the training process)
Le post suivant explique comment exécuter une chaîne de traitement UIMA.

Pour réaliser la construction d'une modélisation, utiliser le descripteur desc/XML2CAS-annotationMapper-HMMTrainModel-FrenchTreeBank-AAE.xml qui constitue un aggregate d'AE présentés ci-dessus en pipeline.
  1. Placer votre corpus sous la forme d'un seul fichier dans le répertoire data/input/FrenchTreebank. Un fichier exemple est fourni. Une manipulation est décrite ci-dessous pour produire un seul fichier à partir des différents fichiers du French Treebank.
  2. Spécifier dans le fichier de règles de l'annotationMapper le nom de l'attribut XML du corpus French Treebank sur lequel vous souhaitez réaliser l'apprentissage (cat, subcat, lemma, mph, ee, ...)
  3. Spécifier le nom du fichier de modélisation à produire dans le paramètre du descripteur 
  4. Lancer le documentAnalyzer (par exemple) pour exécuter la chaîne en spécifiant surtout l'input
Réaliser l'étiquetage à partir d'une modélisation (running the tagging process)
Pour cela utiliser le descripteur desc/wst-FrenchTreebank-HmmTagger-AAE.xml
  1. Les données traitées doivent être des fichiers textes
  2. Spécifier le fichier de modélisation dans le paramètre du descripteur
  3. Spécifier le featurePath de l'annotation à créer avec la valeur prédite par la modélisation
  4. Lancer le documentAnalyzer (par exemple) pour exécuter la chaîne 
Limites actuelles des modélisations
  • Le corpus compte des mots simples et des mots composés, tout deux balisés avec le même élément. Les mots composés imbriquent des mots simples. Ceux-ci n'ont pas avec les mêmes traits que leurs homologues non imbriqués. La construction de ces modélisations a considéré les mots composés mais non les mots simples imbriqués. 
Les mots composés sont de la forme suivante
<w cat="D" ee="D-def-fp" ei="Dfp" lemma="le" mph="fp" subcat="def"></w> <w cat="N" ee="N-C-fp" ei="NCfp" lemma="banque centrale" mph="fp" subcat="C"> <w catint="N">banques</w> <w catint="A">centrales</w> </w>
ou bien 
<w cat="ADV" ee="ADV" ei="ADV" lemma="à tout prix"> <w catint="P">à</w> <w catint="D">tout</w> <w catint="N">prix</w> </w>
La règle de sélection utilisée par l'annotation mapper met des contraintes sur la présence de certains traits. Pour rappel, la contrainte est 
<Contrainte>.[@elementName='w' and @attributeName='cat' and @attributeValue!=""]</Contrainte>
En conséquence, les mots simples composants les mots composés ne sont pas considérés.
    A l'inverse, si l'on ne souhaite pas considérer les mots composés mais les mots simples on peut écrire une contrainte comme celle-ci (on filtre sur la présence d'un caractère blanc)
    <Contrainte>.[@elementName='w' and not(contains(@coveredText,' '))]</Contrainte>
      Mais là effectivement nous n'avons plus accès aux traits du mots composés. Cela ne pose pas de problème pour de l'entrainement de découpeur en mots ou en phrases.
        L'apprentissage d'un étiqueteur morphosyntaxique sur des mots composés ne semble pas non plus poser problème.
          Si vraiment on voulait ne pas considérer les mots simples, on pourrait imaginer une contrainte avec alternative qui exclurait les mots composés et considèrerait les traits des mots simples mais cela ne concernerait pas tous les traits (ici seulement les étiquettes grammaticales : cat et catint).
          • Le processus de lemmatisation via l'algorithme utilisé présente des abérations lorsqu'il ne connaît pas le mot à lemmatiser. En effet, il va lui affecter le lemme d'un mot qu'il connaît et avec lequel il partage le plus grand suffixe commun.
          • ...
          Un seul "gros" fichier d'entraînement
          Le corpus French Treebank est un ensemble de fichiers XML. Utilisant un AE et non un Collection Reader (CR) de uima-connector, il me fallait un seul fichier XML contenant toute la collection. Une petite ligne de shell me résoud le problème
          echo '<?xml version="1.0" encoding="UTF-8"?>' > frenchTreebank.xml ; echo "<ftb>" >> frenchTreebank.xml ; for f in `ls lmf*.xml`; do echo $f; export HEAD=`head -1 $f`; if [ "$HEAD" == '<?xml version="1.0" encoding="UTF-8"?><text>' ]; then echo "<text>" >> frenchTreebank.xml; fi;  cat $f |grep -v "xml version" >> frenchTreebank.xml; done ; echo "</ftb>" >> frenchTreebank.xml 
          Environnement d'exécution
          J'ai réalisé mes traitements sur un système linux via Eclipse.
          J'ai eu à augmenter les capacités de la machine virtuelle Java lors de l'exécution de la chaîne de traitement. Via Eclipse, j'ai rajouté la valeur -Xmx2048m dans le menu Run Configurations > Arguments > VM Arguments.
          La machine que j'utilisais offre 16 Go de RAM et un processeur Intel Xeon W3565 @ 3.20GHz.

          Implémentation de l'algorithme Viterbi du HMM Tagger 
          L'implémentation actuelle (src/main/java/org/apache/uima/examples/tagger/Viterbi.java) fonctionne grosso modo de la sorte (il y a ici d'autres détails techniques cachés) :
          Pour chaque mot phrase d'une phrase on cherche à lui attribuer une probabilité d'étiquette pour cela : 
          on regarde si on connaît la probabilité du mot ou de sa forme en minuscule sinon on cherche le suffixe le plus long en commun avec un mot connu sinon on lui attribue la probabilité d'un mot prédéfini.