[PYTHON] J'ai essayé de comparer la précision de la classification des phrases BERT japonaises et japonaises Distil BERT avec PyTorch et introduction de la technique d'amélioration de la précision BERT

introduction

J'ai essayé d'utiliser le japonais BERT avec huggingface / transformers dans article précédent, mais si vous utilisez huggingface / transformers, d'autres pré-appris Le modèle de BERT est également facile à manipuler.

Dans Liste des modèles utilisables, il semble y avoir d'autres modèles tels que Distil BERT et ALBERT qui semblent être japonais. Les deux sont positionnés comme des BERT légers.

Cette fois, tout en présentant brièvement DistilBERT fourni par Namco Bandai qui peut également être utilisé en se serrant le visage , J'ai essayé de comparer la précision avec BERT normal. Enfin, je présenterai l'une des techniques pour améliorer la précision lors de la classification des phrases avec BERT.

Qu'est-ce que DistilBERT?

J'emprunterai le README du Github de Namco Bandai tel quel.

DistilBERT est un modèle présenté par Huggingface à NeurIPS 2019, et son nom signifie "Distilated-BERT". Veuillez vous référer ici pour les articles soumis.

Distil BERT est un petit modèle de transformateur rapide et léger basé sur l'architecture BERT. On dit que DistilBERT a 40% de paramètres en moins que BERT-base, fonctionne 60% plus vite et maintient 97% des performances de BERT telles que mesurées par le GLUE Benchmark.

DistilBERT est formé à l'aide de la distillation des connaissances, une technique qui comprime un grand modèle appelé enseignant en un modèle plus petit appelé étudiant. En distillant BERT, vous pouvez obtenir un modèle Transformer plus léger et plus rapide, tout en ayant de nombreuses similitudes avec le modèle BERT original.

