Der Mond und das Suppon sind ähnlich rund, aber der Unterschied ist so groß, dass sie nicht verglichen werden können. Das Gleichnis, dass die beiden so unterschiedlich sind. https://dictionary.goo.ne.jp/word/%E6%9C%88%E3%81%A8%E9%BC%88/
Es scheint einen großen Unterschied zu geben, also versuchen wir es mit der Bilderkennung mithilfe von Deep Learning!
Ich werde auch Pytorch (ein wenig) nach Bedarf erklären. (Wenn Sie einen Fehler machen, korrigieren Sie ihn bitte. Vielen Dank.)
Der Code ist hier. https://github.com/kyasby/Tuki-Suppon.git
"Mond und Suppon"
Es scheint ähnlich und anders zu sein.
Pytorch "Fackel Vision.datasets.ImageFolder」
Ich habe es gemacht, weil es nicht viele Artikel gab, die torchvision.datasets.ImageFoldervon
pytorch verwendeten, was
keras from_from_directry` entspricht.
Wenn Sie ein Bild in den Ordner legen, wird es automatisch beschriftet. Praktisch.
Pytorch "Fackel.utils.data.random_split」
Dank dessen müssen Zug und Test nicht getrennt werden, wenn Fotos in einem Ordner abgelegt werden.
Von Google Image ・ 67 Bilder von Suppon Wir haben Bilder gesammelt, die aussehen, als wären sie von oben über der Muschel zu sehen. Zum Beispiel ein Bild wie dieses. (Pii-sans Suppon) http://photozou.jp/photo/show/235691/190390795
・ 70 Bilder des Mondes Ich habe Bilder von runden Monden gesammelt. Ich schneide es von Hand aus, so dass ein großer Kreis auf dem Bildschirm erscheint. Zum Beispiel ein Bild wie dieses.
.
├── main.ipynb
├── pics
├── tuki
| |-tuki1.png
| |-tuki2.png
|
└── kame
|-kame1.png
|-kame2.png
Da die Bilder in Verzeichnisse unterteilt sind, verwenden Sie "torchvision.datasets.ImageFolde", um jedes Verzeichnis automatisch zu kennzeichnen.
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]),
])}
Erstellen Sie ein Vorverarbeitungswörterbuch für Zug und Test. Sie können eine Vorverarbeitungssequenz erstellen, indem Sie "transforms.Compose" verwenden. Es scheint, dass sie in der Reihenfolge verarbeitet werden, in der sie in die Argumente aufgenommen wurden.
Diesmal,
transforms.Resize(256, 256)
→ Ändern Sie die Größe des Bildes auf 256x256.
transforms.RandomHorizontalFlip()
→ Erstellen Sie ein Bild, das horizontal gespiegelt wird.
transforms.ToTensor()
→ PIL oder numpy.ndarray ((Höhe x Breite x Kanal) (0 ~ 255))
Zu
Es wird in Tensor konvertiert ((Kanal x Höhe x Breite) (0,0 ~ 1,0)).
In PIL und Numpy liegen die Bilder in der Reihenfolge (Höhe x Breite x Kanal), in Pytorch ist jedoch zu beachten, dass (Kanal x Höhe x Breite). Es scheint, dass diese Bestellung einfacher zu handhaben ist.
transforms.Normalize(mean=[0.485, 0.456, 0.406],std=[0.229, 0.224, 0.225])
→ Normalisiert jeden GRB mit dem angegebenen Mittelwert und der Standardabweichung.
Dokument 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])
Erstellen Sie einen Datensatz aus dem obigen Verzeichnis.
# ex.
# train_ratio = 0.8
train_size = int(train_ratio * len(data))
# int()Zu einer ganzen Zahl.
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)
Teilt den Datensatz ** zufällig **, ** ohne Deckung **.
Natürlich ist der Datensatz
Sie können die Anzahl der Datensätze in einer Liste an Längen übergeben.
Ich habe auch den Zug und gültige Datengrößen im Wörterbuch gespeichert.
# ex.
# data_train => Subset(data, [4,5,1,7])
# data_val => Subset(data, [3,8,2,6])
Es gibt so viele Rückgabewerte wie Listenlängen. Jeder Rückgabewert enthält eine Liste von Datensätzen und Indexnummern.
(Was ist Teilmenge?)
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}
Erstellen Sie einen Datenlader. In Pytorch wird ein Datenlader erstellt und die Daten auf diese Weise gelesen. Ich habe dies auch in das Wörterbuch aufgenommen.
def imshow(img):
img = img / 2 + 0.5
npimg = img.numpy()
plt.imshow(np.transpose(npimg, (1, 2, 0)))
plt.show()
#Erfassen Sie nach dem Zufallsprinzip Trainingsdaten
dataiter = iter(dataloaders["train"])
images, labels = dataiter.next()
#Bildschirm
imshow(torchvision.utils.make_grid(images))
#Anzeige des Etiketts
print(' '.join('%5s' % labels[labels[j]] for j in range(8)))
Es scheint, dass der obige Code es so anzeigt. Ich habe es von hier bekommen. 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)
Das Modell verwendet ResNet18. Indem Sie "pretrained = True" in das Argument einfügen, können Sie das trainierte Modell verwenden.
Das Transferlernen wird durchgeführt, ohne vorhandene Parameter zu lernen.
Das als require_grad = True
angezeigte Gewicht wird aktualisiert.
Stellen Sie Folgendes ein, um eine Aktualisierung zu verhindern.
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)
# )
Ich wusste, dass die letzte Schicht "(fc)" war, also
for p in model.parameters():
p.requires_grad=False
model.fc = nn.Linear(512, 2)
Verwenden Sie model.parameters ()
, um alle Parameter abzurufen, setzen Sie require_grad = False
und überschreiben Sie die letzte Ebene.
model = model.cuda() #Wenn Sie keine GPU haben, benötigen Sie diese Leitung nicht.
lr = 1e-4
epoch = 40
optim = torch.optim.Adam(model.parameters(), lr=lr, weight_decay=1e-4)
criterion = nn.CrossEntropyLoss().cuda() #Ohne GPU.cuda()Ich brauche es nicht
Wenn Sie eine GPU verwenden möchten, müssen Sie das Modell an die GPU senden.
Das Modell ist fast das gleiche wie im Tutorial. https://pytorch.org/tutorials/beginner/transfer_learning_tutorial.html
def train_model(model, criterion, optimizer, scheduler=None, num_epochs=25):
#:Gibt den Bool-Wert zurück.
use_gpu = torch.cuda.is_available()
#Startzeit
since = time.time()
best_model_wts = copy.deepcopy(model.state_dict())
best_acc = 0.0
#Erstellen Sie ein Wörterbuch mit einer Liste zum Speichern des Fortschritts.
loss_dict ={"train" : [], "val" : []}
acc_dict = {"train" : [], "val" : []}
for epoch in tqdm(range(num_epochs)):
if (epoch+1)%5 == 0:#Die Epoche wird alle fünf Male angezeigt.
print('Epoch {}/{}'.format(epoch, num_epochs - 1))
print('-' * 10)
#Trainiere in jeder Epoche,Val ausführen.
#Die im Wörterbuch enthaltene Leistung wird hier demonstriert, und Sie können Zug und Wert auf einmal schreiben.
for phase in ['train', 'val']:
if phase == 'train':
model.train() #Lernmodus. Dropout etc. machen
else:
model.val() #Inferenzmodus. Nicht aussteigen.
running_loss = 0.0
running_corrects = 0
for data in dataloaders[phase]:
inputs, labels = data #Die von ImageFolder erstellten Daten sind
#Sie erhalten ein Etikett für Ihre Daten.
#Nicht erforderlich, wenn keine GPU verwendet wird
if use_gpu:
inputs = inputs.cuda()
labels = labels.cuda()
#~~~~~~~~~~~~~~forward~~~~~~~~~~~~~~~
outputs = model(inputs)
_, preds = torch.max(outputs.data, 1)
#torch.max gibt den tatsächlichen Wert und den Index zurück.
#torch.max((0.8, 0.1),1)=> (0.8, 0)
#Argument 1 ist, ob der Maximalwert in Zeilen- oder Spaltenrichtung zurückgegeben werden soll.
loss = criterion(outputs, labels)
if phase == 'train':
optimizer.zero_grad()
loss.backward()
optimizer.step()
# statistics #Artikel ohne GPU()Nicht notwendig
running_loss += loss.item() * inputs.size(0)
running_corrects += torch.sum(preds == labels)
# (preds == labels)Ist[True, True, False]Usw., aber
#Python True,Falsch ist jeweils 1,Da es 0 entspricht,
#Sie können mit Summe addieren.
#Speichern Sie den Fortschritt in der Liste
loss_dict[phase].append(epoch_loss)
acc_dict[phase].append(epoch_acc)
#Teilen Sie durch die Anzahl der Proben, um den Durchschnitt zu erhalten.
#Das Einfügen der Anzahl von Samples in das Wörterbuch wird zum Leben erweckt.
epoch_loss = running_loss / data_size[phase]
#Artikel ohne GPU()Nicht notwendig
epoch_acc = running_corrects.item() / data_size[phase]
#tensot().item()Sie können den Wert mithilfe von aus dem Tensor abrufen.
#print(tensorA) => tensor(112, device='cuda:0')
#print(tensorA.itme)) => 112
#Ich benutze Format,.Mit nf können Sie bis zu n Nachkommastellen ausgeben.
#Es ist das gleiche wie C-Sprache.
print('{} Loss: {:.4f} Acc: {:.4f}'.format(phase, epoch_loss, epoch_acc))
# deep copy the model
#Speichern Sie das Modell, wenn sich die Genauigkeit verbessert
if phase == 'val' and epoch_acc > best_acc:
best_acc = epoch_acc
best_model_wts = copy.deepcopy(model.state_dict())
#Ohne Deepcopy Modell.state_dict()Aufgrund von Änderungen im Inhalt
#Die kopierten (Soll-) Daten ändern sich ebenfalls.
#Der Unterschied zwischen Kopie und Deepcopy ist in diesem Artikel leicht zu verstehen.
# 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))
#Liest und gibt das beste Gewicht zurück.
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,Nehmen Sie gem.
loss_train = loss["train"]
loss_val = loss["val"]
acc_train = acc["train"]
acc_val = acc["val"]
#Wenn Sie so schreiben, können Sie ein Diagramm mit Zeilen x Spalten erstellen.
fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(10,5))
#0. Grafik
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()#Beschriftung jedes Diagramms anzeigen
#1. Grafik
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()
#Stellen Sie so ein, dass sich das 0. und 1. Diagramm nicht überlappen
fig.tight_layout()
Überlernen Sie in etwa 11 oder 12 Epochen?
GoogleColabolatory Es gibt eine Zusammenarbeit als einfache Möglichkeit, die GPU zu verwenden. https://colab.research.google.com/notebooks/welcome.ipynb?hl=ja Wenn Sie Bilder in Zusammenarbeit verwenden, können Sie sie bequem als Zip hochladen. (Es ist schwierig, eine nach der anderen hochzuladen.) (Die Methode zum Verknüpfen mit dem Laufwerk ist ebenfalls in Ordnung.) Zu diesem Zeitpunkt kann die Dekomprimierung wie folgt durchgeführt werden.
#/content/pics.Bitte ändern Sie jede Postleitzahl.
!unzip /content/pics.zip -d /content/data > /dev/null 2>&1 &
Auch "Pfad kopieren", der angezeigt wird, wenn Sie mit der rechten Maustaste auf die Datei klicken, ist praktisch.
matplotlib.plt Dieses Mal gebe ich ein Diagramm mit 1 Zeile und 2 Spalten aus. Wenn es sich jedoch beispielsweise um 2 Zeilen und 2 Spalten handelt, können Sie ein Diagramm wie folgt erstellen. Sie können auch ein Diagramm in einem Diagramm überschreiben und zwei gleichzeitig zeichnen. Ich habe jeweils zwei für jedes Diagramm gezeichnet.
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