[PYTHON] Création d'un classificateur négatif / positif à l'aide de BERT

Cet article est l'article du 25ème jour du "Calendrier de l'Avent du traitement du langage naturel 2019 - Qiita".

C'est siny.

Dans cet article, nous avons résumé la création d'un classificateur négatif-positif utilisant BERT, qui joue un rôle majeur dans le traitement du langage naturel à partir de 2019.

introduction

Je pense que les connaissances sur BERT ont été largement diffusées dans les livres, les blogs, Qiita, etc. Cependant, la plupart des ensembles de données pouvant être utilisés pour le traitement du langage naturel sont basés sur l'anglais, et il n'y a pas beaucoup d'ensembles de données japonais, il y a donc peu de cas et d'informations sur l'utilisation de BERT en utilisant du texte japonais. se sentait.

Actuellement, je pense que ce qui suit sont les principaux ensembles de données japonais qui peuvent être utilisés gratuitement.

Lorsque je cherchais "** Existe-t-il un ensemble de données contenant une certaine quantité de données et des données de texte japonais pouvant être utilisées gratuitement? **", chABSA-dataset J'ai trouvé un ensemble de données japonais (environ 2800 données) appelé chakki-works / chABSA-dataset).

chABSA-dataset est un ensemble de données japonais créé à partir des rapports sur les titres des sociétés cotées. Chaque phrase contient non seulement une classification émotionnelle négative / positive, mais également des informations qui expriment la perspective de «ce qui» est négatif / positif. Voici des exemples de données de ** chABSA-dataset **.

{
  "header": {
    "document_id": "E00008",
    "document_name": "Hokuto Co., Ltd.",
    "doc_text": "Rapport sur les valeurs mobilières",
    "edi_id": "E00008",
    "security_code": "13790",
    "category33": "Pêche / Agriculture et foresterie",
    "category17": "Nourriture",
    "scale": "6"
  },
  "sentences": [
    {
      "sentence_id": 0,
      "sentence": "Au cours de l'exercice financier consolidé en cours, l'économie japonaise améliorera sa performance d'entreprise et son environnement d'emploi / de revenu grâce aux politiques économiques du gouvernement et aux mesures d'assouplissement monétaire de la Banque japonaise....",
      "opinions": [
        {
          "target": "L'économie japonaise",
          "category": "NULL#general",
          "polarity": "neutral",
          "from": 11,
          "to": 16
        },
        {
          "target": "La performance de l'entreprise",
          "category": "NULL#general",
          "polarity": "positive",
          "from": 38,
          "to": 42
        },...
      ],
    },
    {
      "sentence_id": 1,
      "sentence": "L'environnement qui entoure le Groupe est tel que si les salaires réels sont atones, les consommateurs...",
      "opinions": [
        {
          "target": "Salaire réel",
          "category": "NULL#general",
          "polarity": "negative",
          "from": 15,
          "to": 19
        },...
      ]
    },...
  ]
}

Avec ** ch ABSA-dataset **, il y a des milliers de données, et il y a des valeurs qui expriment des émotions, donc il peut être utilisé pour une classification négative-positive? », J'ai donc créé un classificateur BERT négatif-positif avec cet ensemble de données. Je l'ai essayé.

Tout le code d'implémentation expliqué dans cet article est sur github ci-dessous, veuillez donc le cloner comme il convient. De plus, chaque processus est décrit dans ** BERT model creation-learning-inference.ipynb ** sur github, veuillez donc vous y référer comme il convient.

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

table des matières

  1. Prémisse
  2. Construction de l'environnement
  3. Schéma de principe du modèle BERT de classification négative / positive
  4. Créer un ensemble de données pour un apprentissage négatif / positif
  5. Implémentation de Tokenizer pour BERT
  6. Créer DataLoader
  7. Application du modèle de classification négative / positive par le BERT
  8. Paramètres de réglage fin de BERT
  9. Apprentissage / raisonnement BERT
  10. Résultats d'apprentissage
  11. Saisissez le texte de test pour visualiser les prédictions et l'attention
  12. Afficher les résultats d'inférence et la matrice mixte avec une grande quantité de données de test
  13. Résumé

1. Prémisse

Dans cet article, nous allons créer un classificateur négatif-positif basé sur les hypothèses suivantes.

