[PYTHON] Ich habe versucht, Kanas handschriftliche Zeichenerkennung durchzuführen. Teil 2/3 Datenerstellung und Lernen

Überblick

Letztes Mal (1/3): https://qiita.com/tfull_tf/items/6015bee4af7d48176736 Nächstes Mal (3/3): https://qiita.com/tfull_tf/items/d9fe3ab6c1e47d1b2e1e

Code: https://github.com/tfull/character_recognition

Bei der Erstellung des Kana-Erkennungssystems haben wir zunächst ein Modell mit CNN erstellt und bestätigt, wie genau es mit MNIST sein würde. Bereiten Sie als Nächstes die Bilddaten von Kana vor, erstellen Sie das Modell auf die gleiche Weise und verbessern Sie das Modell.

Daten erstellen

Ich kann mir keine Bilddaten für Kana vorstellen, daher werde ich sie automatisch erstellen. Derzeit scheinen einige Datensätze für die Öffentlichkeit zugänglich zu sein.

Verwenden Sie ImageMagick zur automatischen Generierung. Sie können dem Bild mit dem Befehl convert Text hinzufügen. Erstellen Sie also zuerst ein schwarzes Bild und schreiben Sie dann nur einen weißen Text darauf.

Datenproliferationsmethode

Um mehrere Bilder für ein Zeichen vorzubereiten, haben wir eine Methode zum Erhöhen der Daten vorbereitet.

1: Verwenden Sie mehrere Schriftarten

Wenn Sie in verschiedenen Schriftarten schreiben, können Sie anhand der Anzahl der Schriftarten unterschiedliche Bilder mit denselben Zeichen erstellen.

Sie können die Schriftart mit dem folgenden Befehl anzeigen. Nehmen Sie also die Schriftart, die als verwendbar erscheint.

convert -list font

Eine Sache, die Sie beachten sollten, ist, dass nicht alle Japanisch unterstützen. Selbst wenn Sie versuchen, Kana auszugeben, wird möglicherweise nichts ausgeschrieben.

Mac OS 10.15, an dem ich hauptsächlich arbeitete, hatte keine Schriftart, die gut aussah, also habe ich das Bild unter Ubuntu generiert. Die folgenden Schriftarten waren von Anfang an enthalten, daher habe ich mich für sie entschieden.

font_list = [
    "Noto-Sans-CJK-JP-Thin",
    "Noto-Sans-CJK-JP-Medium",
    "Noto-Serif-CJK-JP"
]

2: Ändern Sie die Größe der Zeichen

Sie können verschiedene Bilder erzeugen, indem Sie Volltext auf den Bildschirm schreiben oder ein wenig konservativ schreiben. Dieses Mal schrieb ich die Briefe, während ich die Größe schrittweise von etwa der Hälfte auf die Größe knapp darunter erhöhte.

3: Verschieben Sie die Buchstaben

Wenn Sie kleine Buchstaben schreiben, können Sie oben, unten, links und rechts Leerzeichen erstellen, sodass Sie die Technik zum vertikalen und horizontalen Verschieben der Buchstaben verwenden können. Wenn Sie beispielsweise daran denken, Blank / 2 und Blank / 3 nach oben, unten, links und rechts zu verschieben, können Sie 5 x 5 verschiedene Bilder generieren.

4: Drehe den Charakter

Sie können die Zeichen mit konvertieren drehen. Sie können die Anzahl der Bilder erhöhen, indem Sie sie leicht im oder gegen den Uhrzeigersinn drehen.

(Nicht verwendet) Unschärfe hinzufügen

Sie können die Anzahl der Bilder erhöhen, indem Sie ein unscharfes Bild vorbereiten. Wie steht es jedoch mit einem Bild, bei dem die Hälfte des Bildes unscharf ist? Ich habe es nicht getan, weil ich dachte. Eine ausreichende Anzahl von Bildern kann mit 1 bis 4 gesichert werden.

(Nicht verwendet) Fügen Sie Rauschen hinzu

Durch Hinzufügen von Rauschen wie kleinen Punkten zum Bild kann das Bild nicht nur vergrößert, sondern auch widerstandsfähiger gegen Rauschen werden. Ich habe es nicht getan, weil ich keinen einfachen Weg gefunden habe, um nette Geräusche hinzuzufügen, aber es könnte eine gute zukünftige Aufgabe sein.

Ergebnis

