[PYTHON] Ich habe versucht, MNIST nach GNN zu klassifizieren (mit PyTorch-Geometrie).

Einführung

Hallo, ich heiße DNA1980. In letzter Zeit ist ** GNN (Graph Neural Network) ** populär geworden. Ich möchte auch dem Ablauf folgen und Diagramme verarbeiten, aber es gibt viele Diagrammdaten auf der Welt, mit denen ich nicht vertraut bin. Ich weiß nicht, was ich mache, wenn ich es klassifiziere ... Ich dachte, dass GNN angewendet werden könnte, wenn es in ein Diagramm integriert werden könnte, auch wenn es von Anfang an keine Diagrammstruktur hatte, wie z. B. ein Netzwerk, also habe ich es auf jedermanns Lieblings-MNIST angewendet.

Wenn Sie mit GNN nicht vertraut sind, gibt es einige, die ausführlich über Qiita geschrieben haben. Ich empfehle Ihnen daher, dies zu lesen. GNN-Zusammenfassung (1): Einführung von GCN

Der diesmal verwendete Code und der erstellte Datensatz werden auf Github hier veröffentlicht.

Umgebung

Python 3.7.6 PyTorch 1.4.0 PyTorch geometric 1.4.2

Dieses Mal habe ich PyTorch geometric als Bibliothek verwendet, die GNN verarbeitet.

Erstellen eines Datensatzes

Um GNN auf MNIST anzuwenden, das ein zweidimensionales Bild ist, muss es grafisch dargestellt werden.

・ Alle hellen Pixel von 0,4 oder mehr werden als Knoten verwendet. ・ Wenn das Originalbild Knoten in der Nähe von 8 enthält, fügen Sie eine Seite hinzu

Die Konvertierung wurde basierend auf den obigen Regeln durchgeführt.

(Da das Erstellen schwierig war, werden diesmal nur 60000 Daten für den Zug verwendet.)

Das Bild sieht so aus makegraph.png Hier ist der Code, mit dem der Datensatz dieses Mal erstellt wird. (Zuerst hatte ich vor, eine Seite um 24 zu legen, also ist sie extra gepolstert, aber keine Sorge) Da es nicht so viele gibt, habe ich es ehrlich implementiert, aber es scheint schneller zu sein, wenn ich Bitboard usw. verwende.


#Rufen Sie MNIST-Daten aus einer gzip-Datei auf, um sie zweidimensional zu machen
data = 0
with gzip.open('./train-images-idx3-ubyte.gz', 'rb') as f:
    data = np.frombuffer(f.read(), np.uint8, offset=16)
    data = data.reshape([-1,28,28])
data = np.where(data < 102, -1, 1000)

for e,imgtmp in enumerate(data):
    img = np.pad(imgtmp,[(2,2),(2,2)],"constant",constant_values=(-1))
    cnt = 0

    for i in range(2,30):
        for j in range(2,30):
            if img[i][j] == 1000:
                img[i][j] = cnt
                cnt+=1
    
    edges = []
    #y-Koordinate, x-Koordinate
    npzahyou = np.zeros((cnt,2))

    for i in range(2,30):
        for j in range(2,30):
            if img[i][j] == -1:
                continue

            #8 Extrahieren Sie den Teil, der der Umgebung entspricht.
            filter = img[i-2:i+3,j-2:j+3].flatten()
            filter1 = filter[[6,7,8,11,13,16,17,18]]

            npzahyou[filter[12]][0] = i-2
            npzahyou[filter[12]][1] = j-2

            for tmp in filter1:
                if not tmp == -1:
                    edges.append([filter[12],tmp])

    np.save("../dataset/graphs/"+str(e),edges)
    np.save("../dataset/node_features/"+str(e),npzahyou)

Klassifizieren

Diesmal ・ 6 Schichten GCN und 2 Schichten vollständig verbundener Schichten ・ Optimierer ist Adam (alle Parameter sind Standard) ・ Die Mini-Chargengröße beträgt 100 ・ Die Anzahl der Epochen beträgt 150 ・ Verwenden Sie ReLU für die Aktivierungsfunktion ・ Von allen 60.000 Daten werden 50.000 Daten für den Zug und der Rest für Tests verwendet.

Ich habe gelernt als.

Modell-

