• Aucun résultat trouvé

Partie III. Antelope : une plate-forme pour extraire les sens du texte

F. Architecture technique

1.

Environnement de développement .NET

Antelope est développée nativement en C#, un langage objet créé par Microsoft dans le cadre de son architecture .NET. L’ensemble constitué par C#, la bibliothèque de classes et la machine virtuelle45 .NET, est proche de ce qui est proposé par Java. C# est un langage objet moderne, permettant le développement par classes et interfaces, une gestion des erreurs par exceptions, et une désallocation automatique de la mémoire grâce à un ramasse-miettes46. La version la plus récente introduit des éléments de programmation fonctionnelle (λ-expressions).

42 Par exemple, le concept {PEOPLEOFCOLOR} de WordNet nous semble US centric, voire WASP centric. 43 Riz avant cuisson, riz cuit, riz du matin, riz du soir…

44 Neige au sol, neige qui tombe, bourrasque de neige, amoncellement de neige…

45 Une machine virtuelle est un interpréteur de code intermédiaire (appelé Intermediate Language en .NET, un

pseudo assembleur de haut niveau). La machine virtuelle isole l’application en cours d’exécution des spécificités matérielles de l’ordinateur hôte ; l’intérêt de cette approche est d’éviter qu’une erreur applicative ne corrompe la mémoire de l’ordinateur.

46 Le ramasse-miettes (garbage collector en anglais) est un mécanisme de gestion automatique de la mémoire ;

ce mécanisme est transparent pour le développeur, qui se contente de créer des objets, sans les détruire explicitement ; le ramasse-miettes est responsable du recyclage de la mémoire occupée par les objets quand ils ne sont plus utilisés.

28 Antelope fonctionne sous Windows avec .NET, et aussi sous Linux avec MONO47. .NET semble moins utilisé que Java, C/C++, PERL ou Python dans la communauté du TAL. On peut toutefois noter que NooJ ou SharpNLP ont aussi fait ce choix.

2.

Bonnes pratiques issues du génie logiciel

Le développement de grands systèmes d’informations, qui nécessite des milliers de jours d’analyse et de codage sous la pression de délais courts, a forcé à structurer des méthodes de travail. La notion de génie logiciel s’est progressivement imposée dans l’industrie informatique, visant à fournir des « bonnes pratiques » sous forme de méthodes de conception appelées design patterns en anglais (Gamma et al., 1993). Elles sont aujourd’hui adoptées par les organisations ayant besoin de créer des applications de grande taille. Nous présentons ici les bonnes pratiques retenues pour la conception d’Antelope.

a)

Modèle de programmation par interfaces

La programmation orientée objet est un paradigme qui a fait ses preuves. Les langages à objets récents (Java, C#...) ont introduit, en plus de la notion de classe48, une notion explicite d’interface, un regroupement logique de propriétés et de méthodes. Une classe peut implémenter une ou plusieurs interfaces ; une interface peut être implémentée par plusieurs classes. Ce modèle de programmation systématise une séparation formelle entre interface et implémentation, favorisant un couplage faible entre composants, et donc une meilleure réutilisation.

Illustrons cette démarche sur un cas pratique. Par exemple, une opération d’étiquetage morphosyntaxique prend comme paramètre en entrée un texte (déjà découpé sous forme d’une liste de mots) et produit en sortie une liste d’étiquettes (chacune d’entre elles étant associée à un mot). On peut définir une interface ITagger49 de la façon suivante :

List<Etiquette> Tag(List<string> mots);

Plusieurs implémentations sont évidemment possibles ; on peut imaginer coder l’étiquetage morphosyntaxique en utilisant des mécanismes tels que des modèles cachés de Markov (HMM), des séparateurs à vastes marges (SVM) ou encore des champs conditionnels aléatoires (CRF). On disposera alors d’autant de composants (HmmTagger, SvmTagger, CrfTagger…), respectant tous les spécifications de l’interface ITagger. Le reste de l’application manipulera ces composants d’une façon abstraite en tant que ITagger, sans avoir besoin de connaître leur implémentation particulière50. L’application utilisant ces composants peut alors très facilement substituer une implémentation à une autre ; cela permet de choisir, pour une tâche donnée, celui qui donne les meilleurs résultats en fonction de la nature des documents à analyser.

b)