article sens
OS Ubuntu
Modèle BERT Publié par l'Université de Kyotopytorch-pretrained-Modèle BERTLe réglage fin est effectué en fonction de.
Analyse morphologique Juman++ (v2.0.0-rc2) or (v2.0.0-rc3)
Bibliothèque Pytorch

2. Construction de l'environnement

Créez un environnement dans lequel vous pouvez utiliser le modèle pré-entraîné japonais BERT avec PyTorch.

Installation de la bibliothèque


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

Installation de Juman ++

Le modèle pré-entraîné japonais BERT utilisé cette fois utilise Human ++ (v2.0.0-rc2) pour l'analyse morphologique du texte d'entrée, de sorte que cet article fait également correspondre l'outil d'analyse morphologique à ** Human ++ **. La procédure d'installation de Juman ++ est résumée dans un article séparé, veuillez donc vous référer à ce qui suit.

[** Résumé de la procédure d'installation de JUMAN ++ **] https://sinyblog.com/deaplearning/juman/

Préparation du modèle pré-entraîné japonais BERT

Le modèle BERT Japanese Pretrained peut être téléchargé à partir de l'URL suivante.

[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

Téléchargez ** Japanese_L-12_H-768_A-12_E-30_BPE .zip ** à partir de "** Japanese_L-12_H-768_A-12_E-30_BPE.zip (1.6G) ****" sur le HP ci-dessus. Lorsque vous décompressez le fichier zip, certains fichiers sont inclus, mais cette fois, vous avez besoin des trois suivants.

article sens
bert_config.json Fichier de configuration pour le modèle BERT
pytorch_model.bin pytorch version BERT(pytorch-pretrained-BERT)Modèle converti pour
vocab.txt Données du dictionnaire du glossaire BERT

La structure générale des répertoires est la suivante.

├─data
│  └─chABSA    #chABSA fichier json
│  └─test.tsv    #Données de test
│  └─train.tsv    #Données d'entraînement
│  └─test_dumy.tsv  #Données factices
│  └─train_dumy.tsv #Données factices

├─utils
│  └─bert.py    #Définition du modèle BERT
│  └─config.py  #Définition des différents chemins
│  └─dataloader.py    #Pour la génération de dataloader
│  └─predict.py    #Pour raisonner
│  └─predict.py    #Pour raisonner
│  └─tokenizer.py   #Pour l'analyse morphologique
│  └─train.py       #Pour apprendre
├─vocab      #bert lexique dictionnaire vocal.txt
└─weights    # bert_config.json、pytorch_model.bin
└─Create_data_from_chABSA.ipynb   #création de données tsv
└─ Création-apprentissage du modèleBERT~inférence.ipynb   #Création du chargeur de données~Apprentissage~inférence

pytorch_model.bin(pytorch-pretrained-BERT) bert_fine_tuning_chABSA_22epoch.pth (fichier de paramètres appris négatifs / positifs)

3. Diagramme schématique du modèle BERT de classification négative / positive

Il s'agit d'un diagramme schématique du modèle BERT de classification négative / positive à mettre en œuvre cette fois.

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

Le modèle BERT ci-dessus est créé à partir du code source du livre "** Apprenez en faisant! Développement en apprentissage profond par PyTorch **". Cet article n'explique pas les détails du modèle BERT, donc si vous êtes intéressé, veuillez vous référer au livre.

Pour expliquer uniquement les points, le code source BERT lui-même est basé sur huggingface / transformers, et ** tout pour la classification négative-positive à la fin du modèle BERT. Une couche de connexion (linéaire **) est ajoutée et le modèle génère 2 classifications de classe ** [négatif (0) ou positif (1)] ** en sortie. Pour la classification, utilisez la quantité de caractéristiques du premier mot [CLS] ** des données de phrase saisies.

4. Créer un ensemble de données pour un apprentissage négatif / positif

chABSA-dataset Il y a 230 fichiers de données au format json dans l'ensemble de données, mais tel quel, le classificateur négatif / positif utilisant BERT Il ne peut pas être utilisé comme données d'entraînement.

Un fichier json contient plusieurs données texte et contient les informations suivantes.

article sens
sentence_id ID qui identifie de manière unique les données
sentence Données de phrase
opinions Certaines options sont {target,category,porarity,from,Plusieurs ensembles de à} sont inclus.
target Le mot clé est spécifié dans la phrase pour la cible
category Information sur l'industrie
polarity Le mot clé cible est-il positif ou négatif?
from, to De quel caractère à quel caractère le mot-clé de cible existe-t-il dans la phrase?

À partir de ces fichiers json, créez un ensemble de données tsv qui peut être utilisé pour l'entraînement comme suit. Chaque ligne est au format "texte d'entrée 0 (négatif) ou 1 (positif)".

En revanche, les perspectives restent incertaines en raison de risques tels que le ralentissement économique de l'économie chinoise, la gestion politique de la nouvelle administration américaine et le retrait du Royaume-Uni de l'UE.
Dans le secteur des cosmétiques et des produits divers, nous renforçons le développement des magasins dans les grands magasins et travaillons pour attirer les clients grâce à la promotion numérique des ventes et augmenter les clients en organisant des événements, avec un chiffre d'affaires de 3 262 millions de yens (15 sur un an)..Diminution de 5%) 0
De plus, les contrats de maintenance ont augmenté régulièrement, avec un chiffre d'affaires de 6,952 millions de yens (comparaison d'une année sur l'autre).Augmentation de 2%) 1
Concernant les bénéfices, le bénéfice sectoriel (résultat opérationnel) est de 1 en raison d'une augmentation des travaux de remplacement et de la stabilité des bénéfices grâce à des contrats de maintenance.,687 millions de yens (2 par rapport à la même période de l'année précédente).Augmentation de 4%) 1
Dans les autres segments, les systèmes de stationnement pour vélos ont enregistré une performance constante, avec des ventes de 721 millions de yens (0 d'une année sur l'autre)..Augmentation de 8%) 1

