AutoEncoder est un type d'apprentissage non supervisé dans l'apprentissage automatique. La détection d'anomalies est connue comme un exemple d'application. Cette fois, je voudrais essayer AutoEncoedr pour mnist en utilisant CNN (réseau de neurones convolutifs). Je ne sais pas quel numéro brasser, mais c'est un mémorandum d'étude de Pytorch. Cette fois, je me suis référé à ici
Voici une compréhension approximative d'AutoEncoder: Ajustez l'encodeur et le décodeur de sorte que le contenu des données d'entrée et de sortie soit égal. Si les données d'entrée sont différentes des données habituelles, il n'est pas possible de créer des données de sortie égales aux données d'entrée. Par conséquent, s'il y a une grande différence entre les données d'entrée et les données de sortie, cela peut être jugé anormal (il semble).
L'environnement est python ver3.6.9 pytorch ver1.3.1 numpy ver1.17.4
Tout d'abord, chargez mnist. Dans le code (en tant que passe-temps personnel), l'apprentissage scicit est utilisé pour lire les données au format ndarray, mais la vision de la torche est utilisée pour les lire au format Tensor. 7 000 images de données d'image à 0 numéro sont extraites, et 6 000 d'entre elles sont utilisées pour l'apprentissage.
import numpy as np
import matplotlib.pyplot as plt
import torch
from torch import nn, optim
from torch.utils.data import DataLoader, TensorDataset
from sklearn.datasets import fetch_openml
#Télécharger les données mnist
mnist = fetch_openml('mnist_784', version=1, data_home='data/src/download/')
X, y = mnist["data"], mnist["target"]
X_0 = X[np.int32(y) == 0] #Extraire uniquement lorsque la donnée cible est 0
X_0 = (2 *X_0) / 255.0 - 1.0 #max 1.0 min -1.Convertir en 0
X_0 = X_0.reshape([X_0.shape[0], 1, 28, 28])
X_0 = torch.tensor(X_0, dtype = torch.float32)
X_0_train, X_0_test = X_0[:6000, :, :, :], X_0[6000:, :, :, :]
train_loader = DataLoader(X_0_train, batch_size = 50)
Ensuite, créez un réseau à l'aide de Pytorch. L'encodeur utilise nn.Conv2d pour la convolution normale. L'image d'entrée était de 1x28x28 avec 784 dimensions, mais après avoir traversé l'encodeur, elle est dimensionnellement compressée à 4x7x7 avec 196 dimensions. Le décodeur utilise nn.ConvTranspose2d, qui est l'inverse de la convolution normale (?). Ensuite, il revient finalement à 784 dimensions de 1x28x28.
class ConvAutoencoder(nn.Module):
def __init__(self):
super(ConvAutoencoder, self).__init__()
#Encoder Layers
self.conv1 = nn.Conv2d(in_channels = 1, out_channels = 16,
kernel_size = 3, padding = 1)
self.conv2 = nn.Conv2d(in_channels = 16, out_channels = 4,
kernel_size = 3, padding = 1)
#Decoder Layers
self.t_conv1 = nn.ConvTranspose2d(in_channels = 4, out_channels = 16,
kernel_size = 2, stride = 2)
self.t_conv2 = nn.ConvTranspose2d(in_channels = 16, out_channels = 1,
kernel_size = 2, stride = 2)
self.relu = nn.ReLU()
self.pool = nn.MaxPool2d(2, 2)
self.sigmoid = nn.Sigmoid()
def forward(self, x):
#Affiche la dimension lorsque i feuilles d'images monochromes 28x28 sont entrées dans le commentaire
#encode# #in [i, 1, 28, 28]
x = self.relu(self.conv1(x)) #out [i, 16, 28, 28]
x = self.pool(x) #out [i, 16, 14, 14]
x = self.relu(self.conv2(x)) #out [i, 4, 14, 14]
x = self.pool(x) #out [i ,4, 7, 7]
#decode#
x = self.relu(self.t_conv1(x)) #out [i, 16, 14, 14]
x = self.sigmoid(self.t_conv2(x)) #out [i, 1, 28, 28]
return x
Maintenant que nous avons un réseau, apprenons. Le calcul loss_fn compare l'image d'entrée avec l'image de sortie du réseau.
def train_net(n_epochs, train_loader, net, optimizer_cls = optim.Adam,
loss_fn = nn.MSELoss(), device = "cpu"):
"""
n_époques… Nombre de formations
net… réseau
device … "cpu" or "cuda:0"
"""
losses = [] #loss_Enregistrer la transition de fonction
optimizer = optimizer_cls(net.parameters(), lr = 0.001)
net.to(device)
for epoch in range(n_epochs):
running_loss = 0.0
net.train() #Mode réseau d'entraînement
for i, XX in enumerate(train_loader):
XX.to(device)
optimizer.zero_grad()
XX_pred = net(XX) #Prédire sur le réseau
loss = loss_fn(XX, XX_pred) #Données de prédiction et prédiction des données originales
loss.backward()
optimizer.step() #Mise à jour du dégradé
running_loss += loss.item()
losses.append(running_loss / i)
print("epoch", epoch, ": ", running_loss / i)
return losses
losses = train_net(n_epochs = 30,
train_loader = train_loader,
net = net)
Représentez graphiquement la perte de sortie avec matplotlib.
Prédisez sur le net en utilisant des données qui ne sont pas utilisées pour la formation. Quand 0 images sont entrées dans le net
img_num = 4
pred = net(X_0_test[img_num:(img_num + 1)])
pred = pred.detach().numpy()
pred = pred[0, 0, :, :]
origin = X_0_test[img_num:(img_num + 1)].numpy()
origin = origin[0, 0, :, :]
plt.subplot(211)
plt.imshow(origin, cmap = "gray")
plt.xticks([])
plt.yticks([])
plt.text(x = 3, y = 2, s = "original image", c = "red")
plt.subplot(212)
plt.imshow(pred, cmap = "gray")
plt.text(x = 3, y = 2, s = "output image", c = "red")
plt.xticks([])
plt.yticks([])
plt.savefig("0_auto_encoder")
plt.show()
Le haut est l'image d'entrée et le bas est l'image de sortie. 0 est bien reproduit.
Lorsque j'ai entré l'image de 6, je ne pouvais pas bien reproduire 6. Si vous ne parvenez pas à bien reproduire les données, vous pouvez juger qu'elles sont anormales (probablement).
À propos, ce modèle a été capable d'apprendre relativement rapidement, même sur un ordinateur portable, alors j'aimerais l'essayer même dans une couche plus profonde.
Recommended Posts