Définition de tests unitaires et de tests de non-régression

Un test unitaire est destiné à s’assurer du fonctionnement correct d’un composant d’un logiciel indépendamment du reste du programme, afin de vérifier qu’il répond aux spécifications prévues. Après une modification substantielle du code ou un changement de version d’un autre composant,

47 MONO (http://www.mono-project.com) est un portage libre de .NET sur Linux et Mac OS. 48 En C++, une interface peut se définir comme une classe abstraite virtuelle pure.

49 Ici codée en langage C# ; par convention, le nom d’une interface commence par la lettre I en majuscule. 50 Sauf évidemment lors de l’instanciation (il faut quand même préciser à un moment donné qui fait quoi), qui

l’ensemble des tests unitaires peut être rejoué afin de rechercher d’éventuelles régressions du code (c’est-à-dire l’apparition d’erreurs nouvelles).

c)

Conception technique permettant le passage à l’échelle

La capacité à « monter en charge » est un point essentiel pour traiter des corpus importants. L’environnement .NET dispose de nombreux protocoles de communication entre machines51, qui permettent de distribuer facilement des traitements, et d’infrastructures de grilles de calcul massivement parallèle52.

La course à la puissance des processeurs passe aujourd’hui davantage par la multiplication des « cœurs » sur un processeur que par l’augmentation de leur fréquence. Pour en tirer parti et ne pas sous-exploiter les architectures matérielles actuelles, il faut distribuer les calculs sur ces différents cœurs, en lançant des tâches multiples (multithreading) au sein d’un même processus. Ce type de développement est au centre des systèmes d’exploitation et des serveurs de bases de données. La conception de tels systèmes est connue depuis longtemps pour être complexe (Dijkstra, 1965). De plus, les outils qui aident à détecter un risque d’interblocage sont rares ; une erreur nouvelle risque toujours d’apparaître à l’exécution dans une configuration qui n’aura jamais été rencontrée lors des tests.

Les composants spécifiquement écrits pour Antelope ont été conçus pour s’exécuter dans un environnement multitâche. Les composants externes sont encapsulés avec un mécanisme qui garantit l’invocation séquentielle des méthodes. Nous avons pu, par exemple, effectuer une analyse syntaxique complète de la Simple Wikipedia53 en trois jours. Pour cela, nous avons distribué Antelope sur cinq ordinateurs tournant avec un processeur à double cœur ; ils communiquaient (via des services Web) avec un serveur chargé de leur affecter des analyses de phrases et de consolider et stocker les résultats. Sur une seule machine mono-cœur, ce calcul aurait alors pris près d’un mois.

d)

Sauvegarde et restauration du résultat d’une analyse

De même qu’un logiciel bureautique permet d’enregistrer un document sur disque puis de le rouvrir, Antelope peut sauvegarder le résultat de l’analyse d’un texte dans un fichier (typiquement dans un format XML), puis le recharger en mémoire. Ce mécanisme autorise le transport d’un résultat d’analyse entre machines, donc la répartition des traitements, ainsi que leur interruption et reprise.

e)

Présence d’un mécanisme d’extensibilité par annotations

Les annotations sont un modèle très fréquemment utilisé, offrant un mécanisme d’enrichissement de l’information. Dans Antelope, ce modèle est utilisé pour le stockage (par exemple, dans des fichiers XML) et aussi, si nécessaire, pendant des opérations de calcul en mémoire. Il permet de greffer dynamiquement de nouvelles informations à des instances d’objets, sans imposer une modification du code de leur classe ou une spécialisation. Les principaux objets du modèle unifié d’Antelope (document, phrase, analyse syntaxique, mot, coréférence) ainsi que ceux du lexique sémantique (lemme, synset) disposent d’annotations54. Elles permettent de stocker :

51 Web services, XML sur TCP, .NET remoting (flux binaire sur HTTP ou TCP).

52 Par exemple www.alchemi.net ou www.digipede.net (Antelope ne les exploite pas encore). 53 A cette époque, la Simple Wikipedia comportait 15 000 articles écrits en anglais simplifié.

54 Une annotation est implémentée sous forme d’une structure de dictionnaire, c’est-à-dire une liste de paires