Erzeugt ein Bild mit Zeichen durch Kombination von 1 bis 4 (Multiplikation). Bei 256 Pixel in Höhe und Breite wurden mehr als 4000 Bilder für jedes Zeichen erhalten. Sie können die Anzahl der Blätter ändern, indem Sie mit den verschiedenen in der Methode verwendeten Parametern spielen. Es gibt 169 Arten von Hiragana (0x3041 ~ 0x3093) und Katakana (0x30A1 ~ 0x30F6), daher ist die Kapazität ziemlich groß.

Code


data_directory = "/path/to/data"
image_size = 256

#Ein schwarzes Bild erstellen
def make_template():
    res = subprocess.call([
        "convert",
        "-size", "{s}x{s}".format(s = image_size),
        "xc:black",
        "{}/tmp.png ".format(data_directory)
    ])

#Erstellen Sie ein Bild mit weißen Zeichen
def generate(path, font, pointsize, character, rotation, dx, dy):
    res = subprocess.call([
        "convert",
        "-gravity", "Center",
        "-font", font,
        "-pointsize", str(pointsize),
        "-fill", "White",
        "-annotate", format_t(rotation, dx, dy), character,
        "{}/tmp.png ".format(data_directory), path
    ])

#Formatfunktion verschieben
def format_t(rotation, x, y):
    xstr = "+" + str(x) if x >= 0 else str(x)
    ystr = "+" + str(y) if y >= 0 else str(y)
    return "{r}x{r}{x}{y}".format(r = rotation, x = xstr, y = ystr)

Erstellen Sie zum ersten Mal nur einmal ein schwarzes Bild und erstellen Sie ein Bild mit weißen Zeichen, während Sie die Parameter Schriftart, Punktgröße, Zeichen, Drehung, dx und dy in einer Schleife ändern.

Modellbau

Nachdem wir das Image haben, werden wir das Modell auf die gleiche Weise wie MNIST erstellen, aber es hat von Anfang an nicht funktioniert. Der Wert des Cross-Entropy-Fehlers ist für jeden Stapel gleich. Wenn Sie den Wert in der Ebene beim Training als Debug beobachten, enthält der Absolutwert einen großen Wert wie Hunderte oder Tausende und die Ausgabe War immer das gleiche. Aus diesem Grund konnten wir die Stapelnormalisierung einfügen, um die Genauigkeit erheblich zu verbessern.

import torch.nn as nn

