[PYTHON] Implementierung des Chainer-Serienlernens mit Mini-Batch variabler Länge

Einführung

logo.png

NStep LSTM wurde in der Version von Chainer 1.16.0 implementiert. Wie der Name schon sagt, ist NStep LSTM ein Modell, das mehrschichtiges LSTM problemlos realisieren kann. Intern wird RNN verwendet, das mit cuDNN optimiert wurde, und es arbeitet schneller als das herkömmliche LSTM. Darüber hinaus ist es mit NStep LSTM ** nicht mehr erforderlich, die Länge der Mini-Batch-Daten ** abzugleichen, und Sie können jetzt jede Probe unverändert in eine Liste eingeben. Sie müssen nicht mehr mit -1 auffüllen und ignore_label = -1 und where verwenden oder eine nach Datenlänge sortierte Liste transponieren und eingeben.

Deshalb habe ich dieses Mal versucht, die Serienbeschriftung mit diesem NStep LSTM zu lernen.

Unterschied in der Schnittstelle zu herkömmlichem LSTM

Da NStep LSTM eine andere Ein- / Ausgabe als herkömmliches LSTM hat, ist es nicht möglich, das bisher implementierte Modell einfach durch NStep LSTM zu ersetzen.

Die Eingabe und Ausgabe von \ _ \ _ init \ _ \ _ () und \ _ \ _ call \ _ \ _ () von NStep LSTM sind wie folgt.

NStepLSTM.__init__(n_layers, in_size, out_size, dropout, use_cudnn=True)
"""
n_layers (int): Number of layers.
in_size (int): Dimensionality of input vectors.
out_size (int): Dimensionality of hidden states and output vectors.
dropout (float): Dropout ratio.
use_cudnn (bool): Use cuDNN.
"""

...

NStepLSTM.__call__(hx, cx, xs, train=True)
"""
hx (~chainer.Variable): Initial hidden states.
cx (~chainer.Variable): Initial cell states.
xs (list of ~chianer.Variable): List of input sequences.
        Each element ``xs[i]`` is a :class:`chainer.Variable` holding a sequence.
"""
    ...

    return hy, cy, ys

Andererseits war das herkömmliche LSTM wie folgt.

LSTM.__init__(in_size, out_size, **kwargs)
"""
in_size (int) – Dimension of input vectors. If None, parameter initialization will be deferred until the first forward data pass at which time the size will be determined.
out_size (int) – Dimensionality of output vectors.
lateral_init – A callable that takes numpy.ndarray or cupy.ndarray and edits its value.
        It is used for initialization of the lateral connections.
        Maybe be None to use default initialization.
upward_init – A callable that takes numpy.ndarray or cupy.ndarray and edits its value.
        It is used for initialization of the upward connections.
        Maybe be None to use default initialization.
bias_init – A callable that takes numpy.ndarray or cupy.ndarray and edits its value.
        It is used for initialization of the biases of cell input, input gate and output gate, and gates of the upward connection.
        Maybe a scalar, in that case, the bias is initialized by this value.
        Maybe be None to use default initialization.
forget_bias_init – A callable that takes numpy.ndarray or cupy.ndarray and edits its value.
        It is used for initialization of the biases of the forget gate of the upward connection.
        Maybe a scalar, in that case, the bias is initialized by this value.
        Maybe be None to use default initialization.
"""

...

LSTM.__call__(x)
"""
x (~chainer.Variable): A new batch from the input sequence.
"""
    ...

    return y

Daher wird NStep LSTM in den folgenden Punkten anders behandelt als LSTM.

Der große Unterschied besteht darin, dass der Aufruf von \ _ \ _call () \ _ \ _ die anfänglichen verborgenen Zustände und Zellenzustände erhält und die Ein- und Ausgänge aufgelistet werden.

Erleichtern Sie die Handhabung von NStep LSTM

Implementieren Sie Unterklassen, um die NStep-LSTM-Initialisierung und -Aufrufe so nah wie möglich an LSTM zu bringen.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from chainer import Variable
import chainer.links as L
import numpy as np


