[PYTHON] Kumantische Segmentierung 2

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

Bärenfußabdruckbild automatisch generieren

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

Beispiel für die Erzeugung von Bärenabdruckbildern

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

output_5_0.png

Die Antwort ist in der Abbildung unten. Wir möchten lernen, dass diese Antwort ausgegeben werden kann.

y_im

output_6_0.png

Generation des Lehrersets

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

Beispiel für die Generierung von Lehrersätzen

%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()

output_8_0.png

Lernen

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

output_11_1.png

CPU times: user 2h 15min 56s, sys: 3min, total: 2h 18min 56s
Wall time: 1h 20min 54s

Prognose neuer Daten

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

output_14_0.png

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

output_15_0.png

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.

Nachtrag

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.

Recommended Posts