class Model(nn.Module):
    def __init__(self, image_size, output):
        super(Model, self).__init__()
        n = ((image_size - 4) // 2 - 4) // 2

        self.conv1 = nn.Conv2d(1, 4, 5)
        self.relu1 = nn.ReLU()
        self.normal1 = nn.BatchNorm2d(4)
        self.pool1 = nn.MaxPool2d(2, 2)
        self.dropout1 = nn.Dropout2d(0.3)
        self.conv2 = nn.Conv2d(4, 16, 5)
        self.relu2 = nn.ReLU()
        self.normal2 = nn.BatchNorm2d(16)
        self.pool2 = nn.MaxPool2d(2, 2)
        self.dropout2 = nn.Dropout2d(0.3)
        self.flatten = nn.Flatten()
        self.linear1 = nn.Linear(n * n * 16, 1024)
        self.relu3 = nn.ReLU()
        self.normal3 = nn.BatchNorm1d(1024)
        self.dropout3 = nn.Dropout(0.3)
        self.linear2 = nn.Linear(1024, 256)
        self.relu4 = nn.ReLU()
        self.normal4 = nn.BatchNorm1d(256)
        self.dropout4 = nn.Dropout(0.3)
        self.linear3 = nn.Linear(256, output)
        self.softmax = nn.Softmax(dim = 1)

    def forward(self, x):
        x = self.conv1(x)
        x = self.relu1(x)
        x = self.normal1(x)
        x = self.pool1(x)
        x = self.dropout1(x)
        x = self.conv2(x)
        x = self.relu2(x)
        x = self.normal2(x)
        x = self.pool2(x)
        x = self.dropout2(x)
        x = self.flatten(x)
        x = self.linear1(x)
        x = self.relu3(x)
        x = self.normal3(x)
        x = self.dropout3(x)
        x = self.linear2(x)
        x = self.relu4(x)
        x = self.normal4(x)
        x = self.dropout4(x)
        x = self.linear3(x)
        x = self.softmax(x)
        return x

Lernen

Grundsätzlich werden wir nach dem gleichen Verfahren wie in MNIST trainieren. Ich habe Cross Entropy Loss, Adam, verwendet (Lernrate = 0,001).

Punkte, die beim Lernen beachtet werden müssen

Da das Bild beim Ändern der Parameter in einer Schleife erzeugt wurde, vermeiden Sie es, da die Daten verzerrt zu sein scheinen, wenn sie in der richtigen Reihenfolge trainiert werden. Da ich jeden Charakter gleichmäßig lernen möchte, möchte ich sie auch der Reihe nach lernen.

Wenn Sie trainieren, während Sie das Bild in einer Schleife lesen, lernen Sie ein Blatt in einem Stapel. Es gibt jedoch viele Bilddaten. Wenn Sie also alle auf einmal lesen, geht Ihnen möglicherweise der Speicher aus. Um beides zu vermeiden, entschied ich mich, Yield zu verwenden, um die Daten in Blöcken zu lesen.

# a1,Ermitteln Sie die Doppelschleife von a2 anhand der Anzahl der Chunks
def double_range(a1, a2, chunk = 100):
    records = []

    for x1 in a1:
        for x2 in a2:
            records.append((x1, x2))
            if len(records) >= chunk:
                yield records
                records = []

    if len(records) > 0:
        yield records

Eine Funktion, die zwei Arrays ergibt und die in einer Doppelschleife erhaltenen Paare um die Anzahl der Chunks zurückgibt. Geben Sie dies für weiter.

Pseudocode


for indices in double_range("1~Gemischte Bildnummern bis zu N.", "Nummer, die dem Charakter zugewiesen ist(0~168)"):
    inputs = []
    for i_character, i_image in indices:
        inputs.append("i_Zeichen i des zweiten Zeichens_Bild Lädt das erste Bild")

    model.train(inputs) #Lernen

Auf diese Weise kann die Speichernutzung reduziert werden, indem eine Schleife ausgeführt wird, die Bilder für die Stapelgröße liest und trainiert.

Modellleistung

4236 [Blätter / Zeichen] ✕ 169 [Zeichen] Ich habe das Experiment gestartet, nachdem ich die Bilddaten erstellt hatte. Unter Verwendung von 5% der Gesamtzahl als Testdaten haben wir mit 2 Epochen trainiert und die korrekte Antwortrate der Testdaten gemessen. Sie betrug etwa 71,4%. Zuerst habe ich einen Fehler im Programm gemacht und 4236 anstelle von 169 gewählt, aber zu dieser Zeit war es ein Rätsel, dass ungefähr 80% aus waren. Ich möchte die Leistung ein wenig verbessern, aber es scheint, dass ich ein Erkennungssystem erstellen und es vorerst ausführen kann.

Recommended Posts

Ich habe versucht, Kanas handschriftliche Zeichenerkennung durchzuführen. Teil 2/3 Datenerstellung und Lernen
Ich habe versucht, Kanas handschriftliche Zeichenerkennung Teil 3/3 Zusammenarbeit mit der GUI mithilfe von Tkinter durchzuführen
Ich habe versucht, das Bild zu verarbeiten und zu transformieren und die Daten für maschinelles Lernen zu erweitern
Ich habe versucht, Hanana Oba und Emiri Otani durch tiefes Lernen zu klassifizieren (Teil 2)
Ich habe versucht, eine einfache Bilderkennungs-API mit Fast API und Tensorflow zu erstellen
Ich habe versucht, mit Python faker verschiedene "Dummy-Daten" zu erstellen
Ich habe versucht, die Benutzeroberfläche neben Python und Tkinter dreiäugig zu gestalten
Ich habe versucht, Perceptron Teil 1 [Deep Learning von Grund auf neu] zu implementieren.
Ich habe versucht, Deep Learning mit Spark × Keras × Docker skalierbar zu machen
Ich habe versucht, mit Selenium und Python einen regelmäßigen Ausführungsprozess durchzuführen
Ich habe versucht, PyEZ und JSNAPy zu verwenden. Teil 2: Ich habe versucht, PyEZ zu verwenden
Ich habe eine Web-API erstellt
[Deep Learning von Grund auf neu] Ich habe versucht, Sigmoid Layer und Relu Layer zu implementieren
Ich habe versucht, Oba Hanana und Otani Emiri durch tiefes Lernen zu klassifizieren
Ich habe versucht, Runenfiguren mit Scikit-Learn handschriftlich zu erkennen
Ich habe versucht, PyEZ und JSNAPy zu verwenden. Teil 1: Übersicht
[Python] Ich habe versucht, 100 frühere Fragen zu lösen, die Anfänger und Fortgeschrittene lösen sollten [Teil 5/22]
Ich habe DCGAN implementiert und versucht, Äpfel zu generieren
Ich habe versucht, die Daten mit Zwietracht zu speichern
[Python] Ich habe versucht, 100 frühere Fragen zu lösen, die Anfänger und Fortgeschrittene lösen sollten [Teil 7/22]
Ich habe versucht, CloudWatch-Daten mit Python abzurufen
[Python] Ich habe versucht, 100 frühere Fragen zu lösen, die Anfänger und Fortgeschrittene lösen sollten [Teil 4/22]
[Python] Ich habe versucht, 100 frühere Fragen zu lösen, die Anfänger und Fortgeschrittene lösen sollten [Teil 3/22].
[Python] Ich habe versucht, 100 frühere Fragen zu lösen, die Anfänger und Fortgeschrittene lösen sollten [Teil 1/22]
Ich habe versucht, KI für Smash Bra zu machen
Einführung in die KI-Erstellung mit Python! Teil 3 Ich habe versucht, Bilder mit einem Convolutional Neural Network (CNN) zu klassifizieren und vorherzusagen.
[Python] Ich habe versucht, 100 frühere Fragen zu lösen, die Anfänger und Fortgeschrittene lösen sollten [Teil 6/22]
[Einführung in PID] Ich habe versucht, ♬ zu steuern und zu spielen
Ich habe versucht, eine verdächtige Person mithilfe von Geolonia-Adressdaten schnell zu einem MAP zu machen
Ich habe ein ○ ✕ Spiel mit TensorFlow gemacht
Ich habe versucht, Deep Learning mit Spark × Keras × Docker 2 Multi-Host-Edition skalierbar zu machen
Ich habe versucht, mit Python Machine Learning ein Echtzeit-Modell zur Trennung von Tonquellen zu erstellen
Ich habe versucht, Pferderennen vorherzusagen, indem ich alles von der Datenerfassung bis zum tiefen Lernen getan habe
Ich habe versucht, einen "verdammt großen Literaturkonverter" zu machen.
Ich habe versucht, maschinelles Lernen (Objekterkennung) mit TouchDesigner zu verschieben
Ich habe versucht, mit VOICEROID2 2 automatisch zu lesen und zu speichern
Ich habe versucht, CPython ein Post-Inkrement hinzuzufügen. Übersicht und Zusammenfassung
Ich habe versucht, das Spiel in der J League vorherzusagen (Datenanalyse)
Ich habe versucht, mit VOICEROID2 automatisch zu lesen und zu speichern
Ich habe versucht, Linux Systemaufrufe und Scheduler hinzuzufügen
Ich habe versucht, den negativen Teil von Meros zu löschen
Ich habe versucht, Grad-CAM mit Keras und Tensorflow zu implementieren
Ich habe versucht, eine OCR-App mit PySimpleGUI zu erstellen
Ich habe versucht, Dropout zu erklären
Ich habe versucht, Scrapy auf Anaconda zu installieren und konnte es nicht
Ich habe versucht, das Bild mithilfe von maschinellem Lernen zu komprimieren
Ich habe versucht, tief zu lernen
Ich habe versucht zu debuggen.
Einführung in die KI-Erstellung mit Python! Teil 1 Ich habe versucht, die Nummer anhand des handgeschriebenen Zahlenbildes zu klassifizieren und vorherzusagen
Ich habe versucht, die Yin- und Yang-Klassifikation hololiver Mitglieder durch maschinelles Lernen zu überprüfen
Ich habe versucht, Othello AI zu machen, dass ich 7,2 Millionen Hände durch tiefes Lernen mit Chainer gelernt habe
Ich habe versucht, Überlebende der Titanic mit Kaggle vorherzusagen und einzureichen
[Einführung in cx_Oracle] (Teil 6) Zuordnung von DB- und Python-Datentypen
Ich möchte Daten mit Python analysieren können (Teil 3)
Ich habe versucht, Videos mit der Youtube Data API (Anfänger) zu suchen.
Ich habe versucht, Discord Bot und Gesichtserkennung für LT zu kombinieren.
Ich möchte Daten mit Python analysieren können (Teil 1)
Ich habe versucht, die Videoerstellung durch parallele Verarbeitung zu beschleunigen