class LSTM(L.NStepLSTM):

    def __init__(self, in_size, out_size, dropout=0.5, use_cudnn=True):
        n_layers = 1
        super(LSTM, self).__init__(n_layers, in_size, out_size, dropout, use_cudnn)
        self.state_size = out_size
        self.reset_state()

    def to_cpu(self):
        super(LSTM, self).to_cpu()
        if self.cx is not None:
            self.cx.to_cpu()
        if self.hx is not None:
            self.hx.to_cpu()

    def to_gpu(self, device=None):
        super(LSTM, self).to_gpu(device)
        if self.cx is not None:
            self.cx.to_gpu(device)
        if self.hx is not None:
            self.hx.to_gpu(device)

    def set_state(self, cx, hx):
        assert isinstance(cx, Variable)
        assert isinstance(hx, Variable)
        cx_ = cx
        hx_ = hx
        if self.xp == np:
            cx_.to_cpu()
            hx_.to_cpu()
        else:
            cx_.to_gpu()
            hx_.to_gpu()
        self.cx = cx_
        self.hx = hx_

    def reset_state(self):
        self.cx = self.hx = None

    def __call__(self, xs, train=True):
        batch = len(xs)
        if self.hx is None:
            xp = self.xp
            self.hx = Variable(
                xp.zeros((self.n_layers, batch, self.state_size), dtype=xs[0].dtype),
                volatile='auto')
        if self.cx is None:
            xp = self.xp
            self.cx = Variable(
                xp.zeros((self.n_layers, batch, self.state_size), dtype=xs[0].dtype),
                volatile='auto')

        hy, cy, ys = super(LSTM, self).__call__(self.hx, self.cx, xs, train)
        self.hx, self.cx = hy, cy
        return ys

In der obigen Klasse wird \ _ \ _ init () \ _ \ _ wie zuvor nur in_size und out_size angegeben (Standardwert für Dropout ist 0,5, fest auf n_layers = 1 ohne Mehrschichtigkeit von LSTM). .. \ _ \ _ Call () \ _ \ _ initialisiert automatisch cx und hx und gibt nur die Liste von chainer.Variable ein und aus.

Bidirektionales LSTM mit NStep LSTM implementiert

Implementieren Sie bidirektionales LSTM mit NStep LSTM. Erstellen Sie eine Liste für die Rückwärts-LSTM-Eingabe, indem Sie jedes Sample des Chainers umkehren. Variable Liste, die an die Vorwärts-LSTM übergeben werden soll. Richten Sie nach der Berechnung der Ausgabe mit Vorwärts-LSTM und Rückwärts-LSTM ** die Ausrichtung jedes Samples in jeder Ausgabeliste aus und ** verketten Sie, um einen Vektor zu erstellen. In der folgenden Klasse wird eine lineare Operation hinzugefügt, sodass out_size die Anzahl der Beschriftungen für die Serienbeschriftung ist.

class BLSTMBase(Chain):

    def __init__(self, embeddings, n_labels, dropout=0.5, train=True):
        vocab_size, embed_size = embeddings.shape
        feature_size = embed_size
        super(BLSTMBase, self).__init__(
            embed=L.EmbedID(
                in_size=vocab_size,
                out_size=embed_size,
                initialW=embeddings,
            ),
            f_lstm=LSTM(feature_size, feature_size, dropout),
            b_lstm=LSTM(feature_size, feature_size, dropout),
            linear=L.Linear(feature_size * 2, n_labels),
        )
        self._dropout = dropout
        self._n_labels = n_labels
        self.train = train

    def reset_state(self):
        self.f_lstm.reset_state()
        self.b_lstm.reset_state()

    def __call__(self, xs):
        self.reset_state()
        xs_f = []
        xs_b = []
        for x in xs:
            _x = self.embed(self.xp.array(x))
            xs_f.append(_x)
            xs_b.append(_x[::-1])
        hs_f = self.f_lstm(xs_f, self.train)
        hs_b = self.b_lstm(xs_b, self.train)
        ys = [self.linear(F.dropout(F.concat([h_f, h_b[::-1]]), ratio=self._dropout, train=self.train)) for h_f, h_b in zip(hs_f, hs_b)]
        return ys

Lernen Sie die Serienbeschriftung mit bidirektionalem LSTM

