[PYTHON] Laissez le modèle japonais BERT faire le test central et la génération de phrases

1.Tout d'abord

La dernière fois, j'ai essayé ** Tâche de réglage fin et de jugement négatif / positif ** sur le modèle pré-entraîné de BERT, mais il n'y a pas de réglage fin. Mais bien sûr, cela fonctionne.

Cette fois, j'essaierai le ** modèle pré-entraîné japonais BERT ** tel qu'il est sur Google Colab.

2. Configuration

La procédure de configuration est la suivante. Voir Google Colab pour le code (il y a un lien à la fin).

** 1) Installation du module ** Installez les modules requis (** pyknp, transformers **).

** 2) Installation d'une bibliothèque d'analyses morphologiques ** ** "Système d'analyse morphologique japonais JUMMAN ++" ** fourni par l'Université de Kyoto / Kurohashi / Kaoru / Murawaki Laboratory index.php? JUMAN ++) est utilisé.

** 3) Téléchargez le modèle pré-entraîné japonais BERT ** ** "BERT Japanese Pretrained Model" ** fourni par l'Université de Kyoto / Kurohashi / Kaoru / Murawaki Laboratory .php? BERT Japanese Pretrained model) est utilisé.

3. Le BERT peut-il résoudre les questions d'examen du centre?

Ce modèle est pré-appris en utilisant ** Wikipedia japonais **. Cela signifie que ** j'étudie diverses connaissances de l'est et de l'ouest sous la forme de résolution du problème de remplissage du blanc **, donc je vais prétendre que je pourrais peut-être résoudre la ** question à remplir dans le blanc de l'examen du centre d'examen d'entrée à l'université ** J'ai décidé de. Le sujet est Problème 9 de l'histoire mondiale B en 2018. スクリーンショット 2020-08-06 12.55.39.png La bonne réponse est ① "Aristocrate" et "César", mais comment répond le BERT?

import torch
from transformers import BertTokenizer, BertForMaskedLM, BertConfig
import numpy as np
import textwrap
config = BertConfig.from_json_file('./bert/Japanese_L-12_H-768_A-12_E-30_BPE_transformers/config.json')
model = BertForMaskedLM.from_pretrained('./bert/Japanese_L-12_H-768_A-12_E-30_BPE_transformers/pytorch_model.bin', config=config)
bert_tokenizer = BertTokenizer('./bert/Japanese_L-12_H-768_A-12_E-30_BPE_transformers/vocab.txt',
 do_lower_case=False, do_basic_tokenize=False)
from pyknp import Juman
jumanpp = Juman()

Tout d'abord, importez les bibliothèques requises et configurez BERT.

Lors de la saisie dans BERT, mettez [CLS] au début de la liste de mots, mettez [SEP] au séparateur de phrase et remplacez le mot que vous voulez prédire par [MASK], définissez donc une fonction pour le faire. Je vais.

#Vers la liste de mots[CLS],[SEP],[MASK]Fonction à ajouter
def preparation(tokenized_text):
    
    # [CLS],[SEP]Insérer
    tokenized_text.insert(0, '[CLS]')  #Au début de la liste de mots[CLS]Attacher
    tokenized_text.append('[SEP]')  #À la fin de la liste de mots[SEP]Attacher
        
    maru = []
    for i, word in enumerate(tokenized_text):
        if word =='。' and i !=len(tokenized_text)-2:  #Détection de position de "."
            maru.append(i)

    for i, loc in enumerate(maru):
        tokenized_text.insert(loc+1+i, '[SEP]')  #À côté de "." Dans la liste de mots[SEP]Insérer
        
    #"□"[MASK]Remplacer par
    mask_index = []
    for index, word in enumerate(tokenized_text):
        if word =='□':  #Détection de position de "□"
            tokenized_text[index] = '[MASK]'
            mask_index.append(index)
    
    return tokenized_text, mask_index  

