[PYTHON] Erstellung eines negativen / positiven Klassifikators mit BERT

Dieser Beitrag ist der Artikel zum 25. Tag des Adventskalenders 2019 - Qiita zur Verarbeitung natürlicher Sprache.

Es ist siny.

In diesem Artikel haben wir die Erstellung eines negativ-positiven Klassifikators mit BERT zusammengefasst, der ab 2019 eine wichtige Rolle bei der Verarbeitung natürlicher Sprache spielt.

Einführung

Ich denke, dass das Wissen über BERT in Büchern, Blogs, Qiita usw. weit verbreitet ist. Die meisten Datensätze, die für die Verarbeitung natürlicher Sprache verwendet werden können, basieren jedoch auf Englisch, und es gibt nicht viele japanische Datensätze. Daher gibt es nur wenige Fälle und Informationen zur Verwendung von BERT mit japanischem Text. fühlte.

Derzeit denke ich, dass die folgenden wichtigen japanischen Datensätze kostenlos verwendet werden können.

Als ich nach "** Gibt es einen Datensatz mit einer bestimmten Datenmenge und japanischen Textdaten, die kostenlos verwendet werden können? **" suchte, chABSA-Datensatz Ich fand einen japanischen Datensatz (ungefähr 2800 Daten) namens chakki-works / chABSA-Datensatz.

chABSA-Datensatz ist ein japanischer Datensatz, der auf der Grundlage der Wertpapierberichte börsennotierter Unternehmen erstellt wurde. Jeder Satz enthält nicht nur eine negative / positive emotionale Klassifizierung, sondern auch Informationen, die die Perspektive von "was" negativ / positiv ausdrücken. Das Folgende sind Beispieldaten von ** chABSA-Datensatz **.

{
  "header": {
    "document_id": "E00008",
    "document_name": "Hokuto Co., Ltd.",
    "doc_text": "Wertpapierbericht",
    "edi_id": "E00008",
    "security_code": "13790",
    "category33": "Fischerei / Land- und Forstwirtschaft",
    "category17": "Essen",
    "scale": "6"
  },
  "sentences": [
    {
      "sentence_id": 0,
      "sentence": "Im laufenden konsolidierten Geschäftsjahr wird die japanische Wirtschaft aufgrund der Wirtschaftspolitik der Regierung und der geldpolitischen Lockerungsmaßnahmen der Bank of Japan ihre Unternehmensleistung und ihr Beschäftigungs- / Einkommensumfeld verbessern....",
      "opinions": [
        {
          "target": "Japanische Wirtschaft",
          "category": "NULL#general",
          "polarity": "neutral",
          "from": 11,
          "to": 16
        },
        {
          "target": "Unternehmensleistung",
          "category": "NULL#general",
          "polarity": "positive",
          "from": 38,
          "to": 42
        },...
      ],
    },
    {
      "sentence_id": 1,
      "sentence": "Das Umfeld rund um den Konzern ist so, dass die Reallöhne zwar schleppend sind, die Verbraucher jedoch...",
      "opinions": [
        {
          "target": "Reallohn",
          "category": "NULL#general",
          "polarity": "negative",
          "from": 15,
          "to": 19
        },...
      ]
    },...
  ]
}

Mit ** ch ABSA-Datensatz ** gibt es Tausende von Daten und Werte, die Emotionen ausdrücken, sodass sie für die negativ-positive Klassifizierung verwendet werden können? “Also habe ich mit diesem Datensatz einen BERT-negativ-positiven Klassifizierer erstellt. Ich versuchte es.

Der gesamte in diesem Artikel erläuterte Implementierungscode befindet sich auf Github. Klonen Sie ihn daher bitte entsprechend. Darüber hinaus wird jeder Prozess in ** BERT-Modellerstellung-Lerninferenz.ipynb ** auf Github beschrieben. Bitte beziehen Sie sich daher entsprechend darauf.

