Ich habe Satzstück, einen Tokenizer für die Verarbeitung neuronaler Sprachen, auf die Klassifizierung von Dokumenten angewendet.
Neulich habe ich das Satzstück als Option zur Wortaufteilung in der Verarbeitung natürlicher Sprache kennengelernt. Es scheint, dass die maschinelle Übersetzung eine Punktzahl erreicht hat, die über der herkömmlichen Wortteilungsmethode liegt, und ich war einfach daran interessiert, und ich habe mich gefragt, was mit der Dokumentklassifizierung passieren würde, an der ich gerade arbeite, also habe ich es versucht.
SentencePiece(GitHub) Artikel des Autors taku910 (Qiita)
Ich habe KNB Analyzed Blog Corpus verwendet. Dies ist ein analysierter Blog-Korpus mit insgesamt 4.186 Sätzen, die in vier Kategorien unterteilt sind: "Kyoto Sightseeing", "Handy", "Sport" und "Gourmet", einschließlich Morphologie und Groß- und Kleinschreibung. Dieses Mal werden wir nur Kategorien und Sätze verwenden, um das Klassifizierungsproblem zu lösen, zu welcher Kategorie jeder Satz gehört. 10% aller Daten wurden als Testdaten aufgeteilt, und die restlichen 90% wurden für das Training mit SentencePiece und neuronalen Netzwerken verwendet.
Ich habe es unter Python 3.6.1 unter Bash unter Windows ausgeführt. Die detaillierte Version des Python-Moduls finden Sie unter require.txt.
Der Code ist in GitHub zusammengefasst. Ich bin noch unreif, daher würde ich mich freuen, wenn Sie auf Fehler hinweisen oder mir Ratschläge geben könnten.
Grundsätzlich scheint Satzstück von der Kommandozeile aus verwendet zu werden, aber ich wollte es von Python aus verwenden und ich wollte es einfach mit Mecab verwenden, daher ist es nicht sehr intelligent, aber ich habe es aus dem Unterprozess aufgerufen.
def train_sentencepiece(self, vocab_size):
cmd = "spm_train --input=" + self.native_text + \
" --model_prefix=" + self.model_path + \
" --vocab_size=" + str(vocab_size)
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout_data, stderr_data = p.communicate()
Wenn ich separat mit dem gelernten Modell schreibe, dauert es zu lange, jede Zeile zu verarbeiten. Deshalb schreibe ich sie einmal in eine Textdatei und mache alles auf einmal. Ich habe es diesmal nicht verwendet, aber ich habe auch eine Funktion zum Teilen von Zeichen für Zeichen hinzugefügt, um auf Zeichenebene zu lernen.
Dieses Mal werden wir Satzstück und Mecab + Neologd vergleichen
Ich wollte LSTM für das Netzwerk verwenden, aber das Lernen nimmt viel Zeit in Anspruch, deshalb habe ich mich diesmal für CNN entschieden. Wir haben ein Netzwerk mit drei Arten von Filtern implementiert: 3, 4 und 5 Wörter.
class CNN(Chain):
def __init__(self, n_vocab, n_units, n_out, filter_size=(3, 4, 5), stride=1, use_dropout=0.5, ignore_label=-1):
super(CNN, self).__init__()
initializer = initializers.HeNormal()
with self.init_scope():
self.word_embed=L.EmbedID(n_vocab, n_units, ignore_label=-1)
self.conv1 = L.Convolution2D(None, n_units, (filter_size[0], n_units), stride, pad=(filter_size[0], 0), initialW=initializer)
self.conv2 = L.Convolution2D(None, n_units, (filter_size[1], n_units), stride, pad=(filter_size[1], 0), initialW=initializer)
self.conv3 = L.Convolution2D(None, n_units, (filter_size[2], n_units), stride, pad=(filter_size[2], 0), initialW=initializer)
self.norm1 = L.BatchNormalization(n_units)
self.norm2 = L.BatchNormalization(n_units)
self.norm3 = L.BatchNormalization(n_units)
self.l1 = L.Linear(None, n_units)
self.l2 = L.Linear(None, n_out)
self.use_dropout = use_dropout
self.filter_size = filter_size
def forward(self, x, train):
with using_config('train', train):
x = Variable(x)
x = self.word_embed(x)
x = F.dropout(x, ratio=self.use_dropout)
x = F.expand_dims(x, axis=1)
x1 = F.relu(self.norm1(self.conv1(x)))
x1 = F.max_pooling_2d(x1, self.filter_size[0])
x2 = F.relu(self.norm2(self.conv2(x)))
x2 = F.max_pooling_2d(x2, self.filter_size[1])
x3 = F.relu(self.norm3(self.conv3(x)))
x3 = F.max_pooling_2d(x3, self.filter_size[2])
x = F.concat((x1, x2, x3), axis=2)
x = F.dropout(F.relu(self.l1(x)), ratio=self.use_dropout)
x = self.l2(x)
return x
Andere Parameter wurden wie folgt eingestellt.
Anzahl der Einheiten | Mini-Chargengröße | max epoch | WeightDecay | GradientClipping | Optimizer |
---|---|---|---|---|---|
256 | 32 | 30 | 0.001 | 5.0 | Adam |
Tokenizer | mecab+neologd | SentencePiece |
---|---|---|
Beste Genauigkeit | 0.68496418 | 0.668257773 |
Hmmm ... nicht sehr gut War die Anzahl der Sätze zu gering, da nur die Textdaten für den Zug zum Lernen von Satzteil verwendet wurden? Ich habe versucht, das Modell des Satzstücks unter jawiki (2017/05/01 neueste Version) zu lernen.
Tokenizer | mecab+neologd | SentencePiece | SentencePiece(Lerne mit jawiki) |
---|---|---|---|
Beste Genauigkeit | 0.68496418 | 0.668257773 | 0.758949876 |
Diesmal sieht es gut aus.
Die Genauigkeit für jede Epoche ist wie folgt.
Ich habe versucht, einige Sätze zu probieren, die tatsächlich geteilt waren
【SentencePiece】
Es ist zu klein / te / press / press / würzig /.
Wie / wie / Speer / nimm / ga / Fortsetzung / ku / kana / a / ♪
Ein anderer / einer / hartnäckig / Spannung / ri /, / ich denke / ich denke /.
[Satzstück (gelernt auf jawiki)]
Klein / Sa / Too / Te / Button / Press / Spicy / Spicy / of /.
Do / no / ku / rai / ya / ri / take / continue / no / kana / a / ♪
A / und / Bereits / Eins / Hartnäckig / Zhang / Ri /, / Shi / Yo / Ka / To / Think / U /.
【mecab + neologd】
Klein / zu / te / Knopf / drücken / würzig / von / ist / ist /.
Wie viel / wie viel / Austausch / ist / geht weiter / / oder / hey / ♪
Ah / und ein anderer / einer / mein Bestes geben /, / lass uns / oder / denken / denken /.
Selbst mit dem gleichen Satzstück habe ich das Gefühl, dass das Lernen mit Jawiki detaillierter ist. Mecab + neologd ist dem Menschen sinnlich nahe, aber es ist interessant, dass dies nicht bedeutet, dass das Lernen neuronaler Netze zu guten Ergebnissen führt.
Dieses Mal wurden alle Parametereinstellungen wie die Anzahl der Einheiten festgelegt, daher denke ich, dass es notwendig ist, die richtigen Einstellungen vorzunehmen und mit den besten zu vergleichen. Wie ich im Abschnitt über Trennzeichen ein wenig erwähnt habe, möchte ich auch einen Vergleich mit dem Lernen auf Charakterebene versuchen. Danach habe ich einen Satz verwendet, der sich von den Zugdaten unterscheidet, um Satzstück zu lernen, diesmal Jawiki, aber ich möchte überprüfen, wie andere Sätze die Genauigkeit beeinflussen.
Zuerst habe ich es unter CentOS (Docker) versucht, aber ich konnte Satzstück nicht gut installieren. Ich habe aufgegeben, aber es scheint, dass es unter CentOS installiert werden kann, wenn die folgenden Elemente zusätzlich zur GitHub-Prozedur enthalten sind.
$ yum install protobuf-devel boost-devel gflags-devel lmdb-devel
Recommended Posts