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.
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.
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.
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
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.
PKU (Peking University Corpus, Standarddatensatz für das Benchmarking der chinesischen Wortsegmentierung)
[Yao +, 2016] * Sehr ähnlich dem obigen Modell [^ 1]
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.
[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.
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.
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