Ich habe "semantische Segmentierung" studiert, die die Dinge extrahiert, die für tiefes Lernen von Interesse sind, das sich mit Bildern befasst.
Das erste Problem beim Erlernen der semantischen Segmentierung bestand darin, Bilder zu erhalten. Ich konnte kein gutes Gefühl finden und begann damit, automatisch ein Bild zum Üben zu generieren.
"Bilddaten" und "richtige Antwortdaten" für die semantische Segmentierung mit der in [Bilder von Koala und Bär automatisch generieren] erstellten Funktion (https://qiita.com/maskot1977/items/8d5fe2492e9fba2c7d90) Ich werde es selbst machen.
from PIL import ImageFilter
import numpy as np
def getdata_for_semantic_segmentation(im):
x_im = im.filter(ImageFilter.CONTOUR) #Die konturierte wird als "Bilddaten" für die Eingabe verwendet.
a_im = np.asarray(im) #In numpy konvertieren
#Der Schwarzbär wird in Weißbär geändert, und die anderen werden als "richtige Antwortdaten" geschwärzt.
y_im = Image.fromarray(np.where(a_im == 1, 255, 0).astype(dtype='uint8'))
return x_im, y_im
Ich habe 2000 Datensätze wie folgt erstellt.
X_data = [] #Zum Speichern von Bilddaten
Y_data = [] #Zum Speichern korrekter Antwortdaten
for i in range(2000): #Generieren Sie 2000 Bilder
#Bärenbild erzeugen
im = koala_or_bear(bear=True, rotate=True , resize=64, others=True)
#Für die semantische Segmentierung verarbeitet
x_im, y_im = getdata_for_semantic_segmentation(im)
X_data.append(x_im) #Bilddaten
Y_data.append(y_im) #Richtige Antwortdaten
Nur die ersten 8 Elemente der erstellten Bilddaten und der richtigen Antwortdaten werden dargestellt und bestätigt.
%matplotlib inline
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(10,10))
for i in range(16):
ax = fig.add_subplot(4, 4, i+1)
ax.axis('off')
if i < 8: #Zeigen Sie die Top 8 der Bilddaten an
ax.set_title('input_{}'.format(i))
ax.imshow(X_data[i],cmap=plt.cm.gray, interpolation='none')
else: #Zeigen Sie die Top 8 der richtigen Antwortdaten an
ax.set_title('answer_{}'.format(i - 8))
ax.imshow(Y_data[i - 8],cmap=plt.cm.gray, interpolation='none')
plt.show()
Der Zweck der semantischen Segmentierung besteht darin, ein Modell zu erstellen, das den Herrn Kuma entsprechenden Teil aus den obigen "Bilddaten" extrahiert und "korrekte Antwortdaten" ausgibt.
import torch
from torch.utils.data import TensorDataset, DataLoader
#Konvertieren Sie Bilddaten und korrigieren Sie die Antwortdaten in ndarray
X_a = np.array([[np.asarray(x).transpose((2, 0, 1))[0]] for x in X_data])
Y_a = np.array([[np.asarray(y).transpose((2, 0, 1))[0]] for y in Y_data])
#Konvertieren Sie ndarray-Bilddaten und korrigieren Sie die Antwortdaten in Tensor
X_t = torch.tensor(X_a, dtype = torch.float32)
Y_t = torch.tensor(Y_a, dtype = torch.float32)
#Im Data Loader zum Lernen mit PyTorch gespeichert
data_set = TensorDataset(X_t, Y_t)
data_loader = DataLoader(data_set, batch_size = 100, shuffle = True)
Das Modell für die semantische Segmentierung ist im Grunde der [Auto Encoder](https: // qiita.) Unter Verwendung von Convolution Neural Network (CNN). Es ist com / maskot1977 / items / 2fb459c66d49ba550db2).
from torch import nn, optim
from torch.nn import functional as F
class Kuma(nn.Module):
def __init__(self):
super(Kuma, self).__init__()
#Encoderteil
self.encode1 = nn.Sequential(
*[
nn.Conv2d(
in_channels = 1, out_channels = 6, kernel_size = 3, padding = 1),
nn.BatchNorm2d(6)
])
self.encode2 = nn.Sequential(
*[
nn.Conv2d(
in_channels = 6, out_channels = 16, kernel_size = 3, padding = 1),
nn.BatchNorm2d(16)
])
self.encode3 = nn.Sequential(
*[
nn.Conv2d(
in_channels = 16, out_channels = 32, kernel_size = 3, padding = 1),
nn.BatchNorm2d(32)
])
#Decoderteil
self.decode3 = nn.Sequential(
*[
nn.ConvTranspose2d(
in_channels = 32, out_channels = 16, kernel_size = 3, padding = 1),
nn.BatchNorm2d(16)
])
self.decode2 = nn.Sequential(
*[
nn.ConvTranspose2d(
in_channels = 16, out_channels = 6, kernel_size = 3, padding = 1),
nn.BatchNorm2d(6)
])
self.decode1 = nn.Sequential(
*[
nn.ConvTranspose2d(
in_channels = 6, out_channels = 1, kernel_size = 3, padding = 1),
])
def forward(self, x):
#Encoderteil
dim_0 = x.size() #Zum Wiederherstellen der Größe in der ersten Schicht des Decoders
x = F.relu(self.encode1(x))
# return_indices =Stellen Sie im Decoder True und Max ein_Verwenden Sie die Poolposition idx
x, idx_1 = F.max_pool2d(x, kernel_size = 2, stride = 2, return_indices = True)
dim_1 = x.size() #Zum Wiederherstellen der Größe in der zweiten Schicht des Decoders
x = F.relu(self.encode2(x))
# return_indices =Stellen Sie im Decoder True und Max ein_Verwenden Sie die Poolposition idx
x, idx_2 = F.max_pool2d(x, kernel_size = 2, stride = 2, return_indices = True)
dim_2 = x.size()
x = F.relu(self.encode3(x)) #Zum Wiederherstellen der Größe in der dritten Schicht des Decoders
# return_indices =Stellen Sie im Decoder True und Max ein_Verwenden Sie die Poolposition idx
x, idx_3 = F.max_pool2d(x, kernel_size = 2, stride = 2, return_indices = True)
#Decoderteil
x = F.max_unpool2d(x, idx_3, kernel_size = 2, stride = 2, output_size = dim_2)
x = F.relu(self.decode3(x))
x = F.max_unpool2d(x, idx_2, kernel_size = 2, stride = 2, output_size = dim_1)
x = F.relu(self.decode2(x))
x = F.max_unpool2d(x, idx_1, kernel_size = 2, stride = 2, output_size = dim_0)
x = F.relu(self.decode1(x))
x = torch.sigmoid(x)
return x
%%time
kuma = Kuma()
loss_fn = nn.MSELoss()
optimizer = optim.Adam(kuma.parameters(), lr = 0.01)
total_loss_history = []
epoch_time = 50
for epoch in range(epoch_time):
total_loss = 0.0
kuma.train()
for i, (XX, yy) in enumerate(data_loader):
optimizer.zero_grad()
y_pred = kuma(XX)
loss = loss_fn(y_pred, yy)
loss.backward()
optimizer.step()
total_loss += loss.item()
print("epoch:",epoch, " loss:", total_loss/(i + 1))
total_loss_history.append(total_loss/(i + 1))
plt.plot(total_loss_history)
plt.ylabel("loss")
plt.xlabel("epoch time")
plt.savefig("total_loss_history")
plt.show()
epoch: 0 loss: 8388.166772460938
epoch: 2 loss: 8372.164868164062
epoch: 3 loss: 8372.035913085938
...
epoch: 48 loss: 8371.781372070312
epoch: 49 loss: 8371.78125
Der Wert der Verlustfunktion ist eine lächerliche Zahl, ist es okay ...
Es scheint, dass es konvergiert hat. Die Berechnungszeit ist wie folgt.
CPU times: user 6min 7s, sys: 8.1 s, total: 6min 16s
Wall time: 6min 16s
Generieren Sie neue Daten als Testdaten.
X_test = [] #Speichern Sie Bilddaten zum Testen
Y_test = [] #Speichert korrekte Antwortdaten zum Testen
Z_test = [] #Speichern Sie Vorhersageergebnisse zum Testen
for i in range(100): #Generieren Sie 100 neue Daten, die nicht für das Training verwendet werden
im = koala_or_bear(bear=True, rotate=True, resize=64, others=True)
x_im, y_im = getdata_for_semantic_segmentation(im)
X_test.append(x_im)
Y_test.append(y_im)
Vorhersage mit einem trainierten Modell.
#Formatieren Sie die Testbilddaten für PyTorch
X_test_a = np.array([[np.asarray(x).transpose((2, 0, 1))[0]] for x in X_test])
X_test_t = torch.tensor(X_test_a, dtype = torch.float32)
#Berechnen Sie Vorhersagen mit einem trainierten Modell
Y_pred = kuma(X_test_t)
#Speichern Sie die vorhergesagten Werte als ndarray
for pred in Y_pred:
Z_test.append(pred.detach().numpy())
Zeichnen wir nur die ersten 10 Daten, um das Vorhersageergebnis zu sehen. Geben Sie von links nach rechts Bilddaten, korrekte Antwortdaten und Vorhersagedaten ein.
#Zeichnen Sie Bilddaten, korrekte Antwortdaten und vorhergesagte Werte für die ersten 10 Daten
fig = plt.figure(figsize=(6,18))
for i in range(10):
ax = fig.add_subplot(10, 3, (i * 3)+1)
ax.axis('off')
ax.set_title('input_{}'.format(i))
ax.imshow(X_test[i])
ax = fig.add_subplot(10, 3, (i * 3)+2)
ax.axis('off')
ax.set_title('answer_{}'.format(i))
ax.imshow(Y_test[i])
ax = fig.add_subplot(10, 3, (i * 3)+3)
ax.axis('off')
ax.set_title('predicted_{}'.format(i))
yp2 = Y_pred[i].detach().numpy()[0] * 255
z_im = Image.fromarray(np.array([yp2, yp2, yp2]).transpose((1, 2, 0)).astype(dtype='uint8'))
ax.imshow(z_im)
plt.show()
Ich kann das Bärenteil herausschneiden. Selbst wenn sich die Größe des Bären ändert, ist es in Ordnung, ihn zu drehen!
Es scheint jedoch, dass sie dazu neigen, etwas größer auszuschneiden. Es gibt auch einige Fehler.
Vergleichen wir den weiß ausgeschnittenen Bereich mit den richtigen Antwortdaten und den vorhergesagten Daten.
A_ans = []
A_pred = []
for yt, zt in zip(Y_test, Z_test):
#Korrekter weißer Bereich (Da 3 Vektoren vorhanden sind, durch 3 teilen)
A_ans.append(np.where(np.asarray(yt) > 0.5, 1, 0).sum() / 3)
A_pred.append(np.where(np.asarray(zt) > 0.5, 1, 0).sum()) #Voraussichtlicher weißer Bereich
plt.figure(figsize=(4, 4))
plt.scatter(A_ans, A_pred, alpha=0.5)
plt.grid()
plt.xlabel('Observed sizes of bears')
plt.ylabel('Predicted sizes of bears')
plt.xlim([0, 1700])
plt.ylim([0, 1700])
plt.show()
Es ist gut, dass der richtige Antwortwert und der vorhergesagte Wert eine nahezu lineare Beziehung haben, aber es scheint, dass der vorhergesagte Wert tendenziell groß ist.
Wenn Sie nur die Größe des Bären wissen möchten, ist es eine gute Idee, Korrekturen basierend auf dieser Beziehung vorzunehmen. Um jedoch genauer ausschneiden zu können, muss ein komplizierteres Modell erstellt werden.