30

 Des résultats intermédiaires pendant un calcul : par exemple, lors du calcul des anaphores, une annotation précise si un pronom est pléonastique ou non.

 Des données complémentaires optionnelles : un concept du lexique sémantique peut ainsi être relié à l’URL de l’article correspondant dans la Wikipédia.

3.

Intégration de composants externes

L’équipe Proxem a développé ses propres analyseurs syntaxiques à partir de 2011, par apprentissage automatique : un étiquetage morphosyntaxique (en utilisant des CRF) et un analyseur robuste du français. Antelope intègre aussi plusieurs composants externes, codés en différents langages :

 L’étiqueteur morphosyntaxique SS Tagger55 (composant C++).

 Un étiqueteur morphosyntaxique « à la Brill » (réimplémenté nativement en C#).

 Deux analyseurs syntaxiques robustes pour la langue anglaise, qui traitent avec succès des phrases complexes et tolèrent la présence de mots inconnus :

o Le Stanford Parser (Manning, Klein, 2002) est un analyseur probabiliste écrit en Java, fourni avec plusieurs grammaires (allemande, chinoise, arabe). Il produit une forêt d’arbres de constituants, et sait les traduire en arbres de dépendances.

o Le Link Grammar Parser (Sleator, Temperley, 1991), codé en C, repose sur des règles. Il produit un ou plusieurs arbres de dépendances (plus précisément, de liens typés reliant des paires de mots), puis les transforme en arbres de constituants.

 Un analyseur syntaxique du français : le TagParser56 (Francopoulo, 2008), codé en Java, qui produit comme analyse un arbre de dépendances entre chunks.

Antelope utilisant systématiquement le modèle de programmation par interfaces, ces composants externes sont encapsulés par une interface ITagger ou IParser, ce qui permet de les rendre interchangeables.

a)

Link Grammar Parser

Partant d’une phrase, cet analyseur en détermine la structure syntaxique, qui consiste en un ensemble de liens typés reliant des paires de mots. La grammaire de dépendances utilisée pour l’anglais distingue 107 types de liens. L’analyse peut donner une forêt d’arbres, chaque arbre étant pondéré par un « coût syntaxique ». Par exemple, la phrase “the dog with the man and the bone ran” donne deux analyses, correspondant à la distribution possible autour de la conjonction de coordination and :

The dog with (the man and the bone) ran

┌─────────────────Ss────────────────┐ │ ┌───────────Js──────────┐ │ │ ├───Js───┐ │ │ ┌─Ds─┼──Mp─┤ ┌─Ds─┤ ┌──Ds─┤ │ │ │ │ │ │ │ │ │ the dog.n with the man.n and the bone.n ran.v

55 Un étiqueteur morphosyntaxique rapide qui utilise une extension des chaînes de Markov à entropie

maximale. Voir (Tsuruoka, Tsujii, 2005).

(The dog with the man) and (the bone) ran

┌─────────────────Ss────────────────┐ │ ┌───Js───┐ │ ┌─Ds─┼──Mp─┤ ┌─Ds─┤ ┌──Ds─┬──Ss─┤ │ │ │ │ │ │ │ │ the dog.n with the man.n and the bone.n ran.v

Dans les arbres de dépendances produits par le Link Grammar Parser, on remarque que :

 Les nœuds sont les mots de la phrase ; certains d’entre eux ont un suffixe qui indique la partie du discours (nom, verbe, adjectif, adverbe, préposition, etc.). Par exemple, “ran.v” est reconnu en tant que forme de verbe (suffixe .v), et “dog.n” en tant que forme de nom (suffixe .n).

 Des arcs étiquetés relient les nœuds du graphe ; chaque étiquette précise un rôle grammatical (sujet, déterminant, etc.). Par exemple, entre “dog.n” et “ran.v”, le libellé du lien est « Ss » où :

o La première lettre (S_ majuscule) désigne une fonction sujet (Subject). o La seconde lettre (_s minuscule) précise qu’il est singulier (singular).

(1) Robustesse et rapidité de l’analyseur

L’analyseur offre de bonnes performances pour un analyseur en profondeur, ainsi qu’une excellente robustesse. Il traite avec succès des phrases complexes, et est tolérant à la présence de mots inconnus. Quand il en rencontre, il essaie de déterminer leur partie du discours en fonction du contexte. Par exemple, dans la phrase suivante, machining n’est pas présent dans le lexique de référence (comme l’indique l’annotation [!]), mais est supposé être le gérondif d’un verbe (extension .g).