「chABSA-dataset」(https://github.com/sinjorjob/chABSA-dataset)

Inhaltsverzeichnis

  1. Prämisse
  2. Umweltbau
  3. Umrissdiagramm des BERT-Modells der negativen / positiven Klassifizierung
  4. Erstellen eines Datensatzes für negatives / positives Lernen
  5. Implementierung von Tokenizer für BERT
  6. Erstellen Sie DataLoader
  7. Implementierung eines negativen / positiven Klassifizierungsmodells durch BERT
  8. BERT-Feinabstimmungseinstellungen
  9. BERT lernen / argumentieren
  10. Lernergebnisse
  11. Geben Sie den Testtext ein, um Vorhersagen und Aufmerksamkeit zu visualisieren
  12. Zeigen Sie Inferenzergebnisse und eine gemischte Matrix mit einer großen Menge von Testdaten an
  13. Zusammenfassung

1. Prämisse

In diesem Artikel erstellen wir einen negativ-positiven Klassifikator, der auf den folgenden Annahmen basiert.

Artikel Bedeutung
OS Ubuntu
BERT-Modell Herausgegeben von der Kyoto Universitypytorch-pretrained-BERT-ModellDie Feinabstimmung erfolgt basierend auf.
Morphologische Analyse Juman++ (v2.0.0-rc2) or (v2.0.0-rc3)
Bibliothek Pytorch

2. Umweltbau

Erstellen Sie mit PyTorch eine Umgebung, in der Sie das BERT Japanese Pretrained-Modell verwenden können.

Bibliotheksinstallation


conda create -n pytorch python=3.6
conda activate pytorch
conda install pytorch=0.4 torchvision -c pytorch
conda install pytorch=0.4 torchvision cudatoolkit -c pytorch
conda install pandas jupyter matplotlib scipy scikit-learn pillow tqdm cython
pip install torchtext
pip install mojimoji
pip install attrdict
pip install pyknp

Juman ++ Installation

Das diesmal verwendete BERT Japanese Pretrained-Modell verwendet Human ++ (v2.0.0-rc2) für die morphologische Analyse des Eingabetextes. Daher entspricht dieser Artikel auch dem morphologischen Analysewerkzeug ** Human ++ **. Die Vorgehensweise zur Installation von Juman ++ ist in einem separaten Artikel zusammengefasst. Weitere Informationen finden Sie im Folgenden.

[** Zusammenfassung der JUMAN ++ - Installationsprozedur **] https://sinyblog.com/deaplearning/juman/

Vorbereitung des japanischen vorgebildeten BERT-Modells

Das BERT Japanese Pretrained-Modell kann von der folgenden URL heruntergeladen werden.

[BERT Japanese Pretrained model] http://nlp.ist.i.kyoto-u.ac.jp/index.php?BERT%E6%97%A5%E6%9C%AC%E8%AA%9EPretrained%E3 % 83% A2% E3% 83% 87% E3% 83% AB

Laden Sie ** Japanese_L-12_H-768_A-12_E-30_BPE .zip ** von "** Japanese_L-12_H-768_A-12_E-30_BPE.zip (1.6G) ****" auf den oben genannten HP herunter. Wenn Sie die Zip-Datei entpacken, sind einige Dateien enthalten, diesmal benötigen Sie jedoch die folgenden drei.

Artikel Bedeutung
bert_config.json Konfigurationsdatei für das BERT-Modell
pytorch_model.bin Pytorch Version BERT(pytorch-pretrained-BERT)Konvertiertes Modell für
vocab.txt BERT Glossar Wörterbuchdaten

Die gesamte Verzeichnisstruktur ist wie folgt.

├─data
│  └─chABSA    #chABSA json-Datei
│  └─test.tsv    #Testdaten
│  └─train.tsv    #Trainingsdaten
│  └─test_dumy.tsv  #Dummy-Daten
│  └─train_dumy.tsv #Dummy-Daten

├─utils
│  └─bert.py    #BERT-Modelldefinition
│  └─config.py  #Definition verschiedener Pfade
│  └─dataloader.py    #Für die Datenladergenerierung
│  └─predict.py    #Zum Nachdenken
│  └─predict.py    #Zum Nachdenken
│  └─tokenizer.py   #Zur morphologischen Analyse
│  └─train.py       #Zum Lernen
├─vocab      #Bert Lexikon Wörterbuch Gesang.txt
└─weights    # bert_config.json、pytorch_model.bin
└─Create_data_from_chABSA.ipynb   #tsv Datenerstellung
└─BERT Modellbildung-Lernen~Inferenz.ipynb   #Erstellung des Datenladers~Lernen~Inferenz

pytorch_model.bin(pytorch-pretrained-BERT) bert_fine_tuning_chABSA_22epoch.pth (Negative / Positive Learned Parameter File)

3. Schematische Darstellung des BERT-Modells der negativen / positiven Klassifizierung

Es ist ein schematisches Diagramm des BERT-Modells der negativen / positiven Klassifizierung, das dieses Mal implementiert werden soll.

bertネガポジ分類機の概要図.png

Das obige BERT-Modell basiert auf dem Quellcode des Buches "** Learn while make! Development Deep Learning von PyTorch **". In diesem Artikel werden die Details des BERT-Modells nicht erläutert. Wenn Sie interessiert sind, lesen Sie bitte das Buch.

Um nur die Punkte zu erklären, basiert der BERT-Quellcode selbst auf huggingface / transformers und ** alle für eine negativ-positive Klassifizierung am Ende des BERT-Modells. Eine Verbindungsschicht (linear **) wird hinzugefügt, und das Modell gibt 2 Klassenklassifikationen ** [negativ (0) oder positiv (1)] ** als Ausgabe aus. Verwenden Sie zur Klassifizierung die Merkmalsmenge des ersten Wortes [CLS] ** der eingegebenen Textdaten.

4. Erstellen eines Datensatzes für negatives / positives Lernen

chABSA-Datensatz Der Datensatz enthält 230 Datendateien im JSON-Format, aber der negative / positive Klassifikator verwendet BERT Es kann nicht als Trainingsdaten verwendet werden.

Eine JSON-Datei enthält mehrere Textdaten und die folgenden Informationen.

Artikel Bedeutung
sentence_id ID, die die Daten eindeutig identifiziert
sentence Satzdaten
opinions Einige Optionen sind {Ziel,category,porarity,from,Es sind mehrere Sätze von to} enthalten.
target Das Schlüsselwort wird im Satz für das Ziel angegeben
category Brancheninformationen
polarity Ist das Ziel-Keyword positiv oder negativ?
from, to Von welchem Zeichen zu welchem Zeichen existiert das Schlüsselwort des Ziels im Satz?

Erstellen Sie aus diesen JSON-Dateien ein tsv-Dataset, das wie folgt für das Training verwendet werden kann. Jede Zeile hat das Format "Eingabetext 0 (negativ) oder 1 (positiv)".

Auf der anderen Seite bleiben die Aussichten aufgrund von Risiken wie der wirtschaftlichen Abkühlung der chinesischen Wirtschaft, dem politischen Management der neuen US-Regierung und dem Austritt Großbritanniens aus der EU ungewiss.
Im Kosmetik- und sonstigen Warengeschäft stärken wir die Filialentwicklung durch große Filialen und arbeiten daran, Kunden durch digitale Verkaufsförderung zu gewinnen und Kunden durch Veranstaltungen mit einem Umsatz von 3.262 Millionen Yen (15 gegenüber dem Vorjahr) zu steigern..5% Abnahme) 0
Darüber hinaus nahmen die Wartungsverträge mit einem Umsatz von 6 stetig zu,952 Millionen Yen (1-Jahres-Vergleich).2% mehr) 1
In Bezug auf den Gewinn beträgt der Segmentgewinn (Betriebsgewinn) 1 aufgrund einer Zunahme der Ersatzarbeiten und der Sicherung eines stabilen Gewinns durch Wartungsverträge.,687 Millionen Yen (2 im Vergleich zum Vorjahreszeitraum).4% mehr) 1
In anderen Segmenten entwickelten sich Fahrradparksysteme mit einem Umsatz von 721 Millionen Yen (0 gegenüber dem Vorjahr) stetig..8% mehr) 1

