[PYTHON] J'ai essayé la reconnaissance d'image de "Moon and Suppon" avec Pytorch (en utilisant torchvision.datasets.ImageFolder qui correspond à from_from_directry de keras)

Lune et suppon

La lune et le suppon sont également ronds, mais la différence est si grande qu'ils ne peuvent pas être comparés. La parabole que les deux sont si différents. https://dictionary.goo.ne.jp/word/%E6%9C%88%E3%81%A8%E9%BC%88/

Il semble y avoir une grande différence, alors voyons si la reconnaissance d'image peut être faite en utilisant le deep learning!

J'expliquerai également Pytorch (un peu) le cas échéant. (Si vous faites une erreur, veuillez la corriger. Merci.)

Le code est ici. https://github.com/kyasby/Tuki-Suppon.git

Ce mot clé

"Lune et Suppon"

Cela semble être similaire et différent.

vision de la torche de pytorch.datasets.ImageFolder」

Je l'ai fait parce qu'il n'y avait pas beaucoup d'articles qui utilisaient torchvision.datasets.ImageFolderdepytorch, qui correspond à keras from_from_directry. Si vous mettez une image dans le dossier, elle sera étiquetée automatiquement. Pratique.

la torche de pytorch.utils.data.random_split」

Grâce à cela, il n'est pas nécessaire de séparer le train et le test lors de la mise des photos dans un dossier.

Données à utiliser

Depuis google image ・ 67 images de Suppon Nous avons rassemblé des images qui semblent avoir été vues du dessus de la coque. Par exemple, une image comme celle-ci. image.png (Suppon de Pii-san) http://photozou.jp/photo/show/235691/190390795

・ 70 images de la lune J'ai rassemblé des images de lunes rondes. Je l'ai découpé à la main pour qu'un grand cercle apparaisse à l'écran. Par exemple, une image comme celle-ci. image.png

Création de l'ensemble de données

.
├── main.ipynb
├── pics
   ├── tuki
   |     |-tuki1.png
   |     |-tuki2.png
   |        
   └── kame
        |-kame1.png
        |-kame2.png

Puisque les images sont divisées en répertoires, utilisez torchvision.datasets.ImageFolde pour étiqueter automatiquement chaque répertoire.

Importation de module

import matplotlib.pyplot as plt
import numpy as np
import copy
import time
import os
from tqdm import tqdm

import torchvision.transforms as transforms
import torchvision.models as models
import torchvision

import torch.nn as nn
import torch

Prétraitement

transform_dict = {
        'train': transforms.Compose(
            [transforms.Resize((256,256)),
             transforms.RandomHorizontalFlip(),
             transforms.ToTensor(),
             transforms.Normalize(mean=[0.485, 0.456, 0.406],
                                  std=[0.229, 0.224, 0.225]),
             ]),
        'test': transforms.Compose(
            [transforms.Resize((256,256)),
             transforms.ToTensor(),
             transforms.Normalize(mean=[0.485, 0.456, 0.406],
                                  std=[0.229, 0.224, 0.225]),
             ])}

Créez un dictionnaire de prétraitement pour l'entraînement et le test. Vous pouvez créer une séquence de prétraitement en utilisant transforms.Compose. Il semble qu'ils sont traités dans l'ordre où ils ont été présentés dans les arguments.

Cette fois, transforms.Resize(256, 256) → Redimensionnez l'image à 256x256.

transforms.RandomHorizontalFlip() → Créez une image qui est retournée horizontalement.

transforms.ToTensor() → PIL ou numpy.ndarray ((hauteur x largeur x canal) (0 ~ 255)) À Il se convertit en Tensor ((canal x hauteur x largeur) (0,0 ~ 1,0)).

Dans PIL et numpy, les images sont de l'ordre de (hauteur x largeur x canal), mais dans Pytorch, il faut noter que (canal x hauteur x largeur). Il semble que cette commande soit plus facile à gérer.

transforms.Normalize(mean=[0.485, 0.456, 0.406],std=[0.229, 0.224, 0.225]) → Normalise chaque GRB avec la valeur moyenne et l'écart type spécifiés.

document https://pytorch.org/docs/stable/torchvision/transforms.html

base de données

# ex.
# data_folder = "./pics"
# transform   = transform_dict["train"]

data = torchvision.datasets.ImageFolder(root=data_folder, transform=transform_dict[phase])

