Ich studiere die semantische Segmentierung, eine Methode des tiefen Lernens, die den Teil des Interesses aus einem Bild herausschneidet. Dieses Mal möchte ich die Fußabdrücke von Bären herausschneiden. Dies ist eine Fortsetzung von Semantische Segmentierung, nicht ertragen ....
Der große Unterschied zum letzten Mal bestand darin, dass beim letzten Mal entschieden wurde, dass "der Zielbär nur einer pro Bild ist" </ b>, diesmal jedoch "der Fußabdruck des Bären ein Bild ist". Es ist "3 pro" </ b>.
In erster Linie weiß der Autor nicht, wie ein echter Bärenfußabdruck aussieht. Das Bild ist ein Bild.
import random
def draw_footprints(): #Generieren Sie zufällig Bilder mit Bärenfußabdruck
r = g = b = 250
im = Image.new('RGB', (400, 400), (r, g, b))
draw = ImageDraw.Draw(im)
for _ in range(100):
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(3):
r = g = b = 1
center_x = 200
center_y = 200
wx = 60
wy = 50
dx1 = 60
dx2 = 30
dy1 = 90
dy2 = 50
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)
from PIL import Image, ImageDraw
from itertools import product
class Noise: #Fügen Sie dem Bild des Bärenfußabdrucks Rauschen hinzu
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
from PIL import ImageFilter
import numpy as np
#Verarbeiten Sie das Bear Footprint-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
x_im, y_im = getdata_for_semantic_segmentation(draw_footprints())
Geben Sie die folgende Abbildung ein (ein Bild, das die Fußabdrücke eines Bären enthält). Wissen Sie, wo sich die Bärenabdrücke darin befinden?
x_im
Die Antwort ist in der Abbildung unten. Wir möchten lernen, dass diese Antwort ausgegeben werden kann.
y_im
Dieses Mal wurden automatisch 1000 Bilder als Lehrerset generiert.
%%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_footprints())
X_data.append(x_im) #Bilddaten
Y_data.append(y_im) #Richtige Antwortdaten
CPU times: user 1min 20s, sys: 811 ms, total: 1min 21s
Wall time: 1min 21s
%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()
Jetzt fangen wir an zu lernen. Zunächst die Datenkonvertierung
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)
Definition einer Klasse zum Erlernen der kumantischen Segmentierung
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
Fang an zu lernen
%%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()
Mon Feb 3 12:23:20 UTC 2020
epoch: 0 loss: 2685.716845703125
Mon Feb 3 12:24:47 UTC 2020
epoch: 1 loss: 2681.9998046875
Mon Feb 3 12:26:13 UTC 2020
epoch: 2 loss: 2679.750439453125
Mon Feb 3 12:27:39 UTC 2020
epoch: 3 loss: 2678.707568359375
Mon Feb 3 12:29:05 UTC 2020
...
Mon Feb 3 13:39:11 UTC 2020
epoch: 47 loss: 2677.768359375
Mon Feb 3 13:40:49 UTC 2020
epoch: 48 loss: 2677.7637939453125
Mon Feb 3 13:42:29 UTC 2020
epoch: 49 loss: 2677.7629150390626
CPU times: user 2h 15min 56s, sys: 3min, total: 2h 18min 56s
Wall time: 1h 20min 54s
Lassen Sie uns neue Daten generieren, die nicht für das Training verwendet wurden, und Vorhersagen treffen.
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_footprints())
X_test.append(x_im)
Y_test.append(y_im)
Datenformung
#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())
Vergleichen wir die richtige Antwort und das Vorhersageergebnis für die ersten 10 Bilder.
#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. Es funktioniert nicht. Es scheint, dass die Fußabdrücke irgendwie aufgenommen wurden, aber es scheint, dass es viele Fehlalarme gibt, die Nicht-Fußabdrücke als Fußabdrücke beurteilen.
Vergleichen wir den Bereich der richtigen Antwort mit dem Bereich des vorhergesagten Werts.
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()
In Kuma ... nicht semantische Segmentierung gab es eine lineare Beziehung, aber diesmal scheint es, dass keine gute Beziehung zustande gekommen ist.
Die Fortsetzung kommt wieder.
Spätere Erhöhungen der Datenanzahl von 1000 auf 4000 und der Anzahl der Epochen von 50 auf 100 änderten sich nicht wesentlich. Übrigens hat sich die Lernkurve von rund 60 Epochen nicht leicht verringert.