Führen Sie zum Erstellen der Daten den Code ** Create_data_from_chABSA.ipynb ** im Jupyter-Notizbuch aus.

Durch Befolgen der Schritte werden Trainingsdaten (train.tsv) mit 1970 Sätzen und Testdaten (test.tsv) mit 843 Daten erstellt.

5. Implementierung von Tokenizer für BERT

Wir haben die BertTokenizer-Klasse für wortaufteilende Eingabesätze in ** utils \ bert.py ** implementiert. Dieses Mal werden wir den japanischen Datensatz verwenden, aber [BERT Japanese Pretrained model](http://nlp.ist.i.kyoto-u.ac.jp/index.php?BERT%E6%97%A5% E6% 9C% AC% E8% AA% 9EPretrainiert% E3% 83% A2% E3% 83% 87% E3% 83% AB) Führen Sie eine morphologische Analyse mit Human ++ gemäß den Spezifikationen durch.

Außerdem [link](http://nlp.ist.i.kyoto-u.ac.jp/index.php?BERT%E6%97%A5%E6%9C%AC%E8%AA%9EPretrained%E3 % 83% A2% E3% 83% 87% E3% 83% AB) Wie beschrieben, sind die folgenden Punkte für Japanisch angepasst.

Setzen Sie die Option ** --do_lower_case ** in der BertTokenizer-Klasse in bert.py auf ** False **.

Class BertTokenizer(object):
    #Implementierte Klasse zur Aufteilung von Satzwörtern für BERT

    def __init__(self, vocab_file, do_lower_case=False): #In False geändert (anders als im englischen Modell)

Kommentieren Sie Folgendes in der BasicTokenizer-Klasse von tokenizer.py aus

#text = self._tokenize_chinese_chars(text)  #Alle Kanji werden in einer Zeicheneinheit sein, also kommentieren Sie aus

** HumanTokenize-Klasse ** zur morphologischen Analyse mit Human ++ zu tokenizer.py hinzugefügt.

from pyknp import Juman

class JumanTokenize(object):
    """Runs JumanTokenizer."""
    
    def __init__(self):
        self.juman = Juman()

    def tokenize(self, text):
        result = self.juman.analysis(text)
        return [mrph.midasi for mrph in result.mrph_list()]

Wenn Sie die obige HumanTokenizer-Klasse verwenden, wird der Eingabetext von Human ++ wie folgt morphologisch analysiert.

cd chABSA-dataset
python
>>>from utils.tokenizer import JumanTokenize
>>>from pyknp import Juman
>>>text = "Das ordentliche Einkommen verringerte sich gegenüber dem Vorjahr um 818 Millionen Yen, hauptsächlich aufgrund eines Rückgangs der Erträge aus dem Fondsmanagement wie etwa Zinsen für Kredite 2,Es war 27.811 Millionen Yen"
>>>juman = JumanTokenize()
>>>print(juman.tokenize(text))
['gewöhnliche', 'Einnahmen', 'Ist', '、', 'Ausleihe', 'Geld', 'Interesse', 'Eine solche', '資Geld', 'Operation', 'Einnahmen', 'von', 'Verringern', 'Zu', 'Hauptgrund', 'Zu', ' 、', 'Bisherige', 'Jahr', 'Verhältnis', '818 Millionen', 'Kreis', 'Verringern', 'Shi', '2,27.811 Millionen', 'Kreis', 'Wann', 'Nari', 'まShiた']
>>>


6. Erstellen Sie DataLoader

Erstellen Sie einen DataLoader mit torchtext, um Daten für Training und Test zu generieren. Dieses Mal wird die Funktion zum Erstellen des DataLoder "** get_chABSA_DataLoaders_and_TEXT **" in ** dataloder.py ** erstellt. Verwenden Sie diese Funktion.

** get_chABSA_DataLoaders_and_TEXT ** Der Rückgabewert der Funktion lautet wie folgt.

Artikel Bedeutung
train_dl Trainingsdatensatz
val_dl Validierungsdatensatz
TEXT torchtext.data.field.Feldobjekt
dataloaders_dict Iteratorwörterbuchdaten für Trainings- und Verifizierungsdaten**※1**

** * 1 ** dataloaders_dict wird zum Lernen und Überprüfen verwendet.

Wenn Sie sich nicht sicher sind, wie Sie torchtext verwenden sollen, lesen Sie bitte den folgenden Artikel. Pytorch-Textvorverarbeitung (torchtext) [für Anfänger]

Unten finden Sie den Code, der den Dataloader generiert.

from utils.dataloader import get_chABSA_DataLoaders_and_TEXT
from utils.bert import BertTokenizer
train_dl, val_dl, TEXT, dataloaders_dict= get_chABSA_DataLoaders_and_TEXT(max_length=256, batch_size=32)

Nehmen wir die Daten aus den generierten Trainingsdaten (train_dl) und überprüfen den Inhalt.

#Funktionsprüfung Prüfen Sie anhand des Verifizierungsdatensatzes
batch = next(iter(train_dl))
print("Textform=", batch.Text[0].shape)
print("Etikettenform=", batch.Label.shape)
print(batch.Text)
print(batch.Label)

Wie unten gezeigt, werden Textdaten (maximale Länge 256) für die Stapelgröße (32 Stück) in Text (Eingabedaten) generiert. Die Eingabedaten sind numerische Listendaten, die durch Konvertieren der Wortliste in eine ID erhalten werden. Label enthält das korrekte Antwort-Label 0 (negativ) oder 1 (positiv) für den entsprechenden Satz.

Textform= torch.Size([32, 256])
Etikettenform= torch.Size([32])
(tensor([[    2,  3718,   534,  ...,     0,     0,     0],
        [    2, 17249,   442,  ...,     0,     0,     0],
        [    2,   719,  3700,  ...,     0,     0,     0],
        ...,
        [    2,   719,  3700,  ...,     0,     0,     0],
        [    2,    64,     6,  ...,     0,     0,     0],
        [    2,     1,  3962,  ...,     0,     0,     0]]), tensor([68, 48, 31, 30, 33, 89, 55, 49, 53, 29, 61, 44, 21, 69, 51, 48, 30, 32,
        54, 31, 39, 28, 27, 24, 24, 48, 21, 86, 39, 51, 71, 42]))
tensor([0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0,
        1, 1, 0, 1, 0, 1, 0, 0])

Nehmen Sie für alle Fälle einen Satz aus dem Mini-Batch und übergeben Sie die digitalisierten Listendaten an die ** ids_to_tokens ** -Methode von ** tokenizer_bert **, um den ursprünglichen Satz (Wort) wiederherzustellen.

#Überprüfen Sie den ersten Satz der Mini-Charge
tokenizer_bert = BertTokenizer(vocab_file="./vocab/vocab.txt", do_lower_case=False)
text_minibatch_1 = (batch.Text[0][1]).numpy()

#ID zum Wort zurückgeben
text = tokenizer_bert.convert_ids_to_tokens(text_minibatch_1)

print(text)

['[CLS]', 'Der Umsatz', 'Profitieren', 'Ist', '、', 'Komplett', 'Konstruktion', 'Gesamt', 'Profitieren', 'Bewertung', 'Aber', 'Verbesserung', 'tat', 'Ding', 'Von', '、', 'Bisherige', 'Verknüpfen', 'Buchhaltung', 'Jahr', 'Verhältnis', '[UNK]', '.', '[UNK]', '%', 'Erhöhen, ansteigen', 'von', '[UNK]', 'Kreis', '(', 'Bisherige', 'Verknüpfen', 'Buchhaltung', 'Jahr', 'Ist', '[UNK]', 'Kreis', ')', 'Wann', 'wurde', '[SEP]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]', '[PAD]']

Der Anfang des Satzes ist ** [CLS] **, das Ende ist ** [SEP] **, das unbekannte Wort ist ** [UNK] ** und der Teil mit weniger als 256 Zeichen ist mit ** [PAD] ** aufgefüllt. Ich werde.

Bisher haben wir die Erstellung des Datensatzes und des tatsächlich generierten Mini-Batches bestätigt.

7. Implementierung eines negativen / positiven Klassifizierungsmodells durch BERT

Als nächstes werden wir das negativ-positive Klassifizierungsmodell von BERT implementieren.

Das folgende BERT-Modell, das dieses Mal implementiert werden soll, ist in ** utils \ bert.py ** als ** BertModel-Klasse ** definiert. Verwenden Sie diese Klasse also, um das Modell zu generieren.

bertネガポジ分類機の概要図.png

Verwenden Sie die folgenden Dateien, um das Modell zu erstellen.

Artikel Erläuterung
bert_config.json BERT-Modellparameterdatei
pytorch_model.bin Geschultes BERT-Modell

Erstellen Sie zunächst ein Basis-BERT-Modell, indem Sie die Konfigurationseinstellungsdatei als Argument in der ** BertModel-Klasse ** angeben, und lernen Sie dann mit der in ** bert.py ** definierten ** set_learned_params ** -Methode. Stellen Sie die Parameter des fertigen BERT-Modells ein (** pytorch_model.bin **). Nachdem Sie ein negativ-positives Klassifizierungsmodell mit der ** BertForchABSA-Klasse ** erstellt haben, versetzen Sie es mit ** net.train () ** in den Lernmodus.

Der Code zum Generieren des Modells ist unten.

from utils.bert import get_config, BertModel,BertForchABSA, set_learned_params

#Lesen Sie die JOSN-Datei mit den Modelleinstellungen als Objektvariable
config = get_config(file_path="./weights/bert_config.json")

#Generieren Sie ein Basis-BERT-Modell
net_bert = BertModel(config)

#Geschulter Parametersatz für das BERT-Modell
net_bert = set_learned_params(
    net_bert, weights_path="./weights/pytorch_model.bin")

#Generieren Sie ein negatives / positives BERT-Klassifizierungsmodell(Vollständig verbundene Schicht zur negativ-positiven Klassifizierung am Ende des Modells (linear))Hinzufügen)
net = BertForchABSA(net_bert)

#Auf Trainingsmodus einstellen
net.train()

8. BERT-Feinabstimmungseinstellungen

In BERT's Originalarbeit sind alle 12-stufigen BertLayer-Ebenen (Self-Attention) fein abgestimmt, diesmal jedoch nur die letzte 1 Ebene + negativ-positiver Klassifikator Ist das Thema des Lernens.


#Führen Sie die Gradientenberechnung nur für das letzte BertLayer-Modul und den hinzugefügten Klassifizierungsadapter durch

# 1.Für die Gesamtgradientenberechnung auf Falsch setzen
for name, param in net.named_parameters():
    param.requires_grad = False

# 2.Es wurde nur das letzte BertLayer-Modul geändert, um eine Gradientenberechnung zu erhalten
for name, param in net.bert.encoder.layer[-1].named_parameters():
    param.requires_grad = True

# 3.Der Klassifikator (negativ oder positiv) wurde geändert, um eine Gradientenberechnung durchzuführen
for name, param in net.cls.named_parameters():
    param.requires_grad = True

Geben Sie als Nächstes den Optimierer und die Verlustfunktion an, die für das Training verwendet werden sollen.

Sowohl die letzte Schicht von BertLayer (Self-Attention) als auch der Diskriminator verwenden die Klasse ** Torch.optim.Adam **. Die Lernrate (lr) beträgt ** 5e-e ** und Betas ist der Standardwert ** (0,9, 0,999) ** (die Werte in den Nachschlagewerken werden unverändert verwendet).

Und da es sich diesmal um eine Zwei-Klassen-Klassifizierung von negativ oder positiv handelt, wird ** torch.nn.CrossEntropyLoss ** als Kriterium angegeben.


#Der ursprüngliche Teil von BERT ist die Feinabstimmung
optimizer = optim.Adam([
    {'params': net.bert.encoder.layer[-1].parameters(), 'lr': 5e-5},
    {'params': net.cls.parameters(), 'lr': 5e-5}
], betas=(0.9, 0.999))

#Einstellungen der Verlustfunktion
criterion = nn.CrossEntropyLoss()
# nn.LogSoftmax()Nach der Berechnung von nn.NLLLoss(negative log likelihood loss)Berechnung

9. BERT lernen / argumentieren

Als nächstes werden wir lernen und verifizieren. utls.py\train.pyに定義されている学習&検証用の関数train_modelを使って学習と検証を行います。 Verwenden Sie ** train.tsv (1970) ** für das Training und ** test.tsv (843) ** für die Validierung.

Das Erlernen in einer CPU-Umgebung erfordert einige Zeit. Wir empfehlen daher die Verwendung einer GPU-Umgebung wie Google Coraboratory.


#Führen Sie das Lernen / Verifizieren durch
from utils.train import train_model

#Führen Sie das Lernen / Verifizieren durch.
num_epochs = 1   #Bitte ändern Sie die Anzahl der Epochen entsprechend.
net_trained = train_model(net, dataloaders_dict,
                          criterion, optimizer, num_epochs=num_epochs)


#Speichern Sie die gelernten Netzwerkparameter(Dieses Mal wird der Dateiname unter der Annahme beschrieben, dass das Ergebnis der 22. Epoche gespeichert wird.
save_path = './weights/bert_fine_tuning_chABSA_22epoch.pth'
torch.save(net_trained.state_dict(), save_path)

Die Argumente von ** train_model ** lauten wie folgt.

Artikel Erläuterung
net BERT negatives / positives Klassifizierungsmodell
dataloaders_dict Iterator zum Lernen und Verifizieren
criterion Verlustfunktion
optimizer Optimierer
num_epochs Anzahl der Epochen

Bei der Ausführung wird die richtige Antwortrate für jeweils 10 Iterationen und Lost and Acc für jede Epoche wie unten gezeigt angezeigt.

Verwendetes Gerät: CPU
-----start-------
Iteration 10|| Loss: 0.6958 || 10iter: 294.9368 sec. ||Richtige Antwortrate dieser Iteration: 0.46875
Iteration 20|| Loss: 0.7392 || 10iter: 288.1598 sec. ||Richtige Antwortrate dieser Iteration: 0.4375
Iteration 30|| Loss: 0.6995 || 10iter: 232.9404 sec. ||Richtige Antwortrate dieser Iteration: 0.53125
Iteration 40|| Loss: 0.5975 || 10iter: 244.0613 sec. ||Richtige Antwortrate dieser Iteration: 0.6875
Iteration 50|| Loss: 0.5678 || 10iter: 243.3908 sec. ||Richtige Antwortrate dieser Iteration: 0.71875
Iteration 60|| Loss: 0.5512 || 10iter: 269.5538 sec. ||Richtige Antwortrate dieser Iteration: 0.6875
Epoch 1/1 | train |  Loss: 0.6560 Acc: 0.5975
Epoch 1/1 |  val  |  Loss: 0.5591 Acc: 0.7711

10. Lernergebnisse

Dieses Mal habe ich den MAX der Epochenzahl auf 50 gesetzt und die Genauigkeit mit den folgenden 3 Mustern verglichen.

--BertLayer (Selbstaufmerksamkeit) ** Nur die letzte Ebene ** Feinabstimmung --BertLayer (Selbstaufmerksamkeit) ** Nur die beiden hinteren Schichten ** Feinabstimmung

Die Ergebnisse sind wie folgt.

学習結果.png

Das Folgende ist eine Zusammenfassung der Bewertung.

――In diesem Modell hatte die Erhöhung der Anzahl der Feinabstimmungsziele fast keinen Einfluss auf die Verbesserung der Genauigkeit. ――Die Genauigkeit erreicht ungefähr 86%, wenn Sie sie um etwa 5 Epochen drehen, und selbst wenn Sie die Anzahl der Epochen danach erhöhen, steigt die Genauigkeit nicht signifikant an. ――Wenn es 20 Epochen überschreitet, wird das Überlernen bemerkenswert.

Am Ende war die korrekte Antwortrate MAX (** 87,76% **), wenn nur die letzte Schicht von BertLayer fein abgestimmt und ** 22epoch ** gedreht wurde.

11. Geben Sie den Testtext ein, um Vorhersagen und Aufmerksamkeit zu visualisieren

Geben Sie unter Verwendung des erlernten BERT-Negativ / Positiv-Klassifizierungsmodells einen Beispielsatz an, um den negativen / positiven Vorhersagewert und die Aufmerksamkeit (welches Wort wurde hervorgehoben?) Zu visualisieren.

Vorbereitungen

Um das TEXT-Objekt (torchtext.data.field.Field) zu verwenden, das zum Zeitpunkt der Inferenz von torchtext generiert wurde, sichern Sie das TEXT-Objekt vorübergehend in der pkl-Datei.


from utils.predict create_vocab_text
TEXT = create_vocab_text()

Wenn der obige Code ausgeführt wird, wird text.pkl unter \ chABSA-dataset \ data generiert.

Die Methode create_vocab_text ist in Predict.py definiert. Dummy-Daten (train_dumy.tsv, test_dumy.tsv) und BERT-Glossardaten (vocab.txt) unter \ chABSA-dataset \ data werden verwendet, um ein TEXT-Objekt zu generieren und dann mit pickle auszugeben.

def create_vocab_text():
    TEXT = torchtext.data.Field(sequential=True, tokenize=tokenizer_with_preprocessing, use_vocab=True,
                            lower=False, include_lengths=True, batch_first=True, fix_length=max_length, init_token="[CLS]", eos_token="[SEP]", pad_token='[PAD]', unk_token='[UNK]')
    LABEL = torchtext.data.Field(sequential=False, use_vocab=False)
    train_val_ds, test_ds = torchtext.data.TabularDataset.splits(
        path=DATA_PATH, train='train_dumy.tsv',
        test='test_dumy.tsv', format='tsv',
        fields=[('Text', TEXT), ('Label', LABEL)])
    vocab_bert, ids_to_tokens_bert = load_vocab(vocab_file=VOCAB_FILE)
    TEXT.build_vocab(train_val_ds, min_freq=1)
    TEXT.vocab.stoi = vocab_bert
    pickle_dump(TEXT, PKL_FILE)

    return TEXT

Inferenz- und Aufmerksamkeitsvisualisierung durchführen

Da die Methode zum Erstellen des trainierten Modells (** build_bert_model ) und der Inferenz ( vorhersagen **) in ** utils \ predigen.py ** definiert ist, verwenden Sie diese, um den Beispieltext einzugeben. Visualisierung des vorhergesagten Werts und der Aufmerksamkeit. Achtung verwendet IPython, um HTML zu visualisieren.

from utils.config import *
from utils.predict import predict, build_bert_model
from IPython.display import HTML, display


input_text = "Infolgedessen ist der Umsatz im laufenden konsolidierten Geschäftsjahr 1,785 Millionen Yen(Rückgang gegenüber dem Vorjahreszeitraum um 357 Millionen Yen, 16.7% Rückgang)Betriebsverlust 117 Millionen Yen(Der Rückgang um 174 Millionen Yen gegenüber dem Vorjahreszeitraum und das Betriebsergebnis um 57 Millionen Yen gegenüber dem Vorjahreszeitraum)Gewöhnlicher Verlust 112 Millionen Yen(183 Millionen Yen weniger als im gleichen Zeitraum des Vorjahres, ordentliches Einkommen 71 Millionen Yen im gleichen Zeitraum des Vorjahres), Nettoverlust der Eigentümer der Muttergesellschaft 58 Millionen Yen(116 Millionen Yen weniger als im gleichen Zeitraum des Vorjahres, Nettogewinn der Eigentümer der Muttergesellschaft 57 Millionen Yen)ist geworden"
net_trained = build_bert_model()
html_output = predict(input_text, net_trained)
print("======================Anzeige der Inferenzergebnisse======================")
print(input_text)
display(HTML(html_output))

Wenn ich den obigen Code ausführe, erhalte ich das folgende Ergebnis.

推論結果.png

12. Zeigen Sie Inferenzergebnisse und eine gemischte Matrix mit einer großen Menge von Testdaten an

Es macht automatisch Rückschlüsse unter Verwendung einer großen Menge von Testdaten und zeigt die Informationen der ** gemischten Matrix ** an, um das Ergebnis auszuwerten.

Importieren Sie zunächst die erforderlichen Module.

from utils.config import *
from utils.predict import predict2, create_vocab_text, build_bert_model
import pandas as pd
import numpy as np
from sklearn.metrics import confusion_matrix
from sklearn.metrics import accuracy_score
from sklearn.metrics import precision_score
from sklearn.metrics import recall_score
from sklearn.metrics import f1_score

Gemischte Matrizen werden mit ** sklearn ** angezeigt. Wir haben auch eine Methode Predict2 in Utils \ Predict.py hinzugefügt, die nur die vorhergesagten Werte (Preds) zurückgibt.

def predict2(input_text, net_trained):
    TEXT = pickle_load(PKL_FILE)   #Laden von Vokabeldaten
    input = conver_to_model_format(input_text, TEXT)
    input_pad = 1  #In der Wort-ID'<pad>':Weil es 1 ist
    input_mask = (input != input_pad)
    outputs, attention_probs = net_trained(input, token_type_ids=None, attention_mask=None,
                                       output_all_encoded_layers=False, attention_show_flg=True)
    _, preds = torch.max(outputs, 1)  #Etikett vorhersagen
    #html_output = mk_html(input, preds, attention_probs, TEXT)  #HTML-Erstellung
    return preds

Die einzugebenden Daten sind ** test.csv file ** und die folgenden Daten werden vorbereitet.

testデータ.png

Lesen Sie als nächstes die obige test.csv mit Pandas, geben Sie dem trainierten BERT-Modell nacheinander die Sätze der Spalte ** INPUT **, treffen Sie eine negative / positive Beurteilung und speichern Sie das Vorhersageergebnis in der Spalte ** PREDICT **. .. Speichern Sie es nach der Verarbeitung bis zum Ende als ** prognostizierte_test.csv **.

df = pd.read_csv("test.csv", engine="python", encoding="utf-8-sig")
net_trained.eval()  #Im Inferenzmodus.

for index, row in df.iterrows():
    df.at[index, "PREDICT"] = predict(row['INPUT'], net_trained).numpy()[0]  #Im Fall einer GPU-Umgebung ".cpu().numpy()Bitte.
    
df.to_csv("predicted_test .csv", encoding="utf-8-sig", index=False)

Predicted_test.csv mit den folgenden hinzugefügten Vorhersageergebnissen wird generiert.

test2データ.png

Schließlich werden die gemischten Matrixinformationen aus dem Ergebnis dieser CSV-Datei angezeigt.

#Anzeige (Auswertung) der gemischten Matrix

y_true =[]
y_pred =[]
df = pd.read_csv("predicted_test .csv", engine="python", encoding="utf-8-sig")
for index, row in df.iterrows():
    if row['LABEL'] == 0:
        y_true.append("negative")
    if row['LABEL'] ==1:
        y_true.append("positive")
    if row['PREDICT'] ==0:
        y_pred.append("negative")
    if row['PREDICT'] ==1:
        y_pred.append("positive")

    
print(len(y_true))
print(len(y_pred))


#Verwirrte Matrix(confusion matrix)Erhalten
labels = ["negative", "positive"]
from sklearn.metrics import confusion_matrix
cm = confusion_matrix(y_true, y_pred, labels=labels)

#In Datenrahmen konvertieren
cm_labeled = pd.DataFrame(cm, columns=labels, index=labels)

#Ergebnisse anzeigen
cm_labeled

Eine gemischte Matrix ähnlich der folgenden wird angezeigt. 混合行列.png

Die Ansicht ist, dass das Negative und das Positive auf der linken Seite die Beschriftungen der tatsächlichen Daten sind und das Negative und das Positive in vertikaler Richtung die vorhergesagten Werte sind. Zum Beispiel repräsentiert die Zahl "** 62 **" die Anzahl der negativen Daten, die fälschlicherweise als positiv vorhergesagt wurden.

Als nächstes werden die richtige Antwortrate, Präzisionsrate, Rückrufrate und der F-Wert mit dem folgenden Code angezeigt.

y_true =[]
y_pred =[]
df = pd.read_csv("predicted_test .csv", engine="python", encoding="utf-8-sig")
for index, row in df.iterrows():
    y_true.append(row["LABEL"])
    y_pred.append(row["PREDICT"])
        
print("Richtige Antwortrate (Verhältnis der richtigen Antworten aus allen Stichproben)={}%".format((round(accuracy_score(y_true, y_pred),2)) *100 ))
print("Anpassungsrate (Wahrscheinlichkeit, positiv zu sein, was als positiv vorhergesagt wurde)={}%".format((round(precision_score(y_true, y_pred),2)) *100 ))
print("Rückrufrate (Wahrscheinlichkeit für positive Daten als positiv vorausgesagt)={}%".format((round(recall_score(y_true, y_pred),2)) *100 ))
print("F1 (harmonischer Durchschnitt von Präzision und Rückruf)={}%".format((round(f1_score(y_true, y_pred),2)) *100 ))

#Ausführungsergebnis

Richtige Antwortrate (Verhältnis der richtigen Antworten aus allen Stichproben)=76.0%
Anpassungsrate (Wahrscheinlichkeit, positiv zu sein, was als positiv vorhergesagt wurde)=85.0%
Rückrufrate (Wahrscheinlichkeit für positive Daten als positiv vorausgesagt)=71.0%
F1 (harmonischer Durchschnitt von Präzision und Rückruf)=78.0%

13. Zusammenfassung

Dieses Mal haben wir eine vollständig verbundene Schicht (linear) hinzugefügt, die basierend auf dem BERT-Modell Negativ und Positiv beurteilt und zu einer binären Klassifizierung gemacht hat. Es scheint jedoch, dass sie auf verschiedene Aufgaben wie die mehrwertige Klassifizierung und die Anwendung auf die Qualitätssicherung angewendet werden kann. Ich möchte in Zukunft herausfordern. ** * Hinzugefügt am 25.12.2019 ** Wenn Sie daran interessiert sind, das Django REST-Framework mithilfe des in diesem Artikel erstellten BERT-Negativ / Positiv-Klassifikators zu implementieren, ** "Django-Adventskalender 2019 - Qiita-Artikel zum 20. Tag" Siehe / items / 30e10a3db76c6f7c5b4d) **.

Recommended Posts

Erstellung eines negativen / positiven Klassifikators mit BERT
Negative / positive Beurteilung von Sätzen durch BERT und Visualisierung von Gründen
Negative / Positive Analyse 1 Anwendung der Textanalyse
Satzvektorerstellung mit BERT (Keras BERT)
Flexible Animationserstellung mit Animation.FuncAnimation von matplotlib
Python: Negative / Positive Analyse: Twitter Negative / Positive Analyse mit RNN-Teil 1
Scraping & Negative Positive Analyse von Bunharu Online-Artikeln
[Python] Verwenden der Linien-API [1. Erstellung des Beauty-Bots]
[Python] Zusammenfassung der Methode zur Tabellenerstellung mit DataFrame (Pandas)
Negative / Positive Analyse 2 Twitter Negative / Positive Analyse (1)
Negative / Positive Analyse 3 Twitter Negative / Positive Analyse (2)
Beispiel für die Verwendung von Lambda
Negative / positive Beurteilung von Sätzen und Visualisierung von Gründen durch Transformer
Beurteilung der emotionalen Polarität von Sätzen mit dem Textklassifikator fastText