Pour créer les données, exécutez le code ** Create_data_from_chABSA.ipynb ** dans le notebook Jupyter.

Si vous suivez les étapes, vous aurez des données d'entraînement (train.tsv) avec 1970 phrases et des données de test (test.tsv) avec 843 données.

5. Implémentation de Tokenizer pour BERT

Nous avons implémenté la classe BertTokenizer pour les phrases d'entrée de fractionnement de mots dans ** utils \ bert.py **. Cette fois, nous utiliserons l'ensemble de données japonais, mais [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) Utiliser Human ++ pour l'analyse morphologique selon les spécifications.

Aussi, [lien](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) Comme décrit, les points suivants sont personnalisés pour le japonais.

Définissez l'option ** --do_lower_case ** sur ** False ** dans la classe BertTokenizer de bert.py.

Class BertTokenizer(object):
    #Implémentation de la classe de fractionnement de mots de phrase pour BERT

    def __init__(self, vocab_file, do_lower_case=False): #Changé en faux (différent du modèle anglais)

Commentez ce qui suit dans la classe BasicTokenizer de tokenizer.py

#text = self._tokenize_chinese_chars(text)  #Tous les kanji seront dans une unité de caractère, alors commentez

Ajout de la ** classe HumanTokenize ** à l'analyse morphologique avec Human ++ dans tokenizer.py.

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()]

Si vous utilisez la classe HumanTokenizer ci-dessus, le texte d'entrée sera analysé morphologiquement par Human ++ comme suit.

cd chABSA-dataset
python
>>>from utils.tokenizer import JumanTokenize
>>>from pyknp import Juman
>>>text = "Les revenus ordinaires ont diminué de 818 millions de yens par rapport à l'année précédente, principalement en raison d'une baisse des revenus de gestion de fonds tels que les intérêts sur les prêts 2,C'était 27811 millions de yens"
>>>juman = JumanTokenize()
>>>print(juman.tokenize(text))
['Ordinaire', 'Revenu', 'Est', '、', 'Prêt', 'Argent', 'Intérêt', 'Tel', '資Argent', 'Opération', 'Revenu', 'de', 'Diminution', 'À', 'La cause principale', 'À', ' 、', 'Avant', 'année', 'rapport', '818 millions', 'Cercle', 'Diminution', 'Shi', '2,27 811 millions', 'Cercle', 'Quand', 'Nari', 'まShiた']
>>>


6. Créer DataLoader

Créez un DataLoader avec torchtext pour générer des données pour la formation et les tests. Cette fois, la fonction "** get_chABSA_DataLoaders_and_TEXT **" pour créer DataLoder est créée dans ** dataloder.py **, utilisez donc ceci.

** get_chABSA_DataLoaders_and_TEXT ** La valeur de retour de la fonction est la suivante.

