December 9, 2022

Branches Tech

Engagé pour la qualité technologique

Traitement du langage naturel avec Apache OpenNLP

9 min read
Conceptual images of a woman listening to a stream of abstract letters.

Le traitement du langage naturel (TLN) est l’une des frontières les plus importantes du logiciel. L’idée de base – comment consommer et générer efficacement le langage humain – est un effort continu depuis l’aube de l’informatique numérique. L’effort se poursuit aujourd’hui, avec l’apprentissage automatique et les bases de données de graphes en première ligne de l’effort de maîtrise du langage naturel.

Cet article est une introduction pratique à Apache OpenNLPun projet d’apprentissage automatique basé sur Java qui fournit des primitives telles que la segmentation et lemmatisationtous deux requis pour créer des systèmes compatibles NLP.

Qu’est-ce qu’Apache OpenNLP ?

Un système de traitement automatique du langage naturel tel qu’Apache OpenNLP comporte généralement trois parties :

  1. Apprendre d’un corpusqui est un ensemble de données textuelles (pluriel : corpus)
  2. Un modèle généré à partir du corpus
  3. Utilisation du modèle pour effectuer des tâches sur le texte cible

Pour rendre les choses encore plus simples, OpenNLP propose des modèles pré-formés disponibles pour de nombreux cas d’utilisation courants. Pour des exigences plus sophistiquées, vous devrez peut-être former vos propres modèles. Pour un scénario plus simple, vous pouvez simplement télécharger un modèle existant et l’appliquer à la tâche à accomplir.

Détection de la langue avec OpenNLP

Construisons une application de base que nous pouvons utiliser pour voir comment fonctionne OpenNLP. Nous pouvons commencer la mise en page avec un archétype Maven, comme indiqué dans le Listing 1.

Listing 1. Créer un nouveau projet


~/apache-maven-3.8.6/bin/mvn archetype:generate -DgroupId=com.infoworld.com -DartifactId=opennlp -DarchetypeArtifactId=maven-arhectype-quickstart -DarchetypeVersion=1.4 -DinteractiveMode=false

Cet archétype échafaudera un nouveau projet Java. Ensuite, ajoutez la dépendance Apache OpenNLP au pom.xml dans le répertoire racine du projet, comme indiqué dans le Listing 2. (Vous pouvez utiliser n’importe quelle version de la dépendance OpenNLP Le plus courant.)

Listing 2. La dépendance OpenNLP Maven


<dependency>
  <groupId>org.apache.opennlp</groupId>
  <artifactId>opennlp-tools</artifactId>
  <version>2.0.0</version>
</dependency>

Pour faciliter l’exécution du programme, ajoutez également l’entrée suivante au <plugins> partie de la pom.xmle fichier :

Listing 3. Cible d’exécution de la classe principale pour le Maven POM


<plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>exec-maven-plugin</artifactId>
            <version>3.0.0</version>
            <configuration>
                <mainClass>com.infoworld.App</mainClass>
            </configuration>
        </plugin>

Maintenant, exécutez le programme avec maven compile exec:java. (Vous aurez besoin de Maven et d’un JDK installé pour exécuter cette commande.) L’exécuter maintenant vous donnera simplement le familier “Hello World!” production.

Télécharger et configurer un modèle de détection de langue

Nous sommes maintenant prêts à utiliser OpenNLP pour détecter la langue dans notre exemple de programme. La première étape consiste à télécharger un modèle de détection de langue. Téléchargez le dernier composant Language Detector à partir du Page de téléchargement des modèles OpenNLP. Au moment d’écrire ces lignes, la version actuelle est langdetect-183.bin.

Pour faciliter l’accès au modèle, entrons dans le projet Maven et mkdir un nouveau répertoire sur /opennlp/src/main/resourcepuis copiez le langdetect-*.bin déposer là-dedans.

Maintenant, modifions un fichier existant avec ce que vous voyez dans le Listing 4. Nous utiliserons /opennlp/src/main/java/com/infoworld/App.java pour cet exemple.

Listing 4. App.java


package com.infoworld;

import java.util.Arrays;
import java.io.IOException;
import java.io.InputStream;
import java.io.FileInputStream;
import opennlp.tools.langdetect.LanguageDetectorModel;
import opennlp.tools.langdetect.LanguageDetector;
import opennlp.tools.langdetect.LanguageDetectorME;
import opennlp.tools.langdetect.Language;

