[PYTHON] Erstellen Sie mit BERT + LightGBM + optuna ganz einfach ein Modell für die Verarbeitung natürlicher Sprache

Dies ist ein Artikel über das schnelle Erstellen eines Klassifizierungsmodells für natürliche Sprachen mit BERT, LightGBM und optuna. Die Daten verwenden Livedoor News Corpus.

Der gesamte in diesem Artikel verwendete Code ist unten aufgeführt. https://github.com/kazuki-hayakawa/bert_lightgbm_model

Wenn Sie es tatsächlich ausführen, versuchen Sie es bitte nach "git clone".

Gesamtdurchfluss

  1. Laden Sie die Korpusdaten von Livedoor News herunter
  2. Laden Sie das in Japan erlernte BERT-Modell herunter
  3. Starten Sie den Versuchsbehälter
  4. Feature-Generierung
  5. Modelltraining
  6. Bewertung des Modells anhand von Testdaten
  7. Behälter verlassen

Laden Sie die Korpusdaten von Livedoor News herunter

Laden Sie die Daten des Livedoor News Corpus in das Verzeichnis "data / raw" herunter. Das Download-Skript ist in src / data / download_livedoor_news.sh zusammengefasst.

Führen Sie dann src / data / preprocess.py aus, um die Daten vorzuverarbeiten und separat für Training und Test zu speichern.

src/data/preprocess.py


import os
import glob
from tqdm import tqdm
import pandas as pd
from sklearn.model_selection import train_test_split


def read_text(text_filepath):
    """Lesen Sie nur den Text ab der 4. Zeile entsprechend dem Format der Livedoor-Nachrichten"""
    with open(text_filepath, 'r') as f:
        lines = f.readlines()
        lines = lines[3:]

    text = ' '.join(lines)
    #Platz in voller Breite, Zeilenvorschubcode löschen
    text = text.replace('\u3000', '').replace('\n', '')
    return text


def main():
    #Im Voraus herunterladen_livedoor_news.Führen Sie sh aus, um die Daten abzurufen
    exclude_files = ['CHANGES.txt', 'README.txt', 'LICENSE.txt']
    all_file_paths = glob.glob('../../data/raw/text/**/*.txt', recursive=True)
    all_file_paths = [p for p in all_file_paths
                      if os.path.basename(p) not in exclude_files]

    df_processed = pd.DataFrame(columns=['id', 'media', 'text'])
    for idx, filepath in enumerate(tqdm(all_file_paths)):
        media = os.path.dirname(filepath).replace('../../data/raw/text/', '')
        text = read_text(filepath)
        row = pd.Series([idx + 1, media, text], index=df_processed.columns)
        df_processed = df_processed.append(row, ignore_index=True)

    df_train, df_test, _, _ = train_test_split(
        df_processed, df_processed['media'], test_size=0.1, random_state=0,
        stratify=df_processed['media']
    )
    df_train.to_csv('../../data/processed/train_dataset.csv', index=False)
    df_test.to_csv('../../data/processed/test_dataset.csv', index=False)


if __name__ == '__main__':
    main()

Laden Sie das japanisch erlernte BERT-Modell herunter

Informationen zum Verfahren finden Sie unter Erstellen eines japanischen BERT-Anweisungs-Einbettungsberechnungsservers mit bert-as-service.