article sens
train_dl Ensemble de données de formation
val_dl Ensemble de données de validation
TEXT torchtext.data.field.Objet de champ
dataloaders_dict Données de dictionnaire d'itérateur pour les données de formation et de vérification**※1**

** * 1 ** dataloaders_dict est utilisé pour l'apprentissage et la vérification.

Si vous ne savez pas comment utiliser Torchtext, veuillez vous référer à l'article suivant. Prétraitement du texte Pytorch (texte de la torche) [pour les débutants]

Voici le code qui génère le Dataloader.

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)

Retirez les données des données d'entraînement générées (train_dl) et vérifiez le contenu.

#Contrôle de fonctionnement Vérifier avec l'ensemble de données de vérification
batch = next(iter(train_dl))
print("Forme du texte=", batch.Text[0].shape)
print("Forme d'étiquette=", batch.Label.shape)
print(batch.Text)
print(batch.Label)

Comme indiqué ci-dessous, les données texte (la longueur maximale est de 256) pour la taille du lot (32 pièces) sont générées dans le texte (données d'entrée). Les données d'entrée sont des données de liste numérique obtenues en convertissant la liste de mots en un identifiant. L'étiquette contient l'étiquette de réponse correcte de 0 (négatif) ou 1 (positif) pour la phrase correspondante.

Forme du texte= torch.Size([32, 256])
Forme d'étiquette= 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])

Au cas où, prenez une phrase du mini-lot et transmettez les données de la liste numérisée à la méthode ** ids_to_tokens ** de ** tokenizer_bert ** pour restaurer la phrase d'origine (mot).

#Vérifiez la première phrase du mini lot
tokenizer_bert = BertTokenizer(vocab_file="./vocab/vocab.txt", do_lower_case=False)
text_minibatch_1 = (batch.Text[0][1]).numpy()

#Renvoyer l'ID au mot
text = tokenizer_bert.convert_ids_to_tokens(text_minibatch_1)

print(text)

['[CLS]', 'Ventes', 'Profit', 'Est', '、', 'Achevée', 'Construction', 'Total', 'Profit', 'taux', 'Mais', 'Amélioration', 'fait', 'chose', 'De', '、', 'Avant', 'Mise en relation', 'Comptabilité', 'année', 'rapport', '[UNK]', '.', '[UNK]', '%', 'Augmenter', 'de', '[UNK]', 'Cercle', '(', 'Avant', 'Mise en relation', 'Comptabilité', 'année', 'Est', '[UNK]', 'Cercle', ')', 'Quand', 'devenu', '[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]']

Le début de la phrase est ** [CLS] **, la fin est ** [SEP] **, le mot inconnu est ** [UNK] ** et la partie de moins de 256 caractères est complétée par ** [PAD] **. Je vais.

Jusqu'à présent, nous avons confirmé la création de l'ensemble de données et du mini-lot réellement généré.

7. Application du modèle de classification négative / positive par le BERT

Ensuite, nous implémenterons le modèle de classification négatif-positif de BERT.

Le modèle BERT suivant implémenté cette fois est défini comme la ** classe BertModel ** dans ** utils \ bert.py **, donc cette classe est utilisée pour générer le modèle.

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

Utilisez les fichiers suivants pour créer le modèle.

article La description
bert_config.json Fichier de paramètres du modèle BERT
pytorch_model.bin Modèle BERT formé

Commencez par créer un modèle BERT de base en spécifiant le fichier de paramètres de configuration comme argument dans la ** classe BertModel **, puis apprenez à utiliser la méthode ** set_learned_params ** définie dans ** bert.py . Définissez les paramètres du modèle BERT terminé ( pytorch_model.bin **). Ensuite, après avoir généré un modèle de classification négatif-positif en utilisant la ** classe BertForchABSA **, mettez-le en mode apprentissage avec ** net.train () **.

Le code pour générer le modèle est ci-dessous.

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

#Lire le fichier JOSN des paramètres du modèle en tant que variable d'objet
config = get_config(file_path="./weights/bert_config.json")

#Générer le modèle BERT de base
net_bert = BertModel(config)

#Jeu de paramètres formés pour le modèle BERT
net_bert = set_learned_params(
    net_bert, weights_path="./weights/pytorch_model.bin")

#Générer un modèle de classification BERT négatif / positif(Couche entièrement connectée pour la classification négative-positive à la fin du modèle (linéaire))Ajouter)
net = BertForchABSA(net_bert)

#Mettre en mode entraînement
net.train()

8. Paramètres de réglage fin de BERT

Dans l'article original de BERT, toutes les couches BertLayer (Self-Attention) à 12 étages sont affinées, mais cette fois seulement la dernière couche + classificateur négatif-positif Est le sujet de l'apprentissage.


#Effectuer le calcul du gradient uniquement pour le dernier module BertLayer et l'adaptateur de classification ajouté

# 1.Définir sur False pour le calcul du gradient global
for name, param in net.named_parameters():
    param.requires_grad = False

# 2.Changé seulement le dernier module BertLayer pour avoir le calcul de gradient
for name, param in net.bert.encoder.layer[-1].named_parameters():
    param.requires_grad = True

# 3.Changement du classificateur (négatif ou positif) pour avoir un calcul de gradient
for name, param in net.cls.named_parameters():
    param.requires_grad = True

Ensuite, spécifiez l'optimiseur et la fonction de perte à utiliser pour l'entraînement.

La couche finale de BertLayer (Self-Attention) et le discriminateur utilisent la classe ** Torch.optim.Adam **. Le taux d'apprentissage (lr) est ** 5e-e **, et bêtas est la valeur par défaut ** (0,9, 0,999) ** (les valeurs des ouvrages de référence sont utilisées telles quelles).

Et comme il s'agit cette fois d'une classification à deux classes de négatif ou positif, ** torch.nn.CrossEntropyLoss ** est spécifié pour le critère.


#La partie originale de BERT est un réglage fin
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))

