Traitement du langage naturel avec Apache OpenNLP
Le traitement du langage naturel (TAL) est l’une des frontières les plus importantes du logiciel. premières lignes de l’effort de maîtrise du langage naturel.
Cet article est une introduction pratique à Apache OpenNLP, un projet d’apprentissage automatique basé sur Java qui fournit des primitives telles que la segmentation et la lemmatisation, toutes deux nécessaires à la construction de 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 :
- Apprendre d’un corpusqui est un ensemble de données textuelles (pluriel : corpus)
- Un modèle généré à partir du corpus
- 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 la liste 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 la version la plus récente de la dépendance OpenNLP.)
Listing 2. La dépendance OpenNLP Maven
org.apache.opennlp
opennlp-tools
2.0.0
Pour faciliter l’exécution du programme, ajoutez également l’entrée suivante au
partie de la pom.xm
le fichier :
Listing 3. Cible d’exécution de la classe principale pour le Maven POM
org.codehaus.mojo
exec-maven-plugin
3.0.0
com.infoworld.App
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 de la 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/resource
puis 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 faites, 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:
- Open the
langdetect-183.bin
file as an input stream. - Use the input stream to parameterize instantiation of the
LanguageDetectorModel
. - Create a string to use as input.
- Make a language detector object, using the
LanguageDetectorModel
from line 2. - 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
.Well 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, youll 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.
Well 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 points 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 When in the Course 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 en ponctuation, respectivement. Nous pouvons utiliser le code indiqué 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, prenez bien le modèle « Person name finder » pour l’anglais, appelé en-ner-person.bin. Non pas que ce modèle se trouve sur la 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 noms 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
objet, 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. La liste 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 le 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 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 disponible gratuitement avec OpenNLP.
Copyright © 2022 IDG Communications, Inc.