[PYTHON] Lernen Sie die Kategorisierung von Dokumenten mit spaCy CLI

Dieser Artikel ist der dritte Tagesartikel von Adventskalender 2019 für die Verarbeitung natürlicher Sprache Nr. 2.

Einführung

Dieser Artikel befasst sich mit der Kategorisierung von Lerndokumenten mithilfe der Befehlszeilenschnittstelle von spaCy. Schließlich möchte ich GiNZA verwenden, um japanische Dokumente zu klassifizieren, aber leider habe ich meine Bemühungen erschöpft, sodass ich nur englische Dokumente bearbeiten werde.

In den folgenden Artikeln, die ich zuvor geschrieben habe, werden japanische Dokumente ohne Verwendung von CLI klassifiziert. https://qiita.com/kyamamoto9120/items/cd36017be13529366767

Motivation

Im obigen Artikel bestand das Problem darin, dass die Kategorisierung zwar gelernt werden konnte, aber sehr langsam war. Die Ursache ist, dass nur ein Kern der CPU verwendet wird und keine GPU unterstützt wird.

Als ich auf die Dokumentation zurückblickte, um dieses Problem zu beheben, stellte ich fest, dass beim Lernen mit spaCy empfohlen wurde, die CLI für die meisten Zwecke am besten zu verwenden. https://spacy.io/usage/training#spacy-train-cli

Auf der anderen Seite wird nicht viel darüber gesprochen, wie man mit der CLI von spaCy lernt, und es gibt fast keine Informationen auf Japanisch. Also habe ich beschlossen, es zu versuchen, um jemandem zu helfen.

Wir sind sehr willkommen, also danke.

Voraussetzungen

Dieser Artikel wurde mit spaCy 2.2.3 validiert. Die Ausführungsumgebung verwendet die GPU-Laufzeit von Google Colab und die GPU ist Tesla P100.

Verwenden Sie außerdem fetch_20newsgroups von scicit-learn für das Dataset. Ich denke, dass es in 20 Kategorien von Nachrichtenartikeln dem Livedoor News Corpus auf Japanisch ähnlich ist.

Datenaufbereitung

Um mit der spaCy-CLI zu lernen, müssen die Daten im folgenden JSON-Format vorliegen.

[{
    "id": int,                      # ID of the document within the corpus
    "paragraphs": [{                # list of paragraphs in the corpus
        "raw": string,              # raw text of the paragraph
        "sentences": [{             # list of sentences in the paragraph
            "tokens": [{            # list of tokens in the sentence
                "id": int,          # index of the token in the document
                "dep": string,      # dependency label
                "head": int,        # offset of token head relative to token index
                "tag": string,      # part-of-speech tag
                "orth": string,     # verbatim text of the token
                "ner": string       # BILUO label, e.g. "O" or "B-ORG"
            }],
            "brackets": [{          # phrase structure (NOT USED by current models)
                "first": int,       # index of first token
                "last": int,        # index of last token
                "label": string     # phrase label
            }]
        }],
        "cats": [{                  # new in v2.2: categories for text classifier
            "label": string,        # text category label
            "value": float / bool   # label applies (1.0/true) or not (0.0/false)
        }]
    }]
}]

Quelle: https://spacy.io/api/annotation#json-input

Die Konvertierung von spaCy Doc in das oben genannte JSON-Format kann mit gold.docs_to_json erfolgen. Im Folgenden wird der Datensatz fetch_20newsgroups anhand des Beispiels in das obige JSON-Format konvertiert.

import spacy
import srsly
from spacy.gold import docs_to_json
from sklearn.datasets import fetch_20newsgroups
from sklearn.model_selection import train_test_split

def save_to_json(model, data, targets, target_names, output_file, n_texts=0):
  def get_categories(target):
    return dict([(key, int(target == i)) for i, key in enumerate(target_names)])

  nlp = spacy.load(model)
  nlp.disable_pipes(*nlp.pipe_names)
  sentencizer = nlp.create_pipe("sentencizer")
  nlp.add_pipe(sentencizer, first=True)

  docs = []
  count = 0
  for i, doc in enumerate(nlp.pipe(data)):
    doc.cats = get_categories(targets[i])
    docs.append(doc)

    if n_texts > 0 and count == n_texts:
      break
    count += 1

  srsly.write_json(output_file, [docs_to_json(docs)])
  return count