#Paramètres de la fonction de perte
criterion = nn.CrossEntropyLoss()
# nn.LogSoftmax()Après avoir calculé nn.NLLLoss(negative log likelihood loss)Calculer

9. Apprentissage / raisonnement BERT

Ensuite, nous effectuerons l'apprentissage et la vérification. utls.py\train.pyに定義されている学習&検証用の関数train_modelを使って学習と検証を行います。 Utilisez ** train.tsv (1970) ** pour la formation et ** test.tsv (843) ** pour la validation.

L'apprentissage dans un environnement CPU prend du temps, nous vous recommandons donc d'utiliser un environnement GPU tel que Google Coraboratory.


#Effectuer l'apprentissage / la vérification
from utils.train import train_model

#Effectuer l'apprentissage / la vérification.
num_epochs = 1   #Veuillez modifier le nombre d'époques le cas échéant.
net_trained = train_model(net, dataloaders_dict,
                          criterion, optimizer, num_epochs=num_epochs)


#Enregistrer les paramètres réseau appris(Cette fois, le nom du fichier est décrit en supposant que le résultat du virage 22 est enregistré)
save_path = './weights/bert_fine_tuning_chABSA_22epoch.pth'
torch.save(net_trained.state_dict(), save_path)

Les arguments de ** train_model ** sont les suivants.

article La description
net Modèle de classification BERT négatif / positif
dataloaders_dict Itérateur pour l'apprentissage et la vérification
criterion Fonction de perte
optimizer Optimiseur
num_epochs Nombre d'époques

Une fois exécuté, le taux de réponse correct pour chaque 10 itérations et Lost et Acc pour chaque Epoch sera affiché comme indiqué ci-dessous.

Appareil utilisé: cpu
-----start-------
Itération 10|| Loss: 0.6958 || 10iter: 294.9368 sec. ||Taux de réponse correct de cette itération: 0.46875
Itération 20|| Loss: 0.7392 || 10iter: 288.1598 sec. ||Taux de réponse correct de cette itération: 0.4375
Itération 30|| Loss: 0.6995 || 10iter: 232.9404 sec. ||Taux de réponse correct de cette itération: 0.53125
Itération 40|| Loss: 0.5975 || 10iter: 244.0613 sec. ||Taux de réponse correct de cette itération: 0.6875
Itération 50|| Loss: 0.5678 || 10iter: 243.3908 sec. ||Taux de réponse correct de cette itération: 0.71875
Itération 60|| Loss: 0.5512 || 10iter: 269.5538 sec. ||Taux de réponse correct de cette itération: 0.6875
Epoch 1/1 | train |  Loss: 0.6560 Acc: 0.5975
Epoch 1/1 |  val  |  Loss: 0.5591 Acc: 0.7711

10. Résultats d'apprentissage

Cette fois, j'ai mis le MAX du nombre d'époque à 50 et comparé la précision avec les 3 modèles suivants.