Verwenden wir das oben implementierte Modell und wenden es auf die Aufgabe der Serienbeschriftung an. Ich habe die chinesische Wortsegmentierung als Serienbeschriftungsproblem gewählt, bei dem häufig bidirektionales LSTM verwendet wird. Chinesisch hat keine durch Leerzeichen getrennten Wörter wie Englisch. Daher müssen Sie vor der Verarbeitung des Textes Wortgrenzen identifizieren.

Beispiel)

Winter, kann tragen, tragen, tragen; Sommer, Noh (kann) tragen (tragen) Viele (mehr) wenig (wenig) tragen (tragen) viele (mehr) wenig (wenig).

[Chen+, 2015]

Das obige Beispiel hat unterschiedliche Bedeutungen, je nachdem, ob es in "einige" oder "viele" und "kleine" unterteilt ist. Da die Struktur des Satzes fast gleich ist, wird der Begrenzer im Kontext der umgebenden Wörter beurteilt.

B (Beginn, der Anfang eines Wortes mit zwei oder mehr Buchstaben), M (Mitte, die Mitte eines Wortes mit zwei oder mehr Buchstaben), E (Ende) für eine Zeichenfolge, um das Aufteilen chinesischer Wörter als Sequenzbeschriftungsproblem zu lernen. , Ende von zwei oder mehr Buchstabenwörtern), S (einzelnes Wort mit einem Buchstaben). Unter Verwendung der Textdaten mit dieser Bezeichnung lernen wir die jedem Zeichen zugewiesene Bezeichnung aus den Kontextinformationen der Wortzeichenfolge.

Experiment

Zieldatensatz

PKU (Peking University Corpus, Standarddatensatz für das Benchmarking der chinesischen Wortsegmentierung)

Umgebung

Modell- und Experimenteinstellungen

Screen Shot 2016-12-03 at 05.36.56.png [Yao +, 2016] * Sehr ähnlich dem obigen Modell [^ 1]

Versuchsergebnis

Lernprozess und Ergebnisse dieses Modells

Der Lernprozess wird im Folgenden so beschrieben, wie er ist.