newsgroups_train = fetch_20newsgroups(subset='train')
newsgroups_test = fetch_20newsgroups(subset='test')

X_train, X_dev, y_train, y_dev = train_test_split(newsgroups_train.data, newsgroups_train.target, test_size=0.20, random_state=42)

save_to_json(
  'en_core_web_sm',
  X_train,
  y_train,
  newsgroups_train.target_names,
  'train.json',
)

save_to_json(
  'en_core_web_sm',
  X_dev,
  y_dev,
  newsgroups_train.target_names,
  'dev.json',
)

save_to_json(
  'en_core_web_sm',
  newsgroups_test.data,
  newsgroups_test.target,
  newsgroups_test.target_names,
  'test.json',
)

Lernen

Das Lernen erfolgt mit dem Befehl python -m spacy train.

Ich verwende -v anstelle von -b, um das Basismodell anzugeben, das auf dem folgenden Problem basiert. Referenz: https://github.com/explosion/spaCy/issues/4504

$ time python -m spacy train en output train.json dev.json -v en_core_web_sm -p textcat -ta simple_cnn -g 0
Training pipeline: ['textcat']
Starting with blank model 'en'
Loading vector from model 'en_core_web_sm'
Counting training words (limit=0)
tcmalloc: large alloc 2035253248 bytes == 0x65048000 @  0x7fdf2bb321e7 0x5acc1b 0x7fdf2115d5db 0x7fdf2115dbf0 0x7fdf2115de36 0x7fdf2115b5c1 0x50abc5 0x50c549 0x7fdec8648b20 0x7fdec864d98f 0x7fdec86406c5 0x7fdec868fc47 0x7fdecb4f172a 0x7fdec867cfce 0x7fdecb4f172a 0x7fdec86a91e7 0x7fdecb4f172a 0x7fdec8670148 0x7fdec867a24b 0x594f4c 0x54a2c5 0x551761 0x5aa69c 0x50ab53 0x50d320 0x5081d5 0x5895e1 0x5a04ce 0x50d8f5 0x5081d5 0x50a020
Textcat evaluation score: F1-score macro-averaged across the labels
'alt.atheism, comp.graphics, comp.os.ms-windows.misc, comp.sys.ibm.pc.hardware,
comp.sys.mac.hardware, comp.windows.x, misc.forsale, rec.autos, rec.motorcycles,
rec.sport.baseball, rec.sport.hockey, sci.crypt, sci.electronics, sci.med,
sci.space, soc.religion.christian, talk.politics.guns, talk.politics.mideast,
talk.politics.misc, talk.religion.misc'

Itn  Textcat Loss  Textcat  Token %  CPU WPS  GPU WPS
---  ------------  -------  -------  -------  -------
  1      1300.851   45.507  100.000    34746   125805
  2       210.326   62.555  100.000    34629   125121
  3       155.350   71.460  100.000    35131   125583
  4       120.228   76.617  100.000    35244   126553
  5       104.154   78.516  100.000    35371   126499
  6        64.690   80.724  100.000    35491   126734
  7        57.947   82.024  100.000    35750   123946
  8        49.666   82.662  100.000    35840   126354
  9        38.450   83.410  100.000    35538   126965
 10        36.798   83.496  100.000    35435   125634
 11        24.351   83.933  100.000    35467   125578
 12        24.935   83.989  100.000    35490   125223
 13        26.003   84.009  100.000    35329   125631
 14        16.517   84.013  100.000    35255   123643
 15        16.210   84.367  100.000    35234   124040
 16        16.640   84.601  100.000    35554   126235
 17        17.365   84.494  100.000    35436   126539
 18        18.860   84.866  100.000    35596   126301
 19        11.555   84.910  100.000    35644   126256
 20        17.691   84.916  100.000    35481   125505
 21        16.697   85.556  100.000    35767   125510
 22        13.508   84.815  100.000    35795   126961
 23        12.806   84.610  100.000    36021   126313
 24         6.776   84.754  100.000    36155   126526
 25        10.806   85.122  100.000    35866   126933
 26        10.999   85.007  100.000    35972   126758
 27         8.463   85.224  100.000    36065   125702
 28         7.601   84.920  100.000    35606   127107
 29        10.220   85.088  100.000    36242   127223
 30         7.911   84.889  100.000    36157   128428
