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.
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.
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 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)
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.
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
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)))
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.
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