La fonction insère [CLS] au début de la liste de mots, ajoute [SEP] à la fin et insère [SEP] après "." Au milieu. Après avoir décidé de la position des mots de cette manière, remplacez la partie prédite "□" par [MASK] et renvoyez la liste de mots et la position [MASK].

Puis convertissez le texte en un tenseur d'identification.

#Convertir du texte en tenseur d'identification
text = "Dans son livre "Histoire", le Grec Polyubios loue le système d'État républicain romain (système politique) comme excellent. Selon lui, le système national a un élément royal appelé Consul, un élément du système □ appelé Sénat et un élément démocratique appelé le peuple, et ces trois partis coopèrent et se restreignent et s'équilibrent. On dit que c'est en train de faire. Les Romains sont fiers de ce système politique, qui peut être lu à partir du nom qu'ils appelaient «Sénat et peuple romains» pour désigner leur nation. Même □, qui semblait avoir gagné la guerre civile à la fin du gouvernement républicain, a été assassiné parce qu'il était soupçonné d'avoir tenté de briser ce système."
result = jumanpp.analysis(text)  #Partage
tokenized_text = [mrph.midasi for mrph in result.mrph_list()]  #Convertir en liste de mots
tokenized_text, mask_index = preparation(tokenized_text)  # [CLS],[SEP],[MASK]Ajouter
tokens = bert_tokenizer.convert_tokens_to_ids(tokenized_text)  #Convertir en liste d'identifiants
tokens_tensor = torch.tensor([tokens])  #Convertir en tenseur ID

Transformez le texte en une liste de mots, ajoutez [CLS], [SEP], [MASK] en utilisant la fonction précédente, convertissez-le en liste d'ID et convertissez-le en un tenseur d'ID que Pytorch peut lire.

スクリーンショット 2020-08-06 18.47.49.png Convertissez-le comme ça.

Maintenant, déduisons la partie [MASK](5 meilleurs candidats).

# [MASK]Inférer l'emplacement(TOP5)
model.eval() 
tokens_tensor = tokens_tensor.to('cuda')
model.to('cuda')
print(textwrap.fill(text, 45))
print()

with torch.no_grad():
  outputs = model(tokens_tensor)
  predictions = outputs[0]
  
  for i in range(len(mask_index)):
     _, predicted_indexes = torch.topk(predictions[0, mask_index[i]], k=5)
     predicted_tokens = bert_tokenizer.convert_ids_to_tokens(predicted_indexes.tolist())
     print(i, predicted_tokens)

スクリーンショット 2020-08-06 15.35.16.png

C'était déraisonnable, mais la première prédiction incluait le bon ** «noble» **! Malheureusement, je n'ai pas pu répondre correctement au deuxième «César», mais BERT le fera mieux que ce à quoi je m'attendais.

4. Le BERT peut-il générer des phrases?

BERT, qui n'a appris qu'à l'avance, n'a appris que la ** question à remplir dans le blanc ** et la ** connexion de deux phrases **, il n'est donc pas adapté à la génération de phrases en l'état. Cependant, rien ne peut être fait en principe.

Si vous préparez un certain texte, multipliez le premier mot par [MASK] pour faire une prédiction, remplacez le premier mot par le résultat de la prédiction et multipliez le mot suivant par [MASK] pour faire une prédiction, qui est similaire au texte. Vous devriez pouvoir générer une nouvelle instruction.