✔ Saved model to output directory
output/model-final
✔ Created best model
output/model-best

real	97m9.901s
user	87m25.982s
sys	9m32.144s

Es scheint, dass Atmosphärenlernen durchgeführt wird, und es scheint, dass auch GPU verwendet wird. Mit dem Tesla P100 können Sie viel schneller lernen als mit der CPU allein. Beim K80 gab es keinen großen Unterschied zur CPU allein. Ich denke, es ist besser, die GPU sorgfältig auszuwählen, wenn Sie Google Colab verwenden.

Auswertung

Das Lernen erfolgt mit dem Befehl "python -m spacy evalu". Ich war nicht süchtig danach und konnte es reibungslos ausführen.

$ time python -m spacy evaluate output/model-best/ test.json -g 0
tcmalloc: large alloc 1610211328 bytes == 0x4ce4c000 @  0x7fce167961e7 0x5acc1b 0x7fce0bdc15db 0x7fce0bdc1bf0 0x7fce0bdc1e36 0x7fce0bdbf5c1 0x50abc5 0x50c549 0x7fcdb32acb20 0x7fcdb32b198f 0x7fcdb32a46c5 0x7fcdb32f3c47 0x7fcdb615572a 0x7fcdb32e0fce 0x7fcdb615572a 0x7fcdb330d1e7 0x7fcdb615572a 0x7fcdb32d4148 0x7fcdb32de24b 0x594f4c 0x54a2c5 0x551761 0x5aa69c 0x50ab53 0x50c549 0x5081d5 0x5895e1 0x5a04ce 0x50d8f5 0x5081d5 0x50a020
tcmalloc: large alloc 1610211328 bytes == 0x4ce4c000 @  0x7fce167961e7 0x5acc1b 0x7fce0bdc15db 0x7fce0bdc1bf0 0x7fce0bdc1e36 0x7fce0bdbf5c1 0x50abc5 0x50c549 0x7fcdb32acb20 0x7fcdb32b198f 0x7fcdb32a46c5 0x7fcdb32f3c47 0x7fcdb615572a 0x7fcdb32e0fce 0x7fcdb615572a 0x7fcdb330d1e7 0x7fcdb615572a 0x7fcdb32d4148 0x7fcdb32de3fe 0x594f4c 0x54a2c5 0x551761 0x5aa69c 0x50ab53 0x50c549 0x5081d5 0x5895e1 0x5a04ce 0x50d8f5 0x5081d5 0x50a020

================================== Results ==================================

Time      24.76 s
Words     3124908
Words/s   126185 
TOK       100.00 
POS       0.00   
UAS       0.00   
LAS       0.00   
NER P     0.00   
NER R     0.00   
NER F     0.00   
Textcat   70.99  


real	1m22.570s
user	1m13.028s
sys	0m9.359s

Die Punktzahl zum Zeitpunkt der Bewertung ist viel niedriger als die Punktzahl zum Zeitpunkt des Lernens. Die Ursache wurde nicht untersucht, aber ich denke, dies ist ein Problem bei der Arbeit an einer tatsächlichen Aufgabe.

Ich bin der Meinung, dass es viel Raum für Verbesserungen gibt, da wir diesmal keine Vorbehandlung durchgeführt haben.

Zusammenfassung

In diesem Artikel haben wir die CLI von spaCy verwendet, um ein Dataset mit dem Namen fetch_20newsgroups zu klassifizieren. Es ist ein schlechter Artikel, aber ich hoffe, er hilft jemandem.

Als nächstes möchte ich japanische Dokumente mit derselben Methode in Kategorien einteilen.

Recommended Posts

Lernen Sie die Kategorisierung von Dokumenten mit spaCy CLI
Lernen Sie die Kategorisierung japanischer Dokumente mit spaCy / GiNZA (Fehler)
Lerne Python mit ChemTHEATER
Lerne Zundokokiyoshi mit LSTM
Lernen Sie mit Chemo Informatics Matplotlib
Lernen Sie mit Chemo Informatics NumPy
DCGAN mit TF Learn
Lernen Sie Pendulum-v0 mit DDPG
Lernen Sie Librosa mit einem Tutorial 1
Lernen Sie mit Chainer elliptische Bahnen
Lernen Sie neue Daten mit PaintsChainer
Dokumentieren Sie Python-Code mit Doxygen