hiroki-t:/private/work/blstm-cws$ python app/train.py --save -e 10 --gpu 0
2016-12-03 09:34:06.27 JST      13a653  [info]  LOG Start with ACCESSID=[13a653] UNIQUEID=[UNIQID] ACCESSTIME=[2016-12-03 09:34:06.026907 JST]
2016-12-03 09:34:06.27 JST      13a653  [info]  *** [START] ***
2016-12-03 09:34:06.27 JST      13a653  [info]  initialize preprocessor with /private/work/blstm-cws/app/../data/zhwiki-embeddings-100.txt
2016-12-03 09:34:06.526 JST     13a653  [info]  load train dataset from /private/work/blstm-cws/app/../data/icwb2-data/training/pku_training.utf8
2016-12-03 09:34:14.134 JST     13a653  [info]  load test dataset from /private/work/blstm-cws/app/../data/icwb2-data/gold/pku_test_gold.utf8
2016-12-03 09:34:14.589 JST     13a653  [trace]
2016-12-03 09:34:14.589 JST     13a653  [trace] initialize ...
2016-12-03 09:34:14.589 JST     13a653  [trace] --------------------------------
2016-12-03 09:34:14.589 JST     13a653  [info]  # Minibatch-size: 20
2016-12-03 09:34:14.589 JST     13a653  [info]  # epoch: 10
2016-12-03 09:34:14.589 JST     13a653  [info]  # gpu: 0
2016-12-03 09:34:14.589 JST     13a653  [info]  # hyper-parameters: {'adagrad_lr': 0.2, 'dropout_ratio': 0.2, 'weight_decay': 0.0001}
2016-12-03 09:34:14.590 JST     13a653  [trace] --------------------------------
2016-12-03 09:34:14.590 JST     13a653  [trace]
100% (19054 of 19054) |#######################################| Elapsed Time: 0:07:50 Time: 0:07:50
2016-12-03 09:42:05.642 JST     13a653  [info]  [training] epoch 1 - #samples: 19054, loss: 9.640346, accuracy: 0.834476
100% (1944 of 1944) |#########################################| Elapsed Time: 0:00:29 Time: 0:00:29
2016-12-03 09:42:34.865 JST     13a653  [info]  [evaluation] epoch 1 - #samples: 1944, loss: 6.919845, accuracy: 0.890557
2016-12-03 09:42:34.866 JST     13a653  [trace] -
100% (19054 of 19054) |#######################################| Elapsed Time: 0:07:40 Time: 0:07:40
2016-12-03 09:50:15.258 JST     13a653  [info]  [training] epoch 2 - #samples: 19054, loss: 5.526157, accuracy: 0.903373
100% (1944 of 1944) |#########################################| Elapsed Time: 0:00:24 Time: 0:00:24
2016-12-03 09:50:39.400 JST     13a653  [info]  [evaluation] epoch 2 - #samples: 1944, loss: 6.233129, accuracy: 0.900318
2016-12-03 09:50:39.401 JST     13a653  [trace] -
100% (19054 of 19054) |#######################################| Elapsed Time: 0:08:41 Time: 0:08:41
2016-12-03 09:59:21.301 JST     13a653  [info]  [training] epoch 3 - #samples: 19054, loss: 4.217260, accuracy: 0.921377
100% (1944 of 1944) |#########################################| Elapsed Time: 0:00:24 Time: 0:00:24
2016-12-03 09:59:45.587 JST     13a653  [info]  [evaluation] epoch 3 - #samples: 1944, loss: 5.650668, accuracy: 0.913843
2016-12-03 09:59:45.587 JST     13a653  [trace] -
100% (19054 of 19054) |#######################################| Elapsed Time: 0:07:25 Time: 0:07:25
2016-12-03 10:07:11.451 JST     13a653  [info]  [training] epoch 4 - #samples: 19054, loss: 3.488712, accuracy: 0.931668
100% (1944 of 1944) |#########################################| Elapsed Time: 0:00:26 Time: 0:00:26
2016-12-03 10:07:37.889 JST     13a653  [info]  [evaluation] epoch 4 - #samples: 1944, loss: 5.342249, accuracy: 0.917103
2016-12-03 10:07:37.890 JST     13a653  [trace] -
100% (19054 of 19054) |#######################################| Elapsed Time: 0:07:26 Time: 0:07:26
2016-12-03 10:15:03.919 JST     13a653  [info]  [training] epoch 5 - #samples: 19054, loss: 2.995683, accuracy: 0.938305
100% (1944 of 1944) |#########################################| Elapsed Time: 0:00:15 Time: 0:00:15
2016-12-03 10:15:19.749 JST     13a653  [info]  [evaluation] epoch 5 - #samples: 1944, loss: 5.320374, accuracy: 0.921863
2016-12-03 10:15:19.750 JST     13a653  [trace] -
100% (19054 of 19054) |########################################| Elapsed Time: 0:07:29 Time: 0:07:29
2016-12-03 10:22:49.393 JST     13a653  [info]  [training] epoch 6 - #samples: 19054, loss: 2.680496, accuracy: 0.943861
100% (1944 of 1944) |##########################################| Elapsed Time: 0:00:27 Time: 0:00:27
2016-12-03 10:23:16.985 JST     13a653  [info]  [evaluation] epoch 6 - #samples: 1944, loss: 5.326864, accuracy: 0.924161
2016-12-03 10:23:16.986 JST     13a653  [trace] -
100% (19054 of 19054) |########################################| Elapsed Time: 0:07:28 Time: 0:07:28
2016-12-03 10:30:45.772 JST     13a653  [info]  [training] epoch 7 - #samples: 19054, loss: 2.425466, accuracy: 0.947673
100% (1944 of 1944) |##########################################| Elapsed Time: 0:00:22 Time: 0:00:22
2016-12-03 10:31:08.448 JST     13a653  [info]  [evaluation] epoch 7 - #samples: 1944, loss: 5.270019, accuracy: 0.925341
2016-12-03 10:31:08.449 JST     13a653  [trace] -
100% (19054 of 19054) |########################################| Elapsed Time: 0:08:39 Time: 0:08:39
2016-12-03 10:39:47.461 JST     13a653  [info]  [training] epoch 8 - #samples: 19054, loss: 2.233068, accuracy: 0.950928
100% (1944 of 1944) |##########################################| Elapsed Time: 0:00:26 Time: 0:00:26
2016-12-03 10:40:14.2 JST       13a653  [info]  [evaluation] epoch 8 - #samples: 1944, loss: 5.792994, accuracy: 0.924707
2016-12-03 10:40:14.2 JST       13a653  [trace] -
100% (19054 of 19054) |########################################| Elapsed Time: 0:07:10 Time: 0:07:10
2016-12-03 10:47:24.806 JST     13a653  [info]  [training] epoch 9 - #samples: 19054, loss: 2.066807, accuracy: 0.953524
100% (1944 of 1944) |##########################################| Elapsed Time: 0:00:26 Time: 0:00:26
2016-12-03 10:47:51.745 JST     13a653  [info]  [evaluation] epoch 9 - #samples: 1944, loss: 5.864374, accuracy: 0.925294
2016-12-03 10:47:51.746 JST     13a653  [trace] -
100% (19054 of 19054) |########################################| Elapsed Time: 0:08:43 Time: 0:08:43
2016-12-03 10:56:34.758 JST     13a653  [info]  [training] epoch 10 - #samples: 19054, loss: 1.946193, accuracy: 0.955782
100% (1944 of 1944) |##########################################| Elapsed Time: 0:00:22 Time: 0:00:22
2016-12-03 10:56:57.641 JST     13a653  [info]  [evaluation] epoch 10 - #samples: 1944, loss: 5.284819, accuracy: 0.930201
2016-12-03 10:56:57.642 JST     13a653  [trace] -
2016-12-03 10:56:57.642 JST     13a653  [info]  saving the model to /private/work/blstm-cws/app/../output/cws.model ...
2016-12-03 10:56:58.520 JST     13a653  [info]  *** [DONE] ***
2016-12-03 10:56:58.521 JST     13a653  [info]  LOG End with ACCESSID=[13a653] UNIQUEID=[UNIQID] ACCESSTIME=[2016-12-03 09:34:06.026907 JST] PROCESSTIME=[4972.494370000]