Faisons le. Le sujet est ["le discours du président Kennedy exprimant son soutien au projet Apollo"](https://ja.wikipedia.org/wiki/Apollo project). スクリーンショット 2020-08-06 13.28.39.png

#Analyse morphologique
text = "Nous avons décidé d'aller sur la Lune d'ici 10 ans, non pas parce que c'était facile. C'est assez difficile. Cet objectif nous aidera à rassembler le meilleur de nos capacités et de notre technologie et à voir à quel point cela représente. Ce défi est ce que nous voulons relever et que nous ne voulons pas retarder. Et c'est ce que nous voulons gagner, et pas seulement nous."
result = jumanpp.analysis(text)  #Partage
tokenized_text = [mrph.midasi for mrph in result.mrph_list()]  #Convertir en liste de mots
tokenized_text, mask_index = preparation(tokenized_text)  # [CLS],[SEP]Ajouter
tokens = bert_tokenizer.convert_tokens_to_ids(tokenized_text)  #Convertir en liste d'identifiants
tokens_tensor = torch.tensor([tokens])  #Convertir en tenseur ID

Comme précédemment, transformez le texte en une liste de mots, ajoutez [CLS], [SEP] en utilisant la fonction définie, convertissez-le en liste d'ID et convertissez-le en un tenseur d'ID lisible par Pytorch.

Puisque nous faisons plusieurs fois des prédictions de mots, nous définissons une fonction qui prédit un mot.

#1 fonction de prédiction de mot
def predict_one(tokens_tensor, mask_index):

    model.eval()    
    tokens_tensor = tokens_tensor.to('cuda')
    model.to('cuda')
 
    with torch.no_grad():
      outputs = model(tokens_tensor)
      predictions = outputs[0]
 
      _, predicted_indexes = torch.topk(predictions[0, mask_index], k=5)
      predicted_tokens = bert_tokenizer.convert_ids_to_tokens(predicted_indexes.tolist())
    return predicted_tokens, predicted_indexes.tolist()

Une fonction qui prédit un mot multiplié par [MASK] et renvoie le mot et l'ID prédits.

Ensuite, écrivez le code pour générer la phrase.

#Génération de déclaration
for i in range(1,len(tokens_tensor[0])):
    tmp = torch.tensor(tokens_tensor)  # tokens_Copier le tenseur en tmp
    tmp[0, i]=4  #i e[mask]Réécrire dans
    predicted_tokens, predicted_indexes =predict_one(tmp, i)  # [mask]Prédire
    if predicted_indexes !=1:  #La prédiction est[UNK]Autrement
      tokens_tensor[0, i] = predicted_indexes[0]  #ID de prédiction[0]Deuxièmes jetons_Écraser le i-ème du tenseur

target_list = tokens_tensor.tolist()[0]  
predict_list = bert_tokenizer.convert_ids_to_tokens(target_list)  
predict_sentence = ''.join(predict_list[1:])

print('------ original_text -------')
print(textwrap.fill(text,45))
print('------ predict_text -------')
print(textwrap.fill(predict_sentence,45))  

Copiez tokens_tensor dans tmp une fois, multipliez tmp par [MASK] dans l'ordre, et écrasez la partie correspondante de tokens_tensor avec le résultat de la prédiction. Eh bien, quand tu fais ça,

スクリーンショット 2020-08-06 15.37.18.png

Même si l'original disait: «Allons sur la lune d'ici 10 ans», la génération de la phrase était «devrait aller à l'étranger d'ici un an», et elle est devenue petite (rires). Le contenu de la phrase est un peu flou. La génération de phrases ne semble pas très bien fonctionner uniquement avec un pré-apprentissage.

L'ensemble du code a été créé dans Google Colab et publié sur Github, donc si vous voulez l'essayer vous-même, ce [** "lien" **](https://github.com/cedro3/BERT/blob/master/ Cliquez sur BERT_pretrained_model.ipynb) et cliquez sur le bouton ** "Colab sur le Web" ** en haut de la feuille affichée pour la déplacer.

(référence) ・ J'ai essayé de deviner ce que je voulais pour un cadeau de Noël en utilisant le modèle japonais BERTUtiliser JUMAN ++ avec Colab

Recommended Posts

Laissez le modèle japonais BERT faire le test central et la génération de phrases
J'ai écrit le code pour la génération de phrases japonaises avec DeZero
[Version 2020] Laissez Python faire tous les calculs de taxes et de recettes
[PyTorch] Génération de phrases japonaises à l'aide de Transformer
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