class Net(torch.nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = GCNConv(2, 16)
        self.conv2 = GCNConv(16, 32)
        self.conv3 = GCNConv(32, 48)
        self.conv4 = GCNConv(48, 64)
        self.conv5 = GCNConv(64, 96)
        self.conv6 = GCNConv(96, 128)
        self.linear1 = torch.nn.Linear(128,64)
        self.linear2 = torch.nn.Linear(64,10)

    def forward(self, data):
        x, edge_index = data.x, data.edge_index
        x = self.conv1(x, edge_index)
        x = F.relu(x)
        x = self.conv2(x, edge_index)
        x = F.relu(x)
        x = self.conv3(x, edge_index)
        x = F.relu(x)
        x = self.conv4(x, edge_index)
        x = F.relu(x)
        x = self.conv5(x, edge_index)
        x = F.relu(x)
        x = self.conv6(x, edge_index)
        x = F.relu(x)
        x, _ = scatter_max(x, data.batch, dim=0)
        x = self.linear1(x)
        x = F.relu(x)
        x = self.linear2(x)
        return x

Lernteil

data_size = 60000
train_size = 50000
batch_size = 100
epoch_num = 150

def main():
    mnist_list = load_mnist_graph(data_size=data_size)
    device = torch.device('cuda')
    model = Net().to(device)
    trainset = mnist_list[:train_size]
    optimizer = torch.optim.Adam(model.parameters())
    trainloader = DataLoader(trainset, batch_size=batch_size, shuffle=True)
    testset = mnist_list[train_size:]
    testloader = DataLoader(testset, batch_size=batch_size)
    criterion = nn.CrossEntropyLoss()
    history = {
        "train_loss": [],
        "test_loss": [],
        "test_acc": []
    }

    print("Start Train")
    
    model.train()
    for epoch in range(epoch_num):
        train_loss = 0.0
        for i, batch in enumerate(trainloader):
            batch = batch.to("cuda")
            optimizer.zero_grad()
            outputs = model(batch)
            loss = criterion(outputs,batch.t)
            loss.backward()
            optimizer.step()
            
            train_loss += loss.cpu().item()
            if i % 10 == 9:
                progress_bar = '['+('='*((i+1)//10))+(' '*((train_size//100-(i+1))//10))+']'
                print('\repoch: {:d} loss: {:.3f}  {}'
                        .format(epoch + 1, loss.cpu().item(), progress_bar), end="  ")

        print('\repoch: {:d} loss: {:.3f}'
            .format(epoch + 1, train_loss / (train_size / batch_size)), end="  ")
        history["train_loss"].append(train_loss / (train_size / batch_size))

        correct = 0
        total = 0
        batch_num = 0
        loss = 0
        with torch.no_grad():
            for data in testloader:
                data = data.to(device)
                outputs = model(data)
                loss += criterion(outputs,data.t)
                _, predicted = torch.max(outputs, 1)
                total += data.t.size(0)
                batch_num += 1
                correct += (predicted == data.t).sum().cpu().item()

        history["test_acc"].append(correct/total)
        history["test_loss"].append(loss.cpu().item()/batch_num)
        endstr = ' '*max(1,(train_size//1000-39))+"\n"
        print('Test Accuracy: {:.2f} %%'.format(100 * float(correct/total)), end='  ')
        print(f'Test Loss: {loss.cpu().item()/batch_num:.3f}',end=endstr)

    print('Finished Training')

    #Endergebnis Ausgabe
    correct = 0
    total = 0

    with torch.no_grad():
        for data in testloader:
            data = data.to(device)
            outputs = model(data)
            _, predicted = torch.max(outputs, 1)
            total += data.t.size(0)
            correct += (predicted == data.t).sum().cpu().item()
    print('Accuracy: {:.2f} %%'.format(100 * float(correct/total)))

Ergebnis

Die korrekte Antwortrate (Genauigkeit) betrug ** 97,74% **. Die Änderungen des Verlusts und der Testgenauigkeit sind wie folgt. Am Ende scheint es ein wenig zu viel zu lernen, aber Sie können sehen, dass das Lernen sauber voranschreitet. loss.png acc.png

Ich hatte das Gefühl, dass die Informationen bei der Transformation der Daten verloren gingen, war jedoch überrascht, dass sie besser als MLP klassifiziert wurden (Referenz). Es ist interessant, dass Sie so viel klassifizieren können, indem Sie die Koordinaten anstelle der Helligkeit der Pixel als Merkmalsmenge verwenden.

Dann hat jeder ein gutes GNN-Leben!

Recommended Posts

Ich habe versucht, MNIST nach GNN zu klassifizieren (mit PyTorch-Geometrie).
Ich habe versucht, CVAE mit PyTorch zu implementieren
Ich habe versucht, die Satzklassifizierung durch Self Attention mit PyTorch zu implementieren
Ich habe versucht, das Lesen von Dataset mit PyTorch zu implementieren
Ich habe versucht, GAN (mnist) mit Keras zu bewegen
Ich habe versucht, Drachenkugeln nach Adalin zu klassifizieren
Ich habe versucht, die Anzahl der Mnisten durch unbeaufsichtigtes Lernen zu klassifizieren [PCA, t-SNE, k-means]
Ich habe versucht, Faster R-CNN mit Pytorch auszuführen
Ich habe versucht, DCGAN mit PyTorch zu implementieren und zu lernen
[Einführung in Pytorch] Ich habe versucht, Cifar10 mit VGG16 ♬ zu kategorisieren
Ich habe versucht, SSD jetzt mit PyTorch zu implementieren (Dataset)
Ich habe versucht, Pytorchs Datensatz zu erklären
Ich habe versucht, SSD jetzt mit PyTorch zu implementieren (Modellversion)
Ich habe versucht, Autoencoder mit TensorFlow zu implementieren
Ich habe versucht, AutoEncoder mit TensorFlow zu visualisieren
Ich habe versucht, mit Hy anzufangen
Ich habe versucht, Text mit TensorFlow zu klassifizieren
[Einführung in Pytorch] Ich habe mit sinGAN ♬ gespielt
Ich habe versucht, DeepPose mit PyTorch PartⅡ zu implementieren
Ich habe versucht, TSP mit QAOA zu lösen
765 Ich habe versucht, die drei Berufsfamilien durch CNN zu identifizieren (mit Chainer 2.0.0).
Ich habe versucht, Oba Hanana und Otani Emiri durch tiefes Lernen zu klassifizieren
Ich habe versucht, die Blasensortierung nach Sprache zu programmieren
Ich habe versucht, lightGBM, xg Boost mit Boruta zu verwenden
Ich habe versucht, mit TF Learn die logische Operation zu lernen
Ich habe den MNIST-Code von Chainer mit PyTorch + Ignite neu geschrieben
Ich habe versucht, die Daten mit Zwietracht zu speichern
Ich habe versucht, mit OpenCV Bewegungen schnell zu erkennen
Ich habe versucht, Keras in TFv1.1 zu integrieren
Ich habe versucht, CloudWatch-Daten mit Python abzurufen
Ich habe versucht, LLVM IR mit Python auszugeben
Ich habe versucht, ein Objekt mit M2Det zu erkennen!
Ich habe versucht, die Herstellung von Sushi mit Python zu automatisieren
Ich habe versucht, das Überleben der Titanic mit PyCaret vorherzusagen
Ich habe versucht, Linux mit Discord Bot zu betreiben
Ich habe versucht, DP mit Fibonacci-Sequenz zu studieren
Ich habe versucht, Jupyter mit allen Amazon-Lichtern zu starten
Ich habe versucht, Tundele mit Naive Bays zu beurteilen
Ich habe versucht, Hanana Oba und Emiri Otani durch tiefes Lernen zu klassifizieren (Teil 2)
Ich habe versucht, Satzklassifizierung und Aufmerksamkeitsvisualisierung durch das japanische BERT mit PyTorch zu implementieren
Ich habe versucht, die Sündenfunktion mit Chainer zu trainieren
Ich habe versucht, maschinelles Lernen (Objekterkennung) mit TouchDesigner zu verschieben
Ich habe versucht, Funktionen mit SIFT von OpenCV zu extrahieren
Ich habe versucht, mit VOICEROID2 2 automatisch zu lesen und zu speichern
Klassifizieren Sie Mnist-Zahlen nach Keras, ohne dass der Lehrer etwas lernt [Auto Encoder Edition]
Ich habe versucht, mit Blenders Python script_Part 01 zu beginnen
Ich habe versucht, eine CSV-Datei mit Python zu berühren
Ich habe versucht, mit VOICEROID2 automatisch zu lesen und zu speichern
Ich habe versucht, mit Blenders Python script_Part 02 zu beginnen
Ich habe versucht, ObjectId (Primärschlüssel) mit Pymongo zu generieren
Ich habe versucht, künstliches Perzeptron mit Python zu implementieren
Ich habe versucht, eine ML-Pipeline mit Cloud Composer zu erstellen
Ich habe versucht, unsere Dunkelheit mit der Chatwork-API aufzudecken