"Kumantic Segumantion" pour obtenir des informations sur Kuma à partir de l'image de Kuma. Suite à la précédente, cette fois je vais essayer de vérifier ce que le réseau défini dans Kumantic Segumantion regarde. J'ai fait.
Dernière fois Identique à celui défini. Par la suite, nous l'appellerons "Kuma Network".
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__()
#Partie encodeur
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)
])
#Partie décodeur
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):
#Partie encodeur
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)
#Partie décodeur
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
Dernière fois Téléchargez le réseau d'ours formé créé.
url = "https://github.com/maskot1977/PythonCourse2019/blob/master/kuma_050_20200226.pytorch?raw=true"
import urllib.request
urllib.request.urlretrieve(url, 'kuma_050_20200226.pytorch') #Télécharger les données
('kuma_050_20200226.pytorch', <http.client.HTTPMessage at 0x7f73177ebef0>)
Chargez le réseau ours formé sur le réseau ours défini.
kuma = Kuma()
kuma.load_state_dict(torch.load("kuma_050_20200226.pytorch"))
<All keys matched successfully>
kuma
Kuma(
(encode1): Sequential(
(0): Conv2d(1, 6, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): BatchNorm2d(6, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
(encode2): Sequential(
(0): Conv2d(6, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): BatchNorm2d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
(encode3): Sequential(
(0): Conv2d(16, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
(encode4): Sequential(
(0): Conv2d(32, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
(decode4): Sequential(
(0): ConvTranspose2d(64, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): BatchNorm2d(32, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
(decode3): Sequential(
(0): ConvTranspose2d(32, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): BatchNorm2d(16, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
(decode2): Sequential(
(0): ConvTranspose2d(16, 6, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): BatchNorm2d(6, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
(decode1): Sequential(
(0): ConvTranspose2d(6, 1, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
)
)
En regardant les paramètres un par un,
for name, param in kuma.named_parameters():
print(name, param.shape)
encode1.0.weight torch.Size([6, 1, 3, 3])
encode1.0.bias torch.Size([6])
encode1.1.weight torch.Size([6])
encode1.1.bias torch.Size([6])
encode2.0.weight torch.Size([16, 6, 3, 3])
encode2.0.bias torch.Size([16])
encode2.1.weight torch.Size([16])
encode2.1.bias torch.Size([16])
encode3.0.weight torch.Size([32, 16, 3, 3])
encode3.0.bias torch.Size([32])
encode3.1.weight torch.Size([32])
encode3.1.bias torch.Size([32])
encode4.0.weight torch.Size([64, 32, 3, 3])
encode4.0.bias torch.Size([64])
encode4.1.weight torch.Size([64])
encode4.1.bias torch.Size([64])
decode4.0.weight torch.Size([64, 32, 3, 3])
decode4.0.bias torch.Size([32])
decode4.1.weight torch.Size([32])
decode4.1.bias torch.Size([32])
decode3.0.weight torch.Size([32, 16, 3, 3])
decode3.0.bias torch.Size([16])
decode3.1.weight torch.Size([16])
decode3.1.bias torch.Size([16])
decode2.0.weight torch.Size([16, 6, 3, 3])
decode2.0.bias torch.Size([6])
decode2.1.weight torch.Size([6])
decode2.1.bias torch.Size([6])
decode1.0.weight torch.Size([6, 1, 3, 3])
decode1.0.bias torch.Size([1])
Ah, c'est vrai, j'ai bien compris ← Je ne comprends pas
Apparemment, les paramètres de matrice indiqués ci-dessus sont appelés noyaux (ou filtres) dans le monde du deep learning. La forme de la matrice est comme indiqué ci-dessus, mais visualisons les nombres qu'elle contient.
import matplotlib.pyplot as plt
for name, param in kuma.named_parameters():
print(name)
print(param.shape)
if len(param.shape) == 4:
x, y, z, w = param.shape
idx = 0
fig = plt.figure(figsize=(x, y))
for para in param:
for par in para:
idx += 1
ax = fig.add_subplot(y, x, idx)
im = ax.imshow(par.detach().numpy(), cmap="gray")
ax.axis('off')
#fig.colorbar(im)
plt.show()
#break
encode1.0.weight
torch.Size([6, 1, 3, 3])
Cliquez sur l'image pour l'agrandir.
encode1.0.bias torch.Size([6]) encode1.1.weight torch.Size([6]) encode1.1.bias torch.Size([6]) encode2.0.weight torch.Size([16, 6, 3, 3])
Cliquez sur l'image pour l'agrandir.
encode2.0.bias torch.Size([16]) encode2.1.weight torch.Size([16]) encode2.1.bias torch.Size([16]) encode3.0.weight torch.Size([32, 16, 3, 3])
Cliquez sur l'image pour l'agrandir.
encode3.0.bias torch.Size([32]) encode3.1.weight torch.Size([32]) encode3.1.bias torch.Size([32]) encode4.0.weight torch.Size([64, 32, 3, 3])
Cliquez sur l'image pour l'agrandir.
encode4.0.bias torch.Size([64]) encode4.1.weight torch.Size([64]) encode4.1.bias torch.Size([64]) decode4.0.weight torch.Size([64, 32, 3, 3])
Cliquez sur l'image pour l'agrandir.
decode4.0.bias torch.Size([32]) decode4.1.weight torch.Size([32]) decode4.1.bias torch.Size([32]) decode3.0.weight torch.Size([32, 16, 3, 3])
Cliquez sur l'image pour l'agrandir.
decode3.0.bias torch.Size([16]) decode3.1.weight torch.Size([16]) decode3.1.bias torch.Size([16]) decode2.0.weight torch.Size([16, 6, 3, 3])
Cliquez sur l'image pour l'agrandir.
decode2.0.bias torch.Size([6]) decode2.1.weight torch.Size([6]) decode2.1.bias torch.Size([6]) decode1.0.weight torch.Size([6, 1, 3, 3])
Cliquez sur l'image pour l'agrandir.
decode1.0.bias torch.Size([1])
Parlant de mon manque de connaissances, ce réseau d'ours scanne les images avec ce noyau (ou filtre) "3 x 3" pour extraire des caractéristiques de l'image telles que des "lignes".
Pourtant, je ne sais pas comment cela reconnaît Kuma-san.
Même si je regarde le noyau (ou le filtre), cela ne sort pas bien, alors j'ai essayé de faire passer l'image de l'ours à travers le réseau d'ours et de voir à quoi ressemble l'image de l'ours dans chaque couche.
C'est la même chose que Dernière fois.
import numpy as np
import random
from PIL import Image, ImageDraw, ImageFilter
from itertools import product
def draw_bear(n_bear=1): #Générer de manière aléatoire une image de M. 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: #Mettez du bruit sur l'image de l'ours
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
##Traitez l'image de Kuma en données d'enseignant pour la segmentation sémantique
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
Je l'ai modifié pour visualiser les résultats en cours de route.
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__()
#Partie encodeur
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)
])
#Partie décodeur
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):
print("forward input:", x.shape)
draw_layer(x)
#Partie encodeur
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)
print("after encode1:", x.shape)
draw_layer(x)
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)
print("after encode2:", x.shape)
draw_layer(x)
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)
print("after encode3:", x.shape)
draw_layer(x)
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)
print("after encode4:", x.shape)
draw_layer(x)
#Partie décodeur
x = F.max_unpool2d(x, idx_4, kernel_size = 2, stride = 2, output_size = dim_3)
x = F.relu(self.decode4(x))
print("after decode4:", x.shape)
draw_layer(x)
x = F.max_unpool2d(x, idx_3, kernel_size = 2, stride = 2, output_size = dim_2)
x = F.relu(self.decode3(x))
print("after decode3:", x.shape)
draw_layer(x)
x = F.max_unpool2d(x, idx_2, kernel_size = 2, stride = 2, output_size = dim_1)
x = F.relu(self.decode2(x))
print("after decode2:", x.shape)
draw_layer(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)
print("after decode1:", x.shape)
draw_layer(x)
return x
def draw_layer(param):
if len(param.shape) == 4:
x, y, z, w = param.shape
idx = 0
fig = plt.figure(figsize=(y*2, x*2))
for para in param:
for par in para:
idx += 1
ax = fig.add_subplot(x, y, idx)
im = ax.imshow(par.detach().numpy(), cmap="gray")
ax.axis('off')
#fig.colorbar(im)
plt.show()
kuma = Kuma()
kuma.load_state_dict(torch.load("kuma_050_20200226.pytorch"))
<All keys matched successfully>
J'ai fait 4 images avec 3 ours par image et j'ai vérifié leur apparence dans le calque du milieu.
X_test = [] #Stocker les données d'image pour les tests
Y_test = [] #Stocke les données de réponse correctes pour les tests
Z_test = [] #Stocker les résultats de prédiction pour les tests
for i in range(4): #Générer 4 nouvelles données non utilisées pour la formation
x_im, y_im = getdata_for_semantic_segmentation(draw_bear(3))
X_test.append(x_im)
Y_test.append(y_im)
#Formater les données d'image de test pour 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)
#Calculer des prédictions à l'aide d'un modèle entraîné
Y_pred = kuma(X_test_t)
#Stocker les valeurs prévues sous forme de ndarray
for pred in Y_pred:
Z_test.append(pred.detach().numpy())
forward input: torch.Size([4, 1, 400, 400])
Cliquez sur l'image pour l'agrandir.
after encode1: torch.Size([4, 6, 200, 200])
Cliquez sur l'image pour l'agrandir.
after encode2: torch.Size([4, 16, 100, 100])
Cliquez sur l'image pour l'agrandir.
after encode3: torch.Size([4, 32, 50, 50])
Cliquez sur l'image pour l'agrandir.
after encode4: torch.Size([4, 64, 25, 25])
Cliquez sur l'image pour l'agrandir.
after decode4: torch.Size([4, 32, 50, 50])
Cliquez sur l'image pour l'agrandir.
after decode3: torch.Size([4, 16, 100, 100])
Cliquez sur l'image pour l'agrandir.
after decode2: torch.Size([4, 6, 200, 200])
Cliquez sur l'image pour l'agrandir.
after decode1: torch.Size([4, 1, 400, 400])
La première couche du codeur obtient un contour approximatif, les deuxième à troisième couches suppriment le bruit, les troisième à quatrième couches obtiennent une "région entourée par le contour" et les première à quatrième couches du décodeur C'est comme le restaurer pour qu'il puisse être mappé sur l'image d'origine.
Recommended Posts