Es ist nicht der Präzisions-, Rückruf-, F-Wert, sondern der Genauigkeitswert, aber es ist 93,0 in der 10. Epoche. Die Verarbeitungszeit betrug 10 Epochen, was etwas mehr als 80 Minuten betrug.

Vergleichen Sie mit den Ergebnissen früherer Studien

Screen Shot 2016-12-03 at 10.27.55.png [Yao+, 2016] [^2]

All the models are trained on NVIDIA GTX Geforce 970, it took about 16 to 17 hours to train a model on GPU while more than 4 days to train on CPU, in contrast.

[Yao+, 2016]

Es gibt einige Unterschiede zu früheren Untersuchungen, wie z. B. die Initialisierung von Einbettungen, aber es scheint, dass die Genauigkeit und Verarbeitungszeit des 1-Schicht-BLSTM angemessen sind.

Decoding

hiroki-t:/private/work/blstm-cws$ python app/parse.py
2016-12-03 11:01:13.343 JST     549e15  [info]  LOG Start with ACCESSID=[549e15] UNIQUEID=[UNIQID] ACCESSTIME=[2016-12-03 11:01:13.343412 JST]
2016-12-03 11:01:13.343 JST     549e15  [info]  *** [START] ***
2016-12-03 11:01:13.344 JST     549e15  [info]  initialize preprocessor with /private/work/blstm-cws/app/../data/zhwiki-embeddings-100.txt
2016-12-03 11:01:13.834 JST     549e15  [trace]
2016-12-03 11:01:13.834 JST     549e15  [trace] initialize ...
2016-12-03 11:01:13.834 JST     549e15  [trace]
2016-12-03 11:01:13.914 JST     549e15  [info]  loading a model from /private/work/blstm-cws/app/../output/cws.model ...
Input a Chinese sentence! (use 'q' to exit)
Der dritte Schritt der Modernisierung des chinesischen Volkes, eine neue Expedition.
B E B E B E S S B M E B E B E S B E B E B E S S B E S
Chinas Volksfortschritt Abschluss Modernisierung Bau Dritte Schritte Strategie Neue Eroberung.
-
q
2016-12-03 11:02:08.961 JST     549e15  [info]  *** [DONE] ***
2016-12-03 11:02:08.962 JST     549e15  [info]  LOG End with ACCESSID=[549e15] UNIQUEID=[UNIQID] ACCESSTIME=[2016-12-03 11:01:13.343412 JST] PROCESSTIME=[55.618552000]

