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
"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.ImageFolderde
pytorch, 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.
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. (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.
.
├── 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.
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
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
# 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.
# 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?)
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.
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
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.
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
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
model_ft, loss, acc = train_model(model, criterion, optim, num_epochs=epoch)
#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?
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()
Recommended Posts