public class App 
  public static void main( String[] args ) 
    System.out.println( "Hello World!" );
    App app = new App();
    try 
      app.nlp();
     catch (IOException ioe)
      System.err.println("Problem: " + ioe);
    
  
  public void nlp() throws IOException 
    InputStream is = this.getClass().getClassLoader().getResourceAsStream("langdetect-183.bin"); // 1
    LanguageDetectorModel langModel = new LanguageDetectorModel(is); // 2
    String input = "This is a test.  This is only a test.  Do not pass go.  Do not collect $200.  When in the course of human history."; // 3
    LanguageDetector langDetect = new LanguageDetectorME(langModel); // 4
    Language langGuess = langDetect.predictLanguage(input); // 5

    System.out.println("Language best guess: " + langGuess.getLang());

    Language[] languages = langDetect.predictLanguages(input);
    System.out.println("Languages: " + Arrays.toString(languages));
  

Maintenant, vous pouvez exécuter ce programme avec la commande, maven compile exec:java. Lorsque vous le ferez, vous obtiendrez une sortie similaire à celle indiquée dans le Listing 5.

Listing 5. Analyse de la langue 1



Meilleure estimation de la langue : eng Langues : [eng (0.09568318011427969), tgl (0.027236092538322446), cym (0.02607472496029117), war (0.023722424236917564)...

The “ME” in this sample stands for maximum entropy. Maximum entropy is a concept from statistics that is used in natural language processing to optimize for best results.

Evaluate the results

Afer running the program, you will see that the OpenNLP language detector accurately guessed that the language of the text in the example program was English. We’ve also output some of the probabilities the language detection algorithm came up with. After English, it guessed the language might be Tagalog, Welsh, or War-Jaintia. In the detector’s defense, the language sample was small. Correctly identifying the language from just a handful of sentences, with no other context, is pretty impressive.

Before we move on, look back at Listing 4. The flow is pretty simple. Each commented line works like so:

  1. Open the langdetect-183.bin file as an input stream.
  2. Use the input stream to parameterize instantiation of the LanguageDetectorModel.
  3. Create a string to use as input.
  4. Make a language detector object, using the LanguageDetectorModel from line 2.
  5. Run the langDetect.predictLanguage() method on the input from line 3.

Testing probability

If we add more English language text to the string and run it again, the probability assigned to eng should go up. Let’s try it by pasting in the contents of the United States Declaration of Independence into a new file in our project directory: /src/main/resources/declaration.txt. We’ll load that and process it as shown in Listing 6, replacing the inline string:

Listing 6. Load the Declaration of Independence text


String input = new String(this.getClass().getClassLoader().getResourceAsStream("declaration.txt").readAllBytes());

If you run this, you’ll see that English is still the detected language.

Detecting sentences with OpenNLP

You’ve seen the language detection model at work. Now, let’s try out a model for detecting sentences. To start, return to the OpenNLP model download page, and add the latest Sentence English model component to your project’s /resource directory. Notice that knowing the language of the text is a prerequisite for detecting sentences.

We’ll follow a similar pattern to what we did with the language detection model: load the file (in my case opennlp-en-ud-ewt-sentence-1.0-1.9.3.bin) and use it to instantiate a sentence detector. Then, we’ll use the detector on the input file. You can see the new code in Listing 7 (along with its imports); the rest of the code remains the same.

Listing 7. Detecting sentences


import opennlp.tools.sentdetect.SentenceModel;
import opennlp.tools.sentdetect.SentenceDetectorME;
//...
InputStream modelFile = this.getClass().getClassLoader().getResourceAsStream("opennlp-en-ud-ewt-sentence-1.0-1.9.3.bin");
    SentenceModel sentModel = new SentenceModel(modelFile);
    
    SentenceDetectorME sentenceDetector = new SentenceDetectorME(sentModel);
    String sentences[] = phraseDetector.sentDetect(entrée);  System.out.println("Phrases : " + phrases.length + " première ligne : "+ phrases[2])

L’exécution du fichier maintenant produira quelque chose comme ce qui est montré dans le Listing 8.

Listing 8. Sortie du détecteur de phrase


Sentences: 41 first line: In Congress, July 4, 1776

The unanimous Declaration of the thirteen united States of America, When in the Course of human events, ...

Notez que le détecteur de phrases a trouvé 41 phrases, ce qui semble correct. Notez également que ce modèle de détecteur est assez simple : il recherche simplement des périodes et des espaces pour trouver les pauses. Il n’a pas de logique pour la grammaire. C’est pourquoi nous avons utilisé l’index 2 sur le tableau des phrases pour obtenir le préambule réel – les lignes d’en-tête ont été regroupées en deux phrases. (Les documents fondateurs sont notoirement incompatibles avec la ponctuation et le détecteur de phrase ne tente pas de considérer “Quand dans le cours …” comme une nouvelle phrase.)

Tokenisation avec OpenNLP

Après avoir divisé les documents en phrases, la tokenisation est le prochain niveau de granularité. Tokénisation est le processus de décomposer le document en mots et ponctuation, respectivement. Nous pouvons utiliser le code affiché dans le Listing 9 :

Listing 9. Tokénisation


import opennlp.tools.tokenize.SimpleTokenizer;
//...
SimpleTokenizer tokenizer = SimpleTokenizer.INSTANCE;
    String[] tokens = tokenizer.tokenize(input);
    System.out.println("tokens: " + tokens.length + " : " + tokens[73] + " " + tokens[74] + " " + tokens[75]);

Cela donnera une sortie comme ce qui est montré dans le Listing 10.

Listing 10. Sortie du Tokenizer


tokens: 1704 : human events ,

Ainsi, le modèle a divisé le document en 1704 jetons. Nous pouvons accéder au tableau de jetons, aux mots «événements humains» et à la virgule suivante, et chacun occupe un élément.

Recherche de nom avec OpenNLP

Maintenant, nous allons saisir le modèle “Person name finder” pour l’anglais, appelé en-ner-person.bin. Non pas que ce modèle se trouve sur le Page de téléchargement des modèles Sourceforge. Une fois que vous avez le modèle, placez-le dans le répertoire des ressources de votre projet et utilisez-le pour trouver des noms dans le document, comme indiqué dans le Listing 11.

Listing 11. Recherche de nom avec OpenNLP


import opennlp.tools.namefind.TokenNameFinderModel;
import opennlp.tools.namefind.NameFinderME;
import opennlp.tools.namefind.TokenNameFinder;
import opennlp.tools.util.Span
//...
InputStream nameFinderFile = this.getClass().getClassLoader().getResourceAsStream("en-ner-person.bin");
    TokenNameFinderModel nameFinderModel = new TokenNameFinderModel(nameFinderFile);
    NameFinderME nameFinder = new NameFinderME(nameFinderModel);
    Span[] names = nameFinder.find(tokens);
    System.out.println("names: " + names.length);
    for (Span nameSpan : names)
      System.out.println("name: " + nameSpan + " : " + tokens[nameSpan.getStart()-1] + " " + tokens[nameSpan.getEnd()-1]);

Dans le Listing 11, nous chargeons le modèle et l’utilisons pour instancier un NameFinderME object, que nous utilisons ensuite pour obtenir un tableau de noms, modélisés comme des objets span. Un span a un début et une fin qui nous indiquent où le détecteur pense que le nom commence et se termine dans l’ensemble de jetons. Notez que le chercheur de nom attend un tableau de chaînes déjà tokenisées.

Balisage des parties du discours avec OpenNLP

OpenNLP nous permet de baliser des parties du discours (POS) par rapport à des chaînes tokenisées. Le Listing 12 est un exemple de balisage des parties du discours.

Listing 12. Balisage des parties du discours


import opennlp.tools.postag.POSModel;
import opennlp.tools.postag.POSTaggerME;
//…
InputStream posIS = this.getClass().getClassLoader().getResourceAsStream("opennlp-en-ud-ewt-pos-1.0-1.9.3.bin");
POSModel posModel = new POSModel(posIS);
POSTaggerME posTagger = new POSTaggerME(posModel);
String tags[] = posTagger.tag(tokens);
System.out.println("tags: " + tags.length);

for (int i = 0; i < 15; i++)
  System.out.println(tokens[i] + " = " + tags[i]);

Le processus est similaire avec le fichier de modèle chargé dans une classe de modèle, puis utilisé sur le tableau de jetons. Il produit quelque chose comme Listing 13.

Listing 13. Sortie des parties du discours


tags: 1704
Declaration = NOUN
of = ADP
Independence = NOUN
: = PUNCT
A = DET
Transcription = NOUN
Print = VERB
This = DET
Page = NOUN
Note = NOUN
: = PUNCT
The = DET
following = VERB
text = NOUN
is = AUX

Contrairement au modèle de recherche de noms, le tagger POS a fait du bon travail. Il a correctement identifié plusieurs parties différentes du discours. Les exemples du Listing 13 incluent NOUN, ADP (qui signifie adposition) et PUNCT (pour la ponctuation).

Conclusion

Dans cet article, vous avez vu comment ajouter Apache OpenNLP à un projet Java et utiliser des modèles prédéfinis pour le traitement du langage naturel. Dans certains cas, vous devrez peut-être développer votre propre modèle, mais les modèles préexistants feront souvent l’affaire. En plus des modèles présentés ici, OpenNLP inclut des fonctionnalités telles qu’un catégoriseur de documents, un lemmatiseur (qui décompose les mots jusqu’à leurs racines), un fragmenteur et un analyseur. Tous ces éléments sont les éléments fondamentaux d’un système de traitement du langage naturel, et sont disponibles gratuitement avec OpenNLP.

Copyright © 2022 IDG Communications, Inc.

Leave a Reply