# ^Hinweis[gold]Chinas Volksfortschritt Abschluss Modernisierung Bau Dritte Schritte Strategie Neue Eroberung.

Wenn die Decodierung basierend auf dem Lernergebnis durchgeführt wurde, wurden die korrekte Beschriftungssequenz und das Wortteilungsergebnis von der ungeteilten Zeichenfolge zurückgegeben.

abschließend

Ich habe die Serienbeschriftung mit bidirektionalem LSTM unter Verwendung von Chainers NStep LSTM gelernt. Mit der Unterstützung von Mini-Batch + CuDNN mit variabler Länge ist es einfacher, Eingabedaten zu verarbeiten, und die Berechnungsgeschwindigkeit ist schneller als zuvor. Das diesmal implementierte Modell kann nicht nur für die Wortteilung auf Chinesisch, sondern auch für das Lernen von Serien verwendet werden. Daher kann es interessant sein, es auf andere Aufgaben wie das Markieren von Teilwörtern anzuwenden.

Der Quellcode ist auf GitHub verfügbar. https://github.com/chantera/blstm-cws

Zusätzlich zu dem oben eingeführten BLSTM enthält das Repository den Code, den ich tatsächlich in Kombination mit Chainer für die Implementierung von BLSTM + CRF und die Erforschung von NLP verwende. Ich hoffe, dass dies hilfreich sein wird.

Referenz


written by chantera at NAIST cllab

[^ 1]: [Yao +, 2016] gibt den Vektor v ∈ R ^ 2d der Ausgabe von BLSTM mit einer Matrix von W ∈ R ^ d * 2d in die d-Dimension zurück. [^ 2]: In [Yao +, 2016] wird die Dimension von Worteinbettungen auf 200 Dimensionen festgelegt, und aus den Zeichen des Trainingssatzes wird ein Wörterbuch ohne Vorschulung erstellt.

Recommended Posts

Implementierung des Chainer-Serienlernens mit Mini-Batch variabler Länge
Rank Learning über ein neuronales Netzwerk (RankNet-Implementierung von Chainer)
Über Variable von Chainer
Implementierung von TF-IDF mit Gensim
Tiefes Lernen der Verstärkung 2 Implementierung des Lernens der Verstärkung
Einfache Implementierung eines neuronalen Netzwerks mit Chainer
Bedeutung des maschinellen Lernens und des Mini-Batch-Lernens
Stärkung des Lernens 8 Versuchen Sie, die Chainer-Benutzeroberfläche zu verwenden
Implementierung von Desktop-Benachrichtigungen mit Python
Othello-Aus der dritten Zeile von "Implementation Deep Learning" (3)
Qiskit: Implementierung von Quantum Circuit Learning (QCL)
Implementierung eines 3-Schicht-Neuronalen Netzwerks (kein Lernen)
Algorithmus für maschinelles Lernen (Implementierung einer Klassifizierung mit mehreren Klassen)
Othello-Aus der dritten Zeile von "Implementation Deep Learning" (2)
[Lernnotiz] Deep Learning von Grund auf ~ Implementierung von Dropout ~
Implementierung eines Deep Learning-Modells zur Bilderkennung
Tiefes Lernen durch Implementierung (Segmentierung) ~ Implementierung von SegNet ~
Versuchen Sie es mit dem Jupyter Notebook von Azure Machine Learning
Kausales Denken mit maschinellem Lernen (Organisation von Methoden des kausalen Denkens)
[Für Anfänger im Deep Learning] Implementierung einer einfachen binären Klassifizierung durch vollständige Kopplung mit Keras
Implementierung der Clustering-K-Form-Methode für Zeitreihendaten [Unüberwachtes Lernen mit Python Kapitel 13]