Créez un ensemble de données à partir du répertoire ci-dessus.

Séparation du train et du test

# ex.
# train_ratio = 0.8

train_size = int(train_ratio * len(data))
# int()À un entier.
val_size  = len(data) - train_size      
data_size  = {"train":train_size, "val":val_size}
#          =>{"train": 112,       "val": 28}
data_train, data_val = torch.utils.data.random_split(data, [train_size, val_size])

torch.utils.data.random_split(dataset, lengths) Divise l'ensemble de données ** au hasard **, ** sans couverture **. Bien sûr, l'ensemble de données est Vous pouvez transmettre le nombre d'ensembles de données d'une liste à des longueurs.

J'ai également stocké le train et les tailles de données valides dans le dictionnaire.

# ex.
# data_train => Subset(data, [4,5,1,7])
# data_val  => Subset(data, [3,8,2,6])

Il y a autant de valeurs de retour que de longueurs de liste. Chaque valeur de retour contient une liste d'ensembles de données et de numéros d'index.

(Qu'est-ce que le sous-ensemble?)

Chargeur de données

train_loader = torch.utils.data.DataLoader(data_train, batch_size=batch_size, shuffle=True)
val_loader   = torch.utils.data.DataLoader(data_val,   batch_size=batch_size, shuffle=False)
dataloaders  = {"train":train_loader, "val":val_loader}

Créez un chargeur de données. Dans Pytorch, un chargeur de données est créé et les données sont lues de cette manière. J'ai également mis cela dans le dictionnaire.

Vérifiez l'image

def imshow(img):
    img = img / 2 + 0.5     
    npimg = img.numpy()
    plt.imshow(np.transpose(npimg, (1, 2, 0)))
    plt.show()

#Acquérir aléatoirement des données d'entraînement
dataiter = iter(dataloaders["train"])
images, labels = dataiter.next()

#Affichage de l'image
imshow(torchvision.utils.make_grid(images))
#Affichage de l'étiquette
print(' '.join('%5s' % labels[labels[j]] for j in range(8)))

Il semble que le code ci-dessus l'affiche comme ceci. Je l'ai eu d'ici. Https://qiita.com/kuto/items/0ff3ccb4e089d213871d スクリーンショット 2020-04-20 18.37.17.png

La modélisation

model = models.resnet18(pretrained=True)
for param in model.parameters():
    print(param)
# => Parameter containing:
#tensor([[[[-1.0419e-02, -6.1356e-03, -1.8098e-03,  ...,  5.6615e-02,
#            1.7083e-02, -1.2694e-02],
#          ...
#           -7.1195e-02, -6.6788e-02]]]], requires_grad=True)

Le modèle utilise ResNet18. En mettant pretrained = True dans l'argument, vous pouvez utiliser le modèle entraîné. L'apprentissage par transfert est effectué sans apprendre les paramètres existants. Le poids affiché sous la forme «requires_grad = True» est mis à jour. Pour éviter sa mise à jour, définissez comme suit.

model
# => ResNet(
#   (conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
#   (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
#   (relu): ReLU(inplace=True)
#   (maxpool): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)
#   (layer1): Sequential(
#     (0): BasicBlock(
#       (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
#       (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
#       (relu): ReLU(inplace=True)
#       (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
#       (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
#     )
#   ...
#   (avgpool): AdaptiveAvgPool2d(output_size=(1, 1))
#   (fc): Linear(in_features=512, out_features=1000, bias=True)
# )

Je savais que la couche finale était (fc), donc

for p in model.parameters():
    p.requires_grad=False
model.fc = nn.Linear(512, 2)

Utilisez model.parameters () pour récupérer tous les paramètres, définissez requires_grad = False, et écrasez la couche finale.

Paramètres d'apprentissage


model = model.cuda() #Si vous n'avez pas de GPU, vous n'avez pas besoin de cette ligne.
lr = 1e-4
epoch = 40
optim = torch.optim.Adam(model.parameters(), lr=lr, weight_decay=1e-4)
criterion = nn.CrossEntropyLoss().cuda() #Sans GPU.cuda()Je n'en ai pas besoin.

Si vous souhaitez utiliser le GPU, vous devez envoyer le modèle au GPU.

Le modèle est presque le même que le tutoriel. https://pytorch.org/tutorials/beginner/transfer_learning_tutorial.html

La modélisation


def train_model(model, criterion, optimizer, scheduler=None, num_epochs=25):
    #:Renvoie la valeur booléenne.
    use_gpu = torch.cuda.is_available()
    #Heure de début
    since = time.time()
    
    best_model_wts = copy.deepcopy(model.state_dict())
    best_acc = 0.0
    
    #Créez un dictionnaire avec une liste pour enregistrer la progression.
    loss_dict ={"train" : [],  "val" : []}
    acc_dict = {"train" : [],  "val" : []}  

    for epoch in tqdm(range(num_epochs)):
        if (epoch+1)%5 == 0:#L'époque est affichée une fois toutes les cinq fois.
            print('Epoch {}/{}'.format(epoch, num_epochs - 1))
            print('-' * 10)
        
        #A chaque époque, formez,Exécutez val.
        #La puissance mise dans le dictionnaire est démontrée ici, et vous pouvez écrire train et val en une seule fois.
        for phase in ['train', 'val']:
            if phase == 'train':
                model.train()   #Mode d'apprentissage. Faites des abandons, etc.
            else:
                model.val()  #Mode d'inférence. N'abandonnez pas.
            
            running_loss = 0.0
            running_corrects = 0
            
            for data in dataloaders[phase]:
                inputs, labels = data #Les données créées par ImageFolder sont
                                      #Il vous apportera une étiquette pour vos données.
                
                #Non requis si vous n'utilisez pas de GPU
                if use_gpu:
                    inputs = inputs.cuda()
                    labels = labels.cuda()
                
                

                #~~~~~~~~~~~~~~forward~~~~~~~~~~~~~~~
                outputs = model(inputs)

                _, preds = torch.max(outputs.data, 1)
               #torch.max renvoie la valeur réelle et l'index.
               #torch.max((0.8, 0.1),1)=> (0.8, 0)
               #L'argument 1 est de savoir s'il faut renvoyer la valeur maximale dans le sens de la ligne ou dans le sens de la colonne.
                loss = criterion(outputs, labels)

                if phase == 'train':
                    optimizer.zero_grad()
                    loss.backward()
                    optimizer.step()
                
                # statistics #Article sans GPU()Inutile
                running_loss += loss.item() * inputs.size(0) 
                running_corrects += torch.sum(preds == labels)
                # (preds == labels)Est[True, True, False]Etc., mais
                #python vrai,Faux vaut 1 chacun,Puisqu'il correspond à 0,
                #Vous pouvez additionner avec somme.
               
               #Enregistrer la progression dans la liste
               loss_dict[phase].append(epoch_loss)
               acc_dict[phase].append(epoch_acc)

            #Divisez par le nombre d'échantillons pour obtenir la moyenne.
            #Mettre le nombre d'échantillons dans le dictionnaire prend vie.
            epoch_loss = running_loss / data_size[phase]
            #Article sans GPU()Inutile
            epoch_acc = running_corrects.item() / data_size[phase]

           #tensot().item()Vous pouvez récupérer la valeur du tenseur en utilisant.
           #print(tensorA)       => tensor(112, device='cuda:0')
           #print(tensorA.itme)) => 112
                        
            #Utilisez le format,.Avec nf, vous pouvez générer jusqu'à n chiffres après la virgule décimale.
            #C'est la même chose que le langage C.
            print('{} Loss: {:.4f} Acc: {:.4f}'.format(phase, epoch_loss, epoch_acc))
            
            # deep copy the model
            #Enregistrez le modèle lorsque la précision s'améliore
            if phase == 'val' and epoch_acc > best_acc:
                best_acc = epoch_acc
                best_model_wts = copy.deepcopy(model.state_dict())
            #Sans deepcopy, modèle.state_dict()En raison de modifications du contenu
            #Les données copiées (devraient) changeront également.
            #La différence entre la copie et la copie profonde est facile à comprendre dans cet article.
            # https://www.headboost.jp/python-copy-deepcopy/

    time_elapsed = time.time() - since
    print('Training complete in {:.0f}m {:.0f}s'.format(time_elapsed // 60, time_elapsed % 60))
    print('Best val acc: {:.4f}'.format(best_acc))
    
    #Lit et renvoie le meilleur poids.
    model.load_state_dict(best_model_wts)
    return model, loss_dict, acc_dict

Apprentissage

model_ft, loss, acc = train_model(model, criterion, optim, num_epochs=epoch)

Visualisez l'apprentissage


#loss,Sortez acc.
loss_train = loss["train"]
loss_val   = loss["val"]

acc_train = acc["train"]
acc_val   = acc["val"]


#En écrivant ainsi, vous pouvez créer un graphique de lignes x cols.
fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(10,5))

#0e graphique
axes[0].plot(range(epoch), loss_train, label = "train")
axes[0].plot(range(epoch), loss_val,    label =  "val")
axes[0].set_title("Loss")
axes[0].legend()#Afficher l'étiquette de chaque graphique

#1er graphique
axes[1].plot(range(epoch), acc_train, label = "train")
axes[1].plot(range(epoch), acc_val,    label =  "val")
axes[1].set_title("Train Loss")
axes[1].legend()

#Ajustez pour que les 0e et 1er graphiques ne se chevauchent pas
fig.tight_layout()

Avez-vous surapprendre vers 11 ou 12 époques? image.png

prime

GoogleColabolatory La collaboration est un moyen simple d'utiliser le GPU. https://colab.research.google.com/notebooks/welcome.ipynb?hl=ja Lorsque vous utilisez des images en collaboration, il est pratique de les télécharger sous forme de zip. (Il est difficile de télécharger un par un.) (La méthode de liaison avec le lecteur est également OK) A ce moment, la décompression peut être effectuée comme suit.

#/content/pics.Veuillez changer chaque zip.
!unzip /content/pics.zip -d /content/data > /dev/null 2>&1 &

En outre, "Copier le chemin" qui apparaît lorsque vous cliquez avec le bouton droit sur le fichier est également pratique.

matplotlib.plt Cette fois, je produis un graphique avec 1 ligne et 2 colonnes, mais s'il s'agit de 2 lignes et 2 colonnes, par exemple, vous pouvez créer un graphique comme suit. Vous pouvez également écraser un tracé sur un graphique et en tracer deux en même temps. J'ai tracé deux de chaque graphique.

loss_train = loss["train"]
loss_val    = loss["val"]

acc_train = acc["train"]
acc_val    = acc["val"]

fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(10,5))
axes[0,0].plot(range(epoch), loss_train, label = "train")
axes[0,0].plot(range(epoch), loss_val,    label =  "val")
axes[0,0].set_title("Loss")
axes[0,0].legend()

axes[0,1].plot(range(epoch), acc_train, c="red",  label = "train")
axes[0,1].plot(range(epoch), acc_val,    c="pink", label =  "val")
axes[0,1].set_title("Train Loss")
axes[0,1].legend()

x = np.random.rand(100)
xx = np.random.rand(200)
axes[1,0].hist(xx, bins=25, label="xx")
axes[1,0].hist(x, bins=50,   label="x")
axes[1,0].set_title("histgram")

y = np.random.randn(100)
z = np.random.randn(100)
axes[1,1].scatter(y, z, alpha=0.8, label="y,z") 
axes[1,1].scatter(z, y, alpha=0.8, label="z,y")
axes[1,1].set_title("Scatter")
axes[1,1].legend()

fig.tight_layout()

image.png

Recommended Posts

J'ai essayé la reconnaissance d'image de "Moon and Suppon" avec Pytorch (en utilisant torchvision.datasets.ImageFolder qui correspond à from_from_directry de keras)
J'ai essayé la reconnaissance de caractères manuscrits des caractères runiques avec CNN en utilisant Keras
J'ai essayé la reconnaissance d'image de CIFAR-10 avec Keras-Learning-
J'ai essayé la reconnaissance d'image de CIFAR-10 avec la reconnaissance d'image Keras-
[Python] J'ai essayé de juger l'image du membre du groupe d'idols en utilisant Keras
J'ai essayé de créer une API de reconnaissance d'image simple avec Fast API et Tensorflow
J'ai essayé d'implémenter Grad-CAM avec keras et tensorflow
J'ai essayé la reconnaissance faciale du problème du rire en utilisant Keras.
J'ai essayé de transformer l'image du visage en utilisant sparse_image_warp de TensorFlow Addons
J'ai essayé d'obtenir les résultats de Hachinai en utilisant le traitement d'image
J'ai essayé de convertir la chaîne datetime <-> avec tzinfo en utilisant strftime () et strptime ()
J'ai essayé d'extraire et d'illustrer l'étape de l'histoire à l'aide de COTOHA
J'ai essayé d'implémenter CVAE avec PyTorch
J'ai essayé la reconnaissance d'image simple avec Jupyter
J'ai essayé de comparer la précision de la classification des phrases BERT japonaises et japonaises Distil BERT avec PyTorch et introduction de la technique d'amélioration de la précision BERT
J'ai essayé de notifier la mise à jour de "Hameln" en utilisant "Beautiful Soup" et "IFTTT"
J'ai essayé de faire la reconnaissance de caractères manuscrits de Kana Partie 3/3 Coopération avec l'interface graphique en utilisant Tkinter
J'ai essayé la reconnaissance manuscrite des caractères des runes avec scikit-learn
J'ai essayé d'implémenter la lecture de Dataset avec PyTorch
J'ai essayé d'intégrer Keras dans TFv1.1
J'ai essayé de corriger la forme trapézoïdale de l'image
J'ai essayé d'utiliser le filtre d'image d'OpenCV
J'ai essayé de notifier la mise à jour de "Devenir romancier" en utilisant "IFTTT" et "Devenir un romancier API"
Je voulais collecter beaucoup d'images, j'ai donc essayé d'utiliser "google image download"
J'ai essayé d'automatiser la mise à jour de l'article du blog Livedoor avec Python et sélénium.
J'ai essayé d'extraire le texte du fichier image en utilisant Tesseract du moteur OCR
Traitement d'image avec Python (j'ai essayé de le binariser en art mosaïque 0 et 1)
J'ai essayé de comparer la vitesse de traitement avec dplyr de R et pandas de Python
J'ai essayé de lire et d'enregistrer automatiquement avec VOICEROID2 2
[OpenCV / Python] J'ai essayé l'analyse d'image de cellules avec OpenCV
J'ai essayé de lire et d'enregistrer automatiquement avec VOICEROID2
[Introduction à Pytorch] J'ai essayé de catégoriser Cifar10 avec VGG16 ♬
J'ai essayé d'implémenter SSD avec PyTorch maintenant (Dataset)
J'ai essayé de compresser l'image en utilisant l'apprentissage automatique
[Dessin graphique] J'ai essayé d'écrire un graphique à barres multi-séries avec matplotlib et seaborn
J'ai essayé d'utiliser PI Fu pour générer un modèle 3D d'une personne à partir d'une image
J'ai essayé de prédire et de soumettre les survivants du Titanic avec Kaggle
J'ai essayé la "correction gamma" de l'image avec Python + OpenCV
J'ai essayé de trouver la moyenne de plusieurs colonnes avec TensorFlow
Classification d'images avec un réseau de neurones auto-fabriqué par Keras et PyTorch
J'ai essayé d'obtenir les informations du Web en utilisant "Requests" et "lxml"
J'ai essayé de classer MNIST par GNN (avec PyTorch géométrique)
J'ai essayé d'implémenter ListNet d'apprentissage de rang avec Chainer
J'ai essayé de créer une interface graphique à trois yeux côte à côte avec Python et Tkinter
J'ai essayé d'implémenter SSD avec PyTorch maintenant (édition du modèle)
J'ai essayé d'utiliser du pyenv, que je détestais sans manger, et c'était trop pratique de m'asseoir.
J'ai essayé de vérifier l'identification du locuteur par l'API de reconnaissance du locuteur d'Azure Cognitive Services avec Python. # 1
Reconnaissance d'image des déchets avec Edge (Raspberry Pi) à partir de zéro connaissance en utilisant AutoML Vsion et TPU
J'ai essayé de vérifier l'identification du locuteur par l'API de reconnaissance du locuteur d'Azure Cognitive Services avec Python. # 2
J'ai essayé de prédire les hauts et les bas du cours de clôture du cours de l'action de Guru Navi en utilisant TensorFlow (progression)
J'ai essayé la reconnaissance faciale avec Face ++
Reconnaissance d'image avec Keras + OpenCV
J'ai essayé d'obtenir une base de données sur les courses de chevaux en utilisant Pandas
J'ai essayé d'obtenir l'index de la liste en utilisant la fonction énumérer
J'ai essayé d'automatiser l'arrosage du pot avec Raspberry Pi
J'ai essayé de visualiser les signets volant vers Slack avec Doc2Vec et PCA
J'ai essayé de rendre le deep learning évolutif avec Spark × Keras × Docker
J'ai essayé de créer une expression régulière de "temps" en utilisant Python
J'ai essayé de créer l'image de démarrage SD de LicheePi Nano