--BertLayer (Self-Attention) ** Seulement la couche finale ** Réglage fin --BertLayer (Self-Attention) ** Seulement les deux couches arrière ** Réglage fin

Les résultats sont les suivants.

学習結果.png

Voici un résumé de l'évaluation.

―― Dans ce modèle, l'augmentation du nombre de cibles de réglage fin n'avait pratiquement aucun effet sur l'amélioration de la précision. ――La précision atteint environ 86% lorsque vous tournez environ 5 époques, et même si vous augmentez le nombre d'époques après cela, la précision n'augmente pas de manière significative. ――Quand il dépasse 20 époques, le surapprentissage devient remarquable.

En fin de compte, le taux de réponse correcte était MAX (** 87,76% **) lorsque seule la couche finale de BertLayer était affinée et transformée en ** 22epoch **.

11. Saisissez le texte de test pour visualiser les prédictions et l'attention

En utilisant le modèle de classification BERT négatif / positif appris, donnez un exemple de phrase pour visualiser la valeur de prédiction négative / positive et Attention (quel mot a été souligné?).

Préparation préalable

Afin d'utiliser l'objet TEXT (torchtext.data.field.Field) généré par torchtext au moment de l'inférence, vider temporairement l'objet TEXT dans le fichier pkl.


from utils.predict create_vocab_text
TEXT = create_vocab_text()

Lorsque le code ci-dessus est exécuté, text.pkl sera généré sous \ chABSA-dataset \ data.

La méthode create_vocab_text est définie dans predict.py. Les données factices (train_dumy.tsv, test_dumy.tsv) et les données du glossaire BERT (vocab.txt) sous \ chABSA-dataset \ data sont utilisées pour générer un objet TEXT puis sortir avec pickle.

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

Effectuer l'inférence et la visualisation de l'attention

Étant donné que la méthode de construction du modèle entraîné (** build_bert_model ) et la méthode d'inférence ( prédire **) sont définies dans ** utils \ prédire.py **, utilisez ceci pour saisir l'exemple de texte. Pour visualiser la valeur prédite et Attention. Attention utilise IPython pour visualiser le HTML.

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


input_text = "En conséquence de ce qui précède, le chiffre d'affaires de l'exercice consolidé en cours 1,785 millions de yens(357 millions de yens par rapport à la même période de l'année précédente, 16.Diminution de 7%), Perte d'exploitation 117 millions de yens(174 millions de yens de diminution par rapport à la même période de l'année précédente, le bénéfice d'exploitation de 57 millions de yens au cours de la même période de l'année précédente), Perte ordinaire 112 millions de yens(183 millions de yens en baisse par rapport à la même période de l'année précédente, revenu ordinaire 71 millions de yens au cours de la même période de l'année précédente), Perte nette attribuable aux propriétaires de la société mère 58 millions de yens(Une baisse de 116 millions de yens d'une année sur l'autre, un bénéfice net attribuable aux propriétaires de la société mère de 57 millions de yens)est devenu"
net_trained = build_bert_model()
html_output = predict(input_text, net_trained)
print("======================Affichage des résultats d'inférence======================")
print(input_text)
display(HTML(html_output))

Lorsque j'exécute le code ci-dessus, j'obtiens le résultat suivant.

推論結果.png

12. Afficher les résultats de l'inférence et la matrice mixte avec une grande quantité de données de test

Il effectue automatiquement des inférences en utilisant une grande quantité de données de test et affiche les informations de la ** matrice mixte ** pour évaluer le résultat.

Tout d'abord, importez les modules requis.

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

Les matrices mixtes sont affichées en utilisant ** sklearn **. Nous avons également ajouté une méthode prédict2 dans utils \ predict.py qui ne renvoie que les valeurs prédites (preds).

def predict2(input_text, net_trained):
    TEXT = pickle_load(PKL_FILE)   #Chargement des données de vocabulaire
    input = conver_to_model_format(input_text, TEXT)
    input_pad = 1  #Dans le mot ID'<pad>':Parce que c'est 1
    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)  #Étiquette de prédiction
    #html_output = mk_html(input, preds, attention_probs, TEXT)  #Création HTML
    return preds

Les données à saisir sont le ** fichier test.csv ** et les données suivantes sont préparées.

testデータ.png

