"Kumantic Segumantion", um Informationen über Kuma aus dem Bild von Kuma zu erhalten. Dies ist eine Fortsetzung von Kumantic Segmentation 2.
Letztes Mal wollte ich " mehrere </ b> Fußabdrücke von Bären erkennen", indem ich "ein Bild von mehreren </ b> Fußabdrücken von Bären" zum Lernen verwendete. , Funktioniert nicht).
Dieses Mal möchten wir "mehrere </ b> Bärensilhouetten erkennen", indem wir "ein Bild verwenden, das nur eine </ b> Bärensilhouette zeigt", um zu lernen.
Wird zum Erstellen von Datensätzen für Training und Validierung verwendet.
import numpy as np
import random
from PIL import Image, ImageDraw, ImageFilter
from itertools import product
def draw_bear(n_bear=1): #Generieren Sie zufällig ein Bild von Herrn Kuma
r = g = b = 250
im = Image.new('RGB', (400, 400), (r, g, b))
draw = ImageDraw.Draw(im)
for _ in range(random.randint(-1, 0)):
r = random.randint(10, 200)
g = random.randint(10, 200)
b = random.randint(10, 200)
x1 = random.randint(0, 400)
y1 = random.randint(0, 400)
dx = random.randint(10, 50)
dy = random.randint(10, 50)
draw.ellipse((x1, y1, x1+dx, y1+dy), fill=(r, g, b))
for _ in range(n_bear):
r = g = b = 1
center_x = 200
center_y = 200
wx = 60
wy = 50
dx1 = 90
dx2 = 20
dy1 = 90
dy2 = 20
dx3 = 15
dy3 = 100
dy4 = 60
shape1 = (center_x - wx, center_y - wy, center_x + wx, center_y + wy)
shape2 = (center_x - dx1, center_y - dy1, center_x - dx2, center_y - dy2)
shape3 = (center_x + dx2, center_y - dy1, center_x + dx1, center_y - dy2)
shape4 = (center_x - dx3, center_y - dy3, center_x + dx3, center_y - dy4)
zoom = 0.2 + random.random() * 0.4
center_x = random.randint(-30, 250)
center_y = random.randint(-30, 250)
shape1 = modify(shape1, zoom=zoom, center_x=center_x, center_y=center_y)
shape2= modify(shape2, zoom=zoom, center_x=center_x, center_y=center_y)
shape3 = modify(shape3, zoom=zoom, center_x=center_x, center_y=center_y)
shape4 = modify(shape4, zoom=zoom, center_x=center_x, center_y=center_y)
draw.ellipse(shape1, fill=(r, g, b))
draw.ellipse(shape2, fill=(r, g, b))
draw.ellipse(shape3, fill=(r, g, b))
#draw.ellipse(shape4, fill=(r, g, b))
return im
def modify(shape, zoom=1, center_x=0, center_y=0):
x1, y1, x2, y2 = np.array(shape) * zoom
return (x1 + center_x, y1 + center_y, x2 + center_x, y2 + center_y)
class Noise: #Setzen Sie Rauschen auf das Bild des Bären
def __init__(self, input_image):
self.input_image = input_image
self.input_pix = self.input_image.load()
self.w, self.h = self.input_image.size
def saltpepper(self, salt=0.05, pepper=0.05):
output_image = Image.new("RGB", self.input_image.size)
output_pix = output_image.load()
for x, y in product(*map(range, (self.w, self.h))):
r = random.random()
if r < salt:
output_pix[x, y] = (255, 255, 255)
elif r > 1 - pepper:
output_pix[x, y] = ( 0, 0, 0)
else:
output_pix[x, y] = self.input_pix[x, y]
return output_image
##Verarbeiten Sie Kumas Bild in Lehrerdaten für die semantische Segmentierung
def getdata_for_semantic_segmentation(im):
x_im = im.filter(ImageFilter.CONTOUR)
im2 = Noise(input_image=x_im)
x_im = im2.saltpepper()
a_im = np.asarray(im)
y_im = Image.fromarray(np.where(a_im == 1, 255, 0).astype(dtype='uint8'))
return x_im, y_im
Wenn Sie die obige Funktion vorbereiten, können Sie das Bild "x_im" von Herrn Kuma und die richtigen Antwortdaten "y_im" wie folgt erhalten.
x_im, y_im = getdata_for_semantic_segmentation(draw_bear())
Überprüfen Sie den Inhalt
x_im
y_im
Okay, ich habe bestätigt, dass das Bild von Herrn Kuma erzeugt wurde. Dies ist ein Bär, egal wie du es betrachtest.
Generieren Sie 1000 Trainingsdaten wie folgt.
%%time
X_data = [] #Zum Speichern von Bilddaten
Y_data = [] #Zum Speichern korrekter Antwortdaten
for i in range(1000): #Generieren Sie 1000 Bilder
x_im, y_im = getdata_for_semantic_segmentation(draw_bear())
X_data.append(x_im) #Bilddaten
Y_data.append(y_im) #Richtige Antwortdaten
CPU times: user 1min 13s, sys: 865 ms, total: 1min 14s
Wall time: 1min 15s
Überprüfen Sie für alle Fälle nur die ersten 8 der generierten Daten.
%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()
Formatieren Sie die resultierenden Daten für PyTorch.
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)
Ich habe das gleiche Netzwerk wie beim letzten Mal verwendet.
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
Lerne zuerst nur 50 Epochen.
%%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):
!date
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()
Tue Feb 25 12:07:52 UTC 2020
epoch: 0 loss: 1202.7168701171875
Tue Feb 25 12:10:12 UTC 2020
epoch: 1 loss: 1200.6845336914062
Tue Feb 25 12:12:28 UTC 2020
...
Tue Feb 25 13:53:40 UTC 2020
epoch: 47 loss: 1199.1316650390625
Tue Feb 25 13:55:54 UTC 2020
epoch: 48 loss: 1199.1294555664062
Tue Feb 25 13:58:08 UTC 2020
epoch: 49 loss: 1199.133544921875
CPU times: user 1h 36min 47s, sys: 2min 23s, total: 1h 39min 11s
Wall time: 1h 52min 30s
Es sieht so aus, als wäre es konvergiert.
Generieren Sie 100 neue Daten, die nicht für das Training verwendet wurden, und überprüfen Sie sie.
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
x_im, y_im = getdata_for_semantic_segmentation(draw_bear())
X_test.append(x_im)
Y_test.append(y_im)
#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())
Ich werde nur die ersten 10 Daten veranschaulichen.
#Zeichnen Sie Bilddaten, korrekte Antwortdaten und vorhergesagte Werte für die ersten 10 Daten
fig = plt.figure(figsize=(12,36))
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()
Es gibt viel Lärm, aber es scheint bis zu einem gewissen Grad vorhersehbar zu sein.
Schauen wir uns die Beziehung zwischen der tatsächlichen Größe des Bären und der Größe des erkannten (vorhergesagten) Bären an.
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')
plt.ylabel('Predicted sizes')
#plt.xlim([0, 1700])
#plt.ylim([0, 1700])
plt.show()
Die Genauigkeit ist nicht gut, aber es gibt eine vage lineare Beziehung.
Sie können das trainierte Modell wie folgt speichern und jederzeit wieder verwenden.
torch.save(kuma.state_dict(), "kuma_050_20200225.pytorch")
Irgendwie habe ich versucht, weitere 50 Epochen zu lernen. Code weggelassen.
Ich frage mich, ob der Fehler etwas abgenommen hat (aber er ändert sich nicht viel).
Es scheint keine wesentliche Verbesserung zu geben.
torch.save(kuma.state_dict(), "kuma_100_20200225.pytorch")
Vorerst habe ich das trainierte Modell wie oben gespeichert.
Jetzt ist es endlich Zeit, live zu gehen. Bisher haben wir "Bilder mit nur einem Bären </ b>" gelernt und Bären aus "Bildern mit nur einem Bären </ b>" erkannt. Ich habe es getan, aber von nun an werde ich "Bilder mit nur einem Bären </ b>" und aus "Bildern mit mehreren </ b> Bären" lernen. Ich möchte Herrn Kuma entdecken.
Laden Sie das trainierte Modell, das Sie zuvor gespeichert haben.
kuma = Kuma()
kuma.load_state_dict(torch.load("kuma_100_20200225.pytorch"))
<All keys matched successfully>
Erzeugt 100 Bilder mit mehreren Bären. Es erzeugt auch ein enttäuschendes Bild, das den Bären nicht zeigt.
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
x_im, y_im = getdata_for_semantic_segmentation(draw_bear(n_bear=random.randint(0, 5)))
X_test.append(x_im)
Y_test.append(y_im)
#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)
Da es sich um ein trainiertes Modell handelt, erfolgt die Vorhersage sofort.
#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 Sie Bilddaten, korrekte Antwortdaten und vorhergesagte Werte für die ersten 10 Daten
fig = plt.figure(figsize=(12,36))
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()
Es ist ziemlich laut, aber ich konnte eine grobe Vorhersage machen.
Lassen Sie uns die Beziehung zwischen der tatsächlichen Größe von Herrn Kuma und der vorhergesagten Größe sehen.
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')
plt.ylabel('Predicted sizes')
#plt.xlim([0, 1700])
#plt.ylim([0, 1700])
plt.show()
Es gibt eine ziemlich saubere lineare Beziehung. Wenn Sie also nur die Größe wissen möchten, können Sie diese Beziehung anscheinend korrigieren.
Ich habe eine weitere Ebene hinzugefügt, um ein tieferes Netzwerk zu erstellen.
import torch
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)
])
self.encode4 = nn.Sequential(
*[
nn.Conv2d(
in_channels = 32, out_channels = 64, kernel_size = 3, padding = 1),
nn.BatchNorm2d(64)
])
#Decoderteil
self.decode4 = nn.Sequential(
*[
nn.ConvTranspose2d(
in_channels = 64, out_channels = 32, kernel_size = 3, padding = 1),
nn.BatchNorm2d(32)
])
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()
x = F.relu(self.encode1(x))
x, idx_1 = F.max_pool2d(x, kernel_size = 2, stride = 2, return_indices = True)
dim_1 = x.size()
x = F.relu(self.encode2(x))
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))
x, idx_3 = F.max_pool2d(x, kernel_size = 2, stride = 2, return_indices = True)
dim_3 = x.size()
x = F.relu(self.encode4(x))
x, idx_4 = F.max_pool2d(x, kernel_size = 2, stride = 2, return_indices = True)
#Decoderteil
x = F.max_unpool2d(x, idx_4, kernel_size = 2, stride = 2, output_size = dim_3)
x = F.relu(self.decode4(x))
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
Das Ergebnis ist wie folgt. Der Code ist der gleiche wie der oben beschriebene (nur der zu speichernde Dateiname ist unterschiedlich)
Lernkurve
Beispiel für ein Vorhersageergebnis (1 Bär)
Bärengröße
Beispiel für Vorhersageergebnisse (viele Bären)
Bärengröße
Fügen Sie einfach eine Schicht hinzu und es ist ziemlich sauber!