Erstellen Sie ein models / bert_jp-Verzeichnis und laden Sie das [japanisch erlernte BERT-Modell] herunter (https://drive.google.com/drive/folders/1Zsm9DD40lrUVu6iAnIuTH2ODIkh-WM-O).

Benennen Sie die Datei um, damit sie von bert-as-service geladen werden kann

mv model.ckpt-1400000.index bert_model.ckpt.index
mv model.ckpt-1400000.meta bert_model.ckpt.meta 
mv model.ckpt-1400000.data-00000-of-00001 bert_model.ckpt.data-00000-of-00001

Erstellen einer Vokabeldatei

cut -f1 wiki-ja.vocab | sed -e "1 s/<unk>/[UNK]/g" > vocab.txt

Erstellen einer BERT-Konfigurationsdatei

bert_jp/bert_config.json


{
    "attention_probs_dropout_prob" : 0.1,
    "hidden_act" : "gelu",
    "hidden_dropout_prob" : 0.1,
    "hidden_size" : 768,
    "initializer_range" : 0.02,
    "intermediate_size" : 3072,
    "max_position_embeddings" : 512,
    "num_attention_heads" : 12,
    "num_hidden_layers" : 12,
    "type_vocab_size" : 2,
    "vocab_size" : 32000
}

Starten des experimentellen Containers

Führen Sie docker-compose up -d aus, um den Container zu starten. (Informationen zu Dockerfile und docker-compose.yml finden Sie im GitHub-Repository.) Führen Sie dann "Docker-Compose Exec Analytics / Bin / Bash" aus, um den Container einzugeben.

Feature-Generierung

Die Bert-Klasse, die BERT betreibt, wird wie folgt implementiert.

src/features/bert.py


import sentencepiece as spm
from bert_serving.client import BertClient


class Bert():
    """ Bert model client
        Before usage, you need to run bert server.
    """

    def __init__(self, bert_model_path, client_ip='0.0.0.0'):
        self.bert_client = BertClient(ip=client_ip)
        self.spm_model = spm.SentencePieceProcessor()
        self.spm_model.load(bert_model_path + 'wiki-ja.model')

    def _parse(self, text):
        text = str(text).lower()
        encoded_texts = self.spm_model.EncodeAsPieces(text)
        encoded_texts = [t for t in encoded_texts if t.strip()]
        return encoded_texts

    def text2vec(self, texts):
        """

        Args:
            texts (list):Liste der japanischen Saiten

        Returns:
            numpy array:Verteilter Darstellungstensor von Text
        """

        parsed_texts = list(map(self._parse, texts))
        tensor = self.bert_client.encode(parsed_texts, is_tokenized=True)
        return tensor

Verwenden Sie diese Option, um die natürliche Sprache in einen Vektor umzuwandeln. Gleichzeitig wird der Medienname, der die Zielvariable ist, auch in eine Ganzzahlbezeichnung konvertiert. Führen Sie src / features / build_features.py aus.

src/features/build_features.py


import subprocess
import numpy as np
import pandas as pd
from sklearn.preprocessing import LabelEncoder
from bert import Bert


def build_features(df, bert_client):
    vectors = bert_client.text2vec(df['text'])
    le = LabelEncoder()
    targets = le.fit_transform(df['media'])
    return vectors, targets


def main():
    BERT_MODEL_PATH = '../../models/bert_jp/'

    # start bert server
    commands = ['bert-serving-start', '-model_dir',
                BERT_MODEL_PATH, '-num_worker=1', '-cpu']
    p = subprocess.Popen(commands, shell=False,
                         stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)

    # start bert client
    bert = Bert(bert_model_path=BERT_MODEL_PATH, client_ip='0.0.0.0')

    # build train features
    train_dataset = pd.read_csv('../../data/processed/train_dataset.csv')
    train_vectors, train_targets = build_features(train_dataset, bert)
    np.save('../../data/features/train_vectors', train_vectors)
    np.save('../../data/features/train_targets', train_targets)

    # build test features
    test_dataset = pd.read_csv('../../data/processed/test_dataset.csv')
    test_vectors, test_targets = build_features(test_dataset, bert)
    np.save('../../data/features/test_vectors', test_vectors)
    np.save('../../data/features/test_targets', test_targets)

    p.terminate()


if __name__ == '__main__':
    main()

Modelltraining

Die Klasse "MediaClassifier", die ein Modell zur Klassifizierung von Nachrichtenmedien definiert, wird wie folgt implementiert.

src/models/classifier.py


import os
import uuid
import pickle
import numpy as np
import lightgbm as lgb
import optuna
from datetime import datetime, timedelta, timezone
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score


class MediaClassifier():
    """Livedoor News Corpus Mehrklassenklassifizierungsmodell"""

    def __init__(self, output_dir, use_gpu=False):
        JST = timezone(timedelta(hours=+9), 'JST')
        dt_now = datetime.now(JST)
        training_date = dt_now.strftime("%Y%m%d_%H%M%S")
        self.output_dir = os.path.join(output_dir, training_date)
        os.makedirs(self.output_dir, exist_ok=True)
        
        self.device = 'gpu' if use_gpu else 'cpu'

    def train(self, features, targets):
        X_train, X_test, y_train, y_test = train_test_split(
            features, targets, test_size=0.2, random_state=0)

        def objectives(trial):
            trial_uuid = str(uuid.uuid4())
            trial.set_user_attr("trial_uuid", trial_uuid)

            #Parameter- und Rückrufeinstellungen
            params = {
                #Da die Anzahl der Medien im Lebertür-Nachrichtenkorpus 9, 9 Klassifikationen mit mehreren Klassen beträgt
                'objective': 'multiclass',
                'num_class': 9,
                'metric': 'multi_logloss',
                'num_leaves': trial.suggest_int("num_leaves", 10, 500),
                'feature_fraction': trial.suggest_uniform("feature_fraction", 0.0, 1.0),
                'class_weight': 'balanced',
                'device': self.device,
                'verbose': -1
            }

            pruning_callback = optuna.integration.LightGBMPruningCallback(
                trial, "multi_logloss")

            # training
            lgb_model = lgb.train(params, lgb.Dataset(X_train, y_train), num_boost_round=100,
                                  valid_sets=lgb.Dataset(X_test, y_test), callbacks=[pruning_callback])

            y_pred_train = np.argmax(lgb_model.predict(X_train), axis=1)
            y_pred_test = np.argmax(lgb_model.predict(X_test), axis=1)
            accuracy_train = accuracy_score(y_train, y_pred_train)
            accuracy_test = accuracy_score(y_test, y_pred_test)

            trial.set_user_attr("accuracy_train", accuracy_train)
            trial.set_user_attr("accuracy_test", accuracy_test)

            #Modell speichern
            output_file = os.path.join(self.output_dir, f"{trial_uuid}.pkl")
            with open(output_file, "wb") as fp:
                pickle.dump(lgb_model, fp)

            return 1.0 - accuracy_test

        study = optuna.create_study()
        study.optimize(objectives, n_trials=100)

        result_df = study.trials_dataframe()
        result_csv = os.path.join(self.output_dir, "result.csv")
        result_df.to_csv(result_csv, index=False)

        return study.best_trial.user_attrs

Führen Sie das Training mit dem oben genannten Modell durch.

src/models/train_model.py


import numpy as np
from classifier import MediaClassifier


def main():
    train_vectors = np.load('../../data/features/train_vectors.npy')
    train_targets = np.load('../../data/features/train_targets.npy')

    model = MediaClassifier(output_dir='../../models/training_models',
                            use_gpu=False)

    best_result = model.train(train_vectors, train_targets)
    print('best result \n', best_result)


if __name__ == '__main__':
    main()

Nach Abschluss der Ausführung werden die Test-UUID und die Punktzahl des Modells mit der besten Leistung wie folgt ausgegeben. Notieren Sie sich dies.

{'trial_uuid': 'BEST_MODEL_TRIAL_UUID', 'accuracy_train': 1.0, 'accuracy_test': 0.7398190045248869}

Der Teil BEST_MODEL_TRIAL_UUID ist tatsächlich uuid.

Auswertung des Modells mit Testdaten

Die Auswertung unter Verwendung von Testdaten wird wie folgt durchgeführt.

src/models/predict_model.py


import argparse
import pickle
import numpy as np
from sklearn.metrics import accuracy_score


def main(args):
    test_vectors = np.load('../../data/features/test_vectors.npy')
    test_targets = np.load('../../data/features/test_targets.npy')

    with open(args.best_model, 'rb') as f:
        model = pickle.load(f)

    pred_targets = np.argmax(model.predict(test_vectors), axis=1)
    accuracy = accuracy_score(test_targets, pred_targets)
    print('test accuracy : {:.2f}'.format(accuracy))

    
if __name__ == '__main__':
    parser = argparse.ArgumentParser()

    parser.add_argument('--best_model', help='best model pickle file path.')

    args = parser.parse_args()

    main(args)

Das Verzeichnis wird automatisch generiert, wenn Sie mit dem Training des Modells beginnen. Geben Sie daher den Pfad an. Das Folgende ist ein Ausführungsbeispiel.

$ cd src/models
$ python predict_model.py --best_model='../../models/training_models/TRINING_DATE/BEST_MODEL_TRIAL_UUID.pkl'

test accuracy : 0.73

Die richtige Antwortrate war "0,73" in dem Modell, das ich tatsächlich erstellt habe. Es ist nicht sehr teuer, aber ich denke, es kann ein wenig mehr erhöht werden, indem die Datenmenge erhöht und Wege zur Trennung von Texten entwickelt werden.

Ende des Behälters

Verlassen Sie den Container mit "exit" und verlassen Sie ihn mit "docker-compose down".

Recommended Posts

Erstellen Sie mit BERT + LightGBM + optuna ganz einfach ein Modell für die Verarbeitung natürlicher Sprache
Erstellen Sie mit Laragon ganz einfach eine Entwicklungsumgebung
3. Verarbeitung natürlicher Sprache durch Python 2-1. Netzwerk für das gleichzeitige Auftreten
3. Verarbeitung natürlicher Sprache durch Python 1-1. Word N-Gramm
Ich habe versucht, natürliche Sprache mit Transformatoren zu verarbeiten.
3. Verarbeitung natürlicher Sprache mit Python 1-2. So erstellen Sie einen Korpus: Aozora Bunko
Erstellen Sie eine Entwicklungsumgebung für die C-Sprache mit einem Container
3. Verarbeitung natürlicher Sprache durch Python 2-2. Koexistenznetzwerk [mecab-ipadic-NEologd]
[Python] Ich habe mit der Verarbeitung natürlicher Sprache ~ Transformatoren ~ gespielt
Lassen Sie uns die Verarbeitung natürlicher Sprache mit der COTOHA-API genießen
Richten Sie eine Entwicklungsumgebung für die Verarbeitung natürlicher Sprache ein
Python: Verarbeitung natürlicher Sprache
Modell unter Verwendung eines Faltungsnetzwerks in der Verarbeitung natürlicher Sprache
RNN_LSTM2 Verarbeitung natürlicher Sprache
Erstellen einer Umgebung für die Verarbeitung natürlicher Sprache mit Python
Verarbeitung natürlicher Sprache (Originaldaten) mit Word2Vec, entwickelt von US-amerikanischen Google-Forschern
[Übung] Erstellen Sie eine Watson-App mit Python! # 3 [Klassifizierung der natürlichen Sprache]
Ich habe versucht, in einem tief erlernten Sprachmodell zu schreiben
100 Sprachverarbeitungsklopfen mit Python 2015
Verarbeitung natürlicher Sprache 1 Morphologische Analyse
Anpassen der LightGBM-Parameter mit Optuna
Verarbeitung natürlicher Sprache 3 Wortkontinuität
Erstellen Sie einfach CNNs mit Keras
Einfach cProfile mit einem Dekorateur
Verarbeitung natürlicher Sprache 2 Wortähnlichkeit
Ich werde eine detaillierte Erklärung zum Tod schreiben, während ich 100 Python für die Verarbeitung natürlicher Sprache 2020 mit Python löse
Dockerfile mit den notwendigen Bibliotheken für die Verarbeitung natürlicher Sprache mit Python
Fassen Sie mit tf.data.Dataset api zusammen, wie Text (Verarbeitung natürlicher Sprache) vorverarbeitet wird
Fallstudie zur Verarbeitung natürlicher Sprache: Worthäufigkeit in 'Anne mit einem E'
100 Klicks in der Verarbeitung natürlicher Sprache Kapitel 4 Kommentar
100 Sprachverarbeitungsklopfen mit Python (Kapitel 1)
Erstellen Sie eine Deb-Datei mit Docker
Natürliche Sprache: Word2Vec Part3 - CBOW-Modell
100 Sprachverarbeitungsklopfen mit Python (Kapitel 3)
Künstliche Sprache Logivan und Verarbeitung natürlicher Sprache (Verarbeitung künstlicher Sprache)
Erstellen Sie eine Webanwendung mit Django
Erstellen Sie mit Vagrant ganz einfach virtuelle Maschinen
Erstellen Sie mit PySide einen Modelliterator
Vorbereitung zum Starten der Verarbeitung natürlicher Sprache
Installationszusammenfassung des Analysators für die Verarbeitung natürlicher Sprache
Zeichnen Sie einfach eine Karte mit matplotlib.basemap
Natürliche Sprache: Word2Vec Part2 - Skip-Gramm-Modell
Optimieren Sie RF oder lightGBM mit Optuna
Lernen Sie die Grundlagen der Dokumentklassifizierung durch Verarbeitung natürlicher Sprache, Themenmodell
Das stimmt, lass es uns essen. [Verarbeitung natürlicher Sprache beginnend mit Kyoto Ben]
[Verarbeitung natürlicher Sprache] Extrahieren Sie Schlüsselwörter aus der Kakenhi-Datenbank mit MeCab-ipadic-neologd und termextract