Ensuite, lisez le test.csv ci-dessus avec des pandas, donnez les phrases de ** INPUT column ** au modèle BERT entraîné une par une, faites un jugement négatif / positif et stockez le résultat de la prédiction dans la colonne ** PREDICT **. .. Après le traitement jusqu'à la fin, enregistrez-le sous ** predicted_test.csv **.

df = pd.read_csv("test.csv", engine="python", encoding="utf-8-sig")
net_trained.eval()  #En mode inférence.

for index, row in df.iterrows():
    df.at[index, "PREDICT"] = predict(row['INPUT'], net_trained).numpy()[0]  #Dans le cas d'un environnement GPU, ".cpu().numpy()S'il vous plaît.
    
df.to_csv("predicted_test .csv", encoding="utf-8-sig", index=False)

Predicted_test.csv avec les résultats de prédiction suivants ajoutés est généré.

test2データ.png

Enfin, les informations de matrice mixte sont affichées à partir du résultat de ce fichier csv.

#Affichage (évaluation) de la matrice mixte

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))


#Matrice confuse(confusion matrix)Avoir
labels = ["negative", "positive"]
from sklearn.metrics import confusion_matrix
cm = confusion_matrix(y_true, y_pred, labels=labels)

#Convertir en bloc de données
cm_labeled = pd.DataFrame(cm, columns=labels, index=labels)

#Voir les résultats
cm_labeled

Une matrice mixte semblable à la suivante s'affiche. 混合行列.png

Le point de vue est que le négatif et le positif à gauche sont les étiquettes des données réelles, et le négatif et le positif dans la direction verticale sont les valeurs prédites. Par exemple, le nombre «** 62 **» représente le nombre de données négatives qui ont été prédites par erreur comme positives.

Ensuite, le taux de réponse, le taux de précision, le taux de rappel et la valeur F corrects sont affichés avec le code suivant.

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("Taux de réponse correcte (ratio de réponses correctes sur tous les échantillons)={}%".format((round(accuracy_score(y_true, y_pred),2)) *100 ))
print("Taux d'adaptation (probabilité d'être positif dans ce qui était prévu comme positif)={}%".format((round(precision_score(y_true, y_pred),2)) *100 ))
print("Taux de rappel (probabilité prédite positive pour les données positives)={}%".format((round(recall_score(y_true, y_pred),2)) *100 ))
print("F1 (moyenne harmonique de précision et de rappel)={}%".format((round(f1_score(y_true, y_pred),2)) *100 ))

#Résultat d'exécution

Taux de réponse correcte (ratio de réponses correctes sur tous les échantillons)=76.0%
Taux d'adaptation (probabilité d'être positif dans ce qui était prévu comme positif)=85.0%
Taux de rappel (probabilité prédite positive pour les données positives)=71.0%
F1 (moyenne harmonique de précision et de rappel)=78.0%

13. Résumé

Cette fois, nous avons ajouté une couche entièrement connectée (linéaire) qui juge négatif et positif basé sur le modèle BERT et en a fait une classification binaire, mais il semble qu'elle puisse être appliquée à diverses tâches telles que la classification à valeurs multiples et l'application au contrôle qualité. , Je voudrais contester à l'avenir. ** * Ajouté 2019/12/25 ** Si vous souhaitez implémenter le framework Django REST à l'aide du classificateur négatif / positif BERT créé dans cet article, ** "Django Advent Calendar 2019 - Qiita 20th Day Article" Veuillez consulter / items / 30e10a3db76c6f7c5b4d) **.

Recommended Posts

Création d'un classificateur négatif / positif à l'aide de BERT
Jugement négatif / positif des phrases par BERT et visualisation des motifs
Analyse négative / positive 1 Application de l'analyse de texte
Création de vecteurs de phrases avec BERT (Keras BERT)
Création d'animation flexible à l'aide de l'animation.FuncAnimation de matplotlib
Python: analyse négative / positive: analyse négative / positive de Twitter à l'aide de RNN-Partie 1
Raclage et analyse positive négative des articles en ligne Bunharu
[Python] Utilisation de l'API Line [1ère création de Beauty Bot]
[Python] Résumé de la méthode de création de table utilisant DataFrame (pandas)
Analyse négative / positive 2 Analyse négative / positive Twitter (1)
Analyse négative / positive 3 Analyse négative / positive de Twitter (2)
Exemple d'utilisation de lambda
Jugement négatif / positif des phrases et visualisation des motifs par Transformer
Jugement de la polarité émotionnelle des phrases à l'aide du classificateur de texte fastText