En bref, cela ressemble à une version légère de la base BERT qui atteint une vitesse élevée (d'où la précision est légèrement inférieure à celle de la base BERT). Utilisons-le réellement pour voir à quelle vitesse il est et à quel point il est inexact.

Comment utiliser DistilBERT

[Github officiel](https://github.com/BandaiNamcoResearchInc/DistilBERT-base-jp/blob/master/docs/GUIDE.md#transformers-%E3%83%A9%E3%82%A4%E3%83% 96% E3% 83% A9% E3% 83% AA% E3% 83% BC% E3% 81% 8B% E3% 82% 89% E8% AA% AD% E8% BE% BC% E3% 81% BF) Vous pouvez facilement l'appeler en serrant le visage / les transformateurs dans la rue.

-Est-ce que le tokenizer provoque une erreur à moins que vous n'ajoutiez cl-tohoku / au nom comme indiqué ci-dessous?

from transformers import AutoModel, AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained("cl-tohoku/bert-base-japanese-whole-word-masking")
distil_model = AutoModel.from_pretrained("bandainamco-mirai/distilbert-base-japanese")  

Fondamentalement, il peut être utilisé de la même manière que la base japonaise BERT introduite dans Dernier article, mais en raison de la différence dans la structure interne du réseau, le réglage fin est un peu. Il semble que cela doit être changé.

Pour le moment, vérifions la structure du contenu de Distil BERT.

print(distil_model)

C'est long, alors gardez-le fermé. <détails>

Structure du modèle DistilBERT </ summary>

DistilBertModel(
  (embeddings): Embeddings(
    (word_embeddings): Embedding(32000, 768, padding_idx=0)
    (position_embeddings): Embedding(512, 768)
    (LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
    (dropout): Dropout(p=0.1, inplace=False)
  )
  (transformer): Transformer(
    (layer): ModuleList(
      (0): TransformerBlock(
        (attention): MultiHeadSelfAttention(
          (dropout): Dropout(p=0.1, inplace=False)
          (q_lin): Linear(in_features=768, out_features=768, bias=True)
          (k_lin): Linear(in_features=768, out_features=768, bias=True)
          (v_lin): Linear(in_features=768, out_features=768, bias=True)
          (out_lin): Linear(in_features=768, out_features=768, bias=True)
        )
        (sa_layer_norm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
        (ffn): FFN(
          (dropout): Dropout(p=0.1, inplace=False)
          (lin1): Linear(in_features=768, out_features=3072, bias=True)
          (lin2): Linear(in_features=3072, out_features=768, bias=True)
        )
        (output_layer_norm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
      )
      (1): TransformerBlock(
        (attention): MultiHeadSelfAttention(
          (dropout): Dropout(p=0.1, inplace=False)
          (q_lin): Linear(in_features=768, out_features=768, bias=True)
          (k_lin): Linear(in_features=768, out_features=768, bias=True)
          (v_lin): Linear(in_features=768, out_features=768, bias=True)
          (out_lin): Linear(in_features=768, out_features=768, bias=True)
        )
        (sa_layer_norm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
        (ffn): FFN(
          (dropout): Dropout(p=0.1, inplace=False)
          (lin1): Linear(in_features=768, out_features=3072, bias=True)
          (lin2): Linear(in_features=3072, out_features=768, bias=True)
        )
        (output_layer_norm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
      )
      (2): TransformerBlock(
        (attention): MultiHeadSelfAttention(
          (dropout): Dropout(p=0.1, inplace=False)
          (q_lin): Linear(in_features=768, out_features=768, bias=True)
          (k_lin): Linear(in_features=768, out_features=768, bias=True)
          (v_lin): Linear(in_features=768, out_features=768, bias=True)
          (out_lin): Linear(in_features=768, out_features=768, bias=True)
        )
        (sa_layer_norm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
        (ffn): FFN(
          (dropout): Dropout(p=0.1, inplace=False)
          (lin1): Linear(in_features=768, out_features=3072, bias=True)
          (lin2): Linear(in_features=3072, out_features=768, bias=True)
        )
        (output_layer_norm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
      )
      (3): TransformerBlock(
        (attention): MultiHeadSelfAttention(
          (dropout): Dropout(p=0.1, inplace=False)
          (q_lin): Linear(in_features=768, out_features=768, bias=True)
          (k_lin): Linear(in_features=768, out_features=768, bias=True)
          (v_lin): Linear(in_features=768, out_features=768, bias=True)
          (out_lin): Linear(in_features=768, out_features=768, bias=True)
        )
        (sa_layer_norm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
        (ffn): FFN(
          (dropout): Dropout(p=0.1, inplace=False)
          (lin1): Linear(in_features=768, out_features=3072, bias=True)
          (lin2): Linear(in_features=3072, out_features=768, bias=True)
        )
        (output_layer_norm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
      )
      (4): TransformerBlock(
        (attention): MultiHeadSelfAttention(
          (dropout): Dropout(p=0.1, inplace=False)
          (q_lin): Linear(in_features=768, out_features=768, bias=True)
          (k_lin): Linear(in_features=768, out_features=768, bias=True)
          (v_lin): Linear(in_features=768, out_features=768, bias=True)
          (out_lin): Linear(in_features=768, out_features=768, bias=True)
        )
        (sa_layer_norm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
        (ffn): FFN(
          (dropout): Dropout(p=0.1, inplace=False)
          (lin1): Linear(in_features=768, out_features=3072, bias=True)
          (lin2): Linear(in_features=3072, out_features=768, bias=True)
        )
        (output_layer_norm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
      )
      (5): TransformerBlock(
        (attention): MultiHeadSelfAttention(
          (dropout): Dropout(p=0.1, inplace=False)
          (q_lin): Linear(in_features=768, out_features=768, bias=True)
          (k_lin): Linear(in_features=768, out_features=768, bias=True)
          (v_lin): Linear(in_features=768, out_features=768, bias=True)
          (out_lin): Linear(in_features=768, out_features=768, bias=True)
        )
        (sa_layer_norm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
        (ffn): FFN(
          (dropout): Dropout(p=0.1, inplace=False)
          (lin1): Linear(in_features=768, out_features=3072, bias=True)
          (lin2): Linear(in_features=3072, out_features=768, bias=True)
        )
        (output_layer_norm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
      )
    )
  )
)

La différence avec BERT-base est qu'il y a 12 blocs transformer dans BERT-base, mais seulement 6 dans Distil BERT. Vous pouvez également voir que la dénomination de la couche de contenu est un peu différente de BERT-base.

Par conséquent, lors du réglage fin, écrivez comme suit. Un exemple de déclaration de modèle de classification est également décrit.

Cette fois, il n'y a pas d'effet particulier, mais vérifions également la référence DistilBERT. Le modèle de retour est également légèrement différent.

  • https://huggingface.co/transformers/model_doc/distilbert.html

(Comme pour l'article précédent, la classification du titre du corpus d'actualités de livingoor est supposée.)

Modèle de déclaration

import torch
from torch import nn
import torch.nn.functional as F
from transformers import *

class DistilBertClassifier(nn.Module):
  def __init__(self):
    super(DistilBertClassifier, self).__init__()
    # BERT-C'est le seul endroit différent de la base.
    self.distil_bert = AutoModel.from_pretrained("bandainamco-mirai/distilbert-base-japanese")
    #Le nombre de dimensions de la couche cachée de DistilBERT est de 768,9 catégories d'actualités Liveoor
    self.linear = nn.Linear(768, 9)
    #Traitement d'initialisation du poids
    nn.init.normal_(self.linear.weight, std=0.02)
    nn.init.normal_(self.linear.bias, 0)

  def forward(self, input_ids):
    vec, _ = self.distil_bert(input_ids)
    #Obtenez uniquement le vecteur du premier jeton cls
    vec = vec[:,0,:]
    vec = vec.view(-1, 768)
    #Convertir les dimensions pour la classification en couches entièrement connectées
    out = self.linear(vec)
    return F.log_softmax(out)

#Instance de modèle de classification
distil_classifier = DistilBertClassifier()

Réglage fin

#Tout d'abord OFF
for param in distil_classifier.parameters():
    param.requires_grad = False

#Mettre à jour uniquement la dernière couche de DistilBERT ON
# BERT-la base est.encoder.layer[-1]C'était,
#Dans le cas de DistilBERT, comme confirmé la structure ci-dessus, comme suit.transfomer.layer[-1]Ce sera.
for param in distil_classifier.distil_bert.transformer.layer[-1].parameters():
    param.requires_grad = True

#La classification de classe est également activée
for param in distil_classifier.linear.parameters():
    param.requires_grad = True

import torch.optim as optim

#Le taux d'apprentissage est faible pour la partie pré-apprise et élevé pour la dernière couche entièrement connectée.
#N'oubliez pas de changer cela pour Distil BERT
optimizer = optim.Adam([
    {'params': distil_classifier.distil_bert.transformer.layer[-1].parameters(), 'lr': 5e-5},
    {'params': distil_classifier.linear.parameters(), 'lr': 1e-4}
])

Comparaison de BERT-base et Distil BERT

Similaire à Dernière fois, il gère la tâche de classification des titres du corpus de nouvelles de livingoor.

BERT-base

  • Le code source suivant est presque le même que la dernière fois.

Définition du modèle et mise au point

class BertClassifier(nn.Module):
  def __init__(self):
    super(BertClassifier, self).__init__()
    self.bert = BertModel.from_pretrained('cl-tohoku/bert-base-japanese-whole-word-masking')
    #Le calque caché de BERT a 768 dimensions,9 catégories d'actualités Liveoor
    self.linear = nn.Linear(768, 9)
    #Traitement d'initialisation du poids
    nn.init.normal_(self.linear.weight, std=0.02)
    nn.init.normal_(self.linear.bias, 0)

  def forward(self, input_ids):
    # last_Recevoir uniquement caché
    vec, _ = self.bert(input_ids)
    #Obtenez uniquement le vecteur du premier jeton cls
    vec = vec[:,0,:]
    vec = vec.view(-1, 768)
    #Convertir les dimensions pour la classification en couches entièrement connectées
    out = self.linear(vec)
    return F.log_softmax(out)

#Déclaration d'instance de modèle de classification
bert_classifier = BertClassifier()

#Paramètres de réglage précis
#Tout d'abord OFF
for param in bert_classifier.parameters():
    param.requires_grad = False

#Mettre à jour uniquement la dernière couche de BERT ON
for param in bert_classifier.bert.encoder.layer[-1].parameters():
    param.requires_grad = True

#La classification de classe est également activée
for param in bert_classifier.linear.parameters():
    param.requires_grad = True

import torch.optim as optim

#Le taux d'apprentissage est faible pour la partie pré-apprise et élevé pour la dernière couche entièrement connectée.
optimizer = optim.Adam([
    {'params': bert_classifier.bert.encoder.layer[-1].parameters(), 'lr': 5e-5},
    {'params': bert_classifier.linear.parameters(), 'lr': 1e-4}
])

#Paramètres de la fonction de perte
loss_function = nn.NLLLoss()

Apprentissage et raisonnement

#Mesurez le temps d'étude.
import time

start = time.time()
#Paramètres GPU
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
#Envoyer le réseau au GPU
bert_classifier.to(device)
losses = []

#Le nombre d'époques est de 10
for epoch in range(10):
  all_loss = 0
  for idx, batch in enumerate(train_iter):
    batch_loss = 0
    bert_classifier.zero_grad()
    input_ids = batch.Text[0].to(device)
    label_ids = batch.Label.to(device)
    out = bert_classifier(input_ids)
    batch_loss = loss_function(out, label_ids)
    batch_loss.backward()
    optimizer.step()
    all_loss += batch_loss.item()
  print("epoch", epoch, "\t" , "loss", all_loss)

end = time.time()

print ("time : ", end - start)
#epoch 0 	 loss 251.19750046730042
#epoch 1 	 loss 110.7038831859827
#epoch 2 	 loss 82.88570280373096
#epoch 3 	 loss 67.0771074667573
#epoch 4 	 loss 56.24497305601835
#epoch 5 	 loss 42.61423560976982
#epoch 6 	 loss 35.98485875874758
#epoch 7 	 loss 25.728398952633142
#epoch 8 	 loss 20.40780107676983
#epoch 9 	 loss 16.567239843308926
#time :  101.97362518310547

#inférence
answer = []
prediction = []
with torch.no_grad():
    for batch in test_iter:

        text_tensor = batch.Text[0].to(device)
        label_tensor = batch.Label.to(device)

        score = bert_classifier(text_tensor)
        _, pred = torch.max(score, 1)

        prediction += list(pred.cpu().numpy())
        answer += list(label_tensor.cpu().numpy())
print(classification_report(prediction, answer, target_names=categories))
#                precision    recall  f1-score   support

# kaden-channel       0.94      0.92      0.93       172
#dokujo-tsushin       0.75      0.86      0.80       156
#        peachy       0.81      0.68      0.74       211
#   movie-enter       0.78      0.81      0.80       171
#          smax       0.98      0.91      0.94       176
#livedoor-homme       0.68      0.83      0.75        83
#  it-life-hack       0.79      0.94      0.86       150
#    topic-news       0.81      0.76      0.78       172
#  sports-watch       0.89      0.82      0.85       185

#      accuracy                           0.83      1476
#     macro avg       0.83      0.84      0.83      1476
#  weighted avg       0.84      0.83      0.83      1476

Le temps d'apprentissage de 10 époques était d'environ 102 secondes et la précision était de 0,83 (score F).

DistilBERT

Apprentissage et raisonnement

  • Effectuer l'apprentissage et l'inférence comme suit en fonction du modèle défini ci-dessus et des paramètres de réglage précis ――Mais ce n'est pas différent de BERT-base, mais juste au cas où ...
import time

#Paramètres GPU
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
#Envoyer le réseau au GPU
distil_classifier.to(device)
losses = []

start = time.time()
#Le nombre d'époques est de 10
for epoch in range(10):
  all_loss = 0
  for idx, batch in enumerate(train_iter):
    batch_loss = 0
    distil_classifier.zero_grad()
    input_ids = batch.Text[0].to(device)
    label_ids = batch.Label.to(device)
    out = distil_classifier(input_ids)
    batch_loss = loss_function(out, label_ids)
    batch_loss.backward()
    optimizer.step()
    all_loss += batch_loss.item()
  print("epoch", epoch, "\t" , "loss", all_loss)

end = time.time()
print ("time : ", end - start)
#/usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py:26: UserWarning: Implicit dimension choice for log_softmax has been deprecated. Change the call to include dim=X as an argument.
#epoch 0 	 loss 450.1027842760086
#epoch 1 	 loss 317.39041769504547
#epoch 2 	 loss 211.34138756990433
#epoch 3 	 loss 144.4813650548458
#epoch 4 	 loss 106.24609130620956
#epoch 5 	 loss 83.87273170053959
#epoch 6 	 loss 68.9661111086607
#epoch 7 	 loss 59.31868125498295
#epoch 8 	 loss 49.874382212758064
#epoch 9 	 loss 41.56027300283313
#time :  60.22182369232178


from sklearn.metrics import classification_report

answer = []
prediction = []
with torch.no_grad():
    for batch in test_iter:

        text_tensor = batch.Text[0].to(device)
        label_tensor = batch.Label.to(device)

        score = distil_classifier(text_tensor)
        _, pred = torch.max(score, 1)

        prediction += list(pred.cpu().numpy())
        answer += list(label_tensor.cpu().numpy())
print(classification_report(prediction, answer, target_names=categories))

#/usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py:26: UserWarning: Implicit dimension choice for log_softmax has been deprecated. Change the call to include dim=X as an argument.
#                precision    recall  f1-score   support

# kaden-channel       0.93      0.96      0.95       163
#dokujo-tsushin       0.88      0.88      0.88       178
#        peachy       0.86      0.75      0.80       202
#   movie-enter       0.86      0.84      0.85       183
#          smax       0.96      0.95      0.95       165
#livedoor-homme       0.67      0.71      0.69        96
#  it-life-hack       0.91      0.91      0.91       178
#    topic-news       0.80      0.86      0.83       148
#  sports-watch       0.88      0.91      0.89       163

#      accuracy                           0.87      1476
#     macro avg       0.86      0.86      0.86      1476
#  weighted avg       0.87      0.87      0.87      1476

――Le temps d'apprentissage de 10 époques était d'environ 60 secondes et la précision était de 0,87 (score F). C'est bien que le temps d'apprentissage soit plus rapide, mais la précision s'est améliorée. «À l'origine, il était censé être un peu moins précis que BERT-base, mais il semble que ce soit plus élevé. ――De toute façon, la tâche de classer les titres du corpus d'actualités de livingoor, que j'essaie toujours à titre expérimental, n'est peut-être pas très bonne ...

Essayez d'améliorer la précision de la base BERT

À partir de là, je présenterai une technique pour améliorer la précision lors de la classification des phrases en japonais BERT, pas en comparaison avec Distil BERT.

(À l'origine, vous devriez d'abord considérer soigneusement le prétraitement en fonction de la tâche, mais cela semble être une technique d'amélioration de la précision qui ne dépend pas beaucoup de la tâche, je vais donc l'introduire ici.)

Bien que ce soit une technique, elle est introduite dans 5.3 Feature-based Approach with BERT de BERT's paper, et dans le concours NLP précédemment organisé à kaggle Cela semble être la 1ère méthode de Jigsaw Unintended Bias in Toxicity Classification.

Veuillez vous référer à l'article suivant pour plus de détails sur la technique.

Le fait est que sur les 12 couches Encoder de la base BERT, il est préférable de combiner les vecteurs des jetons CLS des 4 couches finales plutôt que d'utiliser uniquement les vecteurs des jetons CLS de la couche finale. Il semble. (Je ne sais pas pourquoi ...)

L'idée est si simple que je vais l'essayer dans cette tâche de classification des titres du corpus d'actualités de Liveoor.

la mise en oeuvre

Modèle de déclaration

class BertClassifierRevised(nn.Module):
  def __init__(self):
    super(BertClassifierRevised, self).__init__()
    self.bert = BertModel.from_pretrained('cl-tohoku/bert-base-japanese-whole-word-masking')
    #Le nombre de dimensions de la couche cachée de BERT est de 768, mais comme il traite de la combinaison des vecteurs des quatre dernières couches, il est fixé à 768 x 4 dimensions.
    self.linear = nn.Linear(768*4, 9)
    #Traitement d'initialisation du poids
    nn.init.normal_(self.linear.weight, std=0.02)
    nn.init.normal_(self.linear.bias, 0)
  
  #Préparer une fonction pour obtenir le vecteur du jeton cls
  def _get_cls_vec(self, vec):
    return vec[:,0,:].view(-1, 768)

  def forward(self, input_ids):
    #Dernière valeur de retour_hidden_Dans l'état, seule la couche finale peut être obtenue, donc
    # output_hidden_states=Déclarez True pour obtenir tous les vecteurs de calque cachés,
    #Troisième valeur de retour(État de toutes les couches cachées)Obtenir.
    _, _,  hidden_states = self.bert(input_ids, output_hidden_states=True)

    #Obtenez le vecteur de jeton cls de chacune des 4 dernières couches cachées
    vec1 = self._get_cls_vec(hidden_states[-1])
    vec2 = self._get_cls_vec(hidden_states[-2])
    vec3 = self._get_cls_vec(hidden_states[-3])
    vec4 = self._get_cls_vec(hidden_states[-4])

    #Combinez quatre jetons cls en un seul vecteur.
    vec = torch.cat([vec1, vec2, vec3, vec4], dim=1)

    #Convertir les dimensions pour la classification en couches entièrement connectées
    out = self.linear(vec)
    return F.log_softmax(out)

#Déclaration d'instance
bert_classifier_revised = BertClassifierRevised()

Réglage fin

#Tout d'abord OFF
for param in bert_classifier_revised.parameters():
    param.requires_grad = False

#Allumez les 4 dernières couches de BERT
for param in bert_classifier_revised.bert.encoder.layer[-1].parameters():
    param.requires_grad = True

for param in bert_classifier_revised.bert.encoder.layer[-2].parameters():
    param.requires_grad = True

for param in bert_classifier_revised.bert.encoder.layer[-3].parameters():
    param.requires_grad = True

for param in bert_classifier_revised.bert.encoder.layer[-4].parameters():
    param.requires_grad = True

#La classification de classe est également activée
for param in bert_classifier_revised.linear.parameters():
    param.requires_grad = True

import torch.optim as optim

#Le taux d'apprentissage est faible pour la partie pré-apprise et élevé pour la dernière couche entièrement connectée.
optimizer = optim.Adam([
    {'params': bert_classifier_revised.bert.encoder.layer[-1].parameters(), 'lr': 5e-5},
    {'params': bert_classifier_revised.bert.encoder.layer[-2].parameters(), 'lr': 5e-5},
    {'params': bert_classifier_revised.bert.encoder.layer[-3].parameters(), 'lr': 5e-5},
    {'params': bert_classifier_revised.bert.encoder.layer[-4].parameters(), 'lr': 5e-5},
    {'params': bert_classifier_revised.linear.parameters(), 'lr': 1e-4}
])

#Paramètres de la fonction de perte
loss_function = nn.NLLLoss()

Apprentissage et raisonnement


import time

start = time.time()
#Paramètres GPU
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
#Envoyer le réseau au GPU
bert_classifier_revised.to(device)
losses = []

#Le nombre d'époques est de 5
for epoch in range(10):
  all_loss = 0
  for idx, batch in enumerate(train_iter):
    batch_loss = 0
    bert_classifier_revised.zero_grad()
    input_ids = batch.Text[0].to(device)
    label_ids = batch.Label.to(device)
    out = bert_classifier_revised(input_ids)
    batch_loss = loss_function(out, label_ids)
    batch_loss.backward()
    optimizer.step()
    all_loss += batch_loss.item()
  print("epoch", epoch, "\t" , "loss", all_loss)

end = time.time()

print ("time : ", end - start)
#epoch 0 	 loss 196.0047192275524
#epoch 1 	 loss 75.8067753687501
#epoch 2 	 loss 42.30751228891313
#epoch 3 	 loss 16.470114511903375
#epoch 4 	 loss 7.427484432584606
#epoch 5 	 loss 2.9392087209271267
#epoch 6 	 loss 1.5984382012393326
#epoch 7 	 loss 1.7370687873335555
#epoch 8 	 loss 0.9278695838729618
#epoch 9 	 loss 1.499190401067608
#time :  149.01919651031494

#inférence
answer = []
prediction = []
with torch.no_grad():
    for batch in test_iter:

        text_tensor = batch.Text[0].to(device)
        label_tensor = batch.Label.to(device)

        score = bert_classifier_revised(text_tensor)
        _, pred = torch.max(score, 1)

        prediction += list(pred.cpu().numpy())
        answer += list(label_tensor.cpu().numpy())
print(classification_report(prediction, answer, target_names=categories))
#                precision    recall  f1-score   support

# kaden-channel       0.80      0.99      0.89       137
#dokujo-tsushin       0.89      0.86      0.88       183
#        peachy       0.78      0.82      0.80       168
#   movie-enter       0.87      0.88      0.87       176
#          smax       0.95      0.93      0.94       168
#livedoor-homme       0.72      0.83      0.77        88
#  it-life-hack       0.95      0.79      0.86       215
#    topic-news       0.83      0.84      0.83       159
#  sports-watch       0.92      0.86      0.89       182

#      accuracy                           0.86      1476
#     macro avg       0.86      0.87      0.86      1476
#  weighted avg       0.87      0.86      0.86      1476
  • La perte diminue plus rapidement que la base BERT ――Le temps d'apprentissage était d'environ 150 secondes, ce qui était un peu plus long que la base BERT.
  • La précision est de 0,86, ce qui est amélioré par rapport à 0,83 de la base BERT. Génial.

en conclusion

  • J'ai comparé BERT-base et Distil BERT. En conséquence, DistilBERT est meilleur en termes de vitesse et de précision, mais je sens que je comprends comment utiliser DistilBERT. Dans la seconde moitié, nous avons introduit un plan pour considérer le jeton cls des 4 dernières couches comme un plan pour améliorer la précision de BERT. Base BERT Il semble que cela contribue définitivement à l'amélioration de la précision par rapport à. À partir de maintenant, lors de l'implémentation du modèle de classification avec BERT, utilisons les 4 dernières couches pour le moment.

fin

Recommended Posts

J'ai essayé de comparer la précision de la classification des phrases BERT japonaises et japonaises Distil BERT avec PyTorch et introduction de la technique d'amélioration de la précision BERT
J'ai essayé d'implémenter la classification des phrases et la visualisation de l'attention par le japonais BERT avec PyTorch
J'ai essayé de comparer la vitesse de traitement avec dplyr de R et pandas de Python
J'ai essayé d'implémenter la classification des phrases par Self Attention avec PyTorch
J'ai essayé d'analyser la négativité de Nono Morikubo. [Comparer avec Posipa]
[PyTorch] Introduction à la classification des documents japonais à l'aide de BERT
[Introduction à AWS] J'ai essayé de porter une application de conversation et de jouer avec text2speech @ AWS ♪
J'ai essayé d'implémenter et d'apprendre DCGAN avec PyTorch
[Introduction à Pytorch] J'ai essayé de catégoriser Cifar10 avec VGG16 ♬
J'ai essayé d'automatiser la mise à jour de l'article du blog Livedoor avec Python et sélénium.
J'ai essayé de trouver l'entropie de l'image avec python
J'ai essayé de trouver la moyenne de plusieurs colonnes avec TensorFlow
J'ai essayé de publier automatiquement sur ChatWork au moment du déploiement avec Fabric et ChatWork Api
J'ai essayé de comparer la précision des modèles d'apprentissage automatique en utilisant kaggle comme thème.
J'ai essayé de vérifier la classification yin et yang des membres hololive par apprentissage automatique
J'ai essayé d'automatiser l'arrosage du pot avec Raspberry Pi
[Introduction à Python] J'ai comparé les conventions de nommage de C # et Python.
[Introduction à StyleGAN] J'ai joué avec "The Life of a Man" ♬
J'ai essayé d'agrandir la taille du volume logique avec LVM
De l'introduction de JUMAN ++ à l'analyse morphologique du japonais avec Python
J'ai essayé d'améliorer l'efficacité du travail quotidien avec Python
J'ai essayé de créer Othello AI avec tensorflow sans comprendre la théorie de l'apprentissage automatique ~ Introduction ~
J'ai essayé de visualiser la tranche d'âge et la distribution des taux d'Atcoder
10 méthodes pour améliorer la précision de BERT
J'ai essayé d'exprimer de la tristesse et de la joie face au problème du mariage stable.
J'ai essayé de faire la différence de Config avant et après le travail avec le script pyATS / Genie self-made
J'ai essayé d'améliorer la précision de mon propre réseau neuronal
[PyTorch] Introduction à la classification de documents à l'aide de BERT
J'ai essayé d'obtenir le code d'authentification de l'API Qiita avec Python.
J'ai essayé d'extraire automatiquement les mouvements des joueurs Wiire avec un logiciel
[Introduction à Pytorch] J'ai joué avec sinGAN ♬
J'ai essayé d'apprendre l'angle du péché et du cos avec le chainer
J'ai essayé d'extraire et d'illustrer l'étape de l'histoire à l'aide de COTOHA
J'ai essayé de vérifier et d'analyser l'accélération de Python par Cython
J'ai essayé d'implémenter CVAE avec PyTorch
J'ai essayé d'obtenir et d'analyser les données statistiques de la nouvelle Corona avec Python: données de l'Université John's Hopkins
J'ai essayé de rationaliser le rôle standard des nouveaux employés avec Python
J'ai essayé de visualiser le texte du roman "Weather Child" avec Word Cloud
J'ai essayé d'obtenir les informations sur le film de l'API TMDb avec Python
J'ai essayé de prédire le comportement du nouveau virus corona avec le modèle SEIR.
J'ai essayé de contrôler la bande passante et le délai du réseau avec la commande tc
J'ai essayé la reconnaissance d'image de "Moon and Suppon" avec Pytorch (en utilisant torchvision.datasets.ImageFolder qui correspond à from_from_directry de keras)
J'ai essayé de notifier la mise à jour de "Hameln" en utilisant "Beautiful Soup" et "IFTTT"
J'ai essayé de visualiser facilement les tweets de JAWS DAYS 2017 avec Python + ELK
J'ai couru le tutoriel TensorFlow avec des commentaires (classification du texte des critiques de films)
L'histoire de la fabrication de soracom_exporter (j'ai essayé de surveiller SORACOM Air avec Prometheus)
J'ai essayé de créer un modèle avec l'exemple d'Amazon SageMaker Autopilot
J'ai essayé d'envoyer automatiquement la littérature du nouveau virus corona à LINE avec Python
J'ai essayé d'implémenter la lecture de Dataset avec PyTorch
J'ai essayé de sauvegarder les données avec discorde
J'ai essayé de corriger la forme trapézoïdale de l'image
[Introduction au PID] J'ai essayé de contrôler et de jouer ♬
J'ai essayé de vectoriser les paroles de Hinatazaka 46!
Introduction au Deep Learning pour la première fois (Chainer) Reconnaissance de caractères japonais Chapitre 4 [Amélioration de la précision de la reconnaissance en développant les données]
J'ai essayé de faire quelque chose comme un chatbot avec le modèle Seq2Seq de TensorFlow
J'ai essayé de notifier la mise à jour de "Devenir romancier" en utilisant "IFTTT" et "Devenir un romancier API"