┌──Ss──┬───Pg*b───┬───MVp──┬─Js┐ │ │ │ │ │ George.n was.v machining[!].g in Najaf

(2) Stockage externe de la grammaire

La LinkGrammar s’appuie sur une grammaire lexicalisée qui couvre d’une façon relativement complète la langue anglaise courante. Chaque élément du lexique est associé à un ensemble de structures élémentaires qui sont des configurations de la structure de dépendance décrivant les liens possibles de cette unité lexicale. Le formalisme est équivalent à une CFG et l’algorithme d’analyse est en O(n3).

La grammaire est stockée indépendamment du code, dans des fichiers textes qui contiennent également le lexique de référence (approximativement 60 000 mots). Ce stockage externe permet de modifier ou d’enrichir la grammaire ou le lexique. En revanche, le formalisme de stockage est propriétaire et plutôt complexe à maîtriser.

Nous avons importé la ressource LinkGrammar-WN, qui enrichit le lexique du Link Grammar Parser de 14 000 nouveaux noms provenant de WordNet. Elle a été créée en se basant sur la démarche de fusion de lexiques présentée dans (Szolovits, 2003).

32

b)

Mécanismes techniques d’intégration

L’intégration des composants externes se fait de différentes façons. Si le code source du composant est disponible et écrit dans un langage pour lequel il existe un compilateur pour .NET57, une recompilation suffit.

Si le composant est écrit en Java, nous utilisons le logiciel IKVM, qui est capable de traduire un fichier binaire Java .class ou .jar dans le bytecode équivalent de .NET. C’est le mécanisme que nous avons mis en œuvre pour intégrer les analyseurs d’Antelope à l’architecture UIMA (voir page 36). Pour du code en C ou C++, nous encapsulons le composant à travers un mécanisme standard de bibliothèque dynamique (DLL) ; l’interface de programmation du composant est présentée en utilisant un design pattern classique (de type Façade), qui regroupe l’ensemble des services du composant dans une classe unique. L’expérience nous a toutefois montré qu’il est dangereux de mélanger du code .NET ou Java avec du code C ou C++ ; en effet, le premier s’exécute en bénéficiant de la protection offerte par une machine virtuelle : même en cas d’erreur d’exécution dans le programme, les mécanismes d’exceptions permettent une reprise sur erreur ; en revanche, une erreur dans du code C/C++ peut résulter en une corruption de la mémoire et une erreur fatale au programme. C’est donc difficile à accepter dans un contexte industriel, avec des contraintes de production en 24/7 58. Concrètement, nous avons constaté ce problème avec un correcteur orthographique ; une solution est alors d’effectuer un portage du code C/C++ vers du code natif C#.

c)

Adaptation à un format commun

Il est relativement aisé d’intégrer un nouvel étiqueteur morphosyntaxique pour l’anglais, dans la mesure où le jeu d’étiquette du Penn TreeBank est un standard de fait, généralement bien suivi (à quelques détails près parfois, comme des étiquettes particulières pour les verbes to be et to have). L’effort à fournir est plus important pour les analyseurs syntaxiques. En effet, même s’ils produisent des structures de même nature (arbres de constituants et arbres de dépendances) avec des étiquettes de constituants normalisées (NP, VP, PP…), les étiquettes et l’organisation des dépendances diffèrent radicalement entre les différents analyseurs que nous avons utilisés.

La figure 5 permet de le constater, en comparant la RSyntS produite par le Link Grammar Parser (à gauche) avec celle du Stanford Parser (à droite), lors de l’analyse syntaxique d’une même phrase (l’arbre de constituants est au-dessus des mots, l’arbre de dépendances en-dessous). Nous verrons au chapitre VII.A que lors du passage en RSyntP nous obtenons un format commun de dépendances syntaxiques profondes.

57 VB, Pascal, Python, Eiffel, COBOL, PHP, etc. étendus pour offrir des fonctionnalités identiques.

Figure 5 : Comparaison des sorties du Link Grammar et du Stanford Parser

G. Positionnement par rapport à d’autres plates-