J'écris des programmes de Deep Learning uniquement dans Keras depuis longtemps, mais maintenant je dois écrire dans PyTorch, donc après avoir étudié, j'ai essayé de faire quelque chose qui fonctionne en utilisant MNIST comme exemple.
[Historique des corrections] -Flatten () et Softmax () sont maintenant utilisés dans le modèle -En conséquence, la fonction de perte est changée en CrossEntropyLoss ().
Pour le moment, ce sera un tutoriel au début, donc j'ai commencé PyTorch Tutorial depuis le début.
Cependant, c'est vraiment difficile à comprendre. Je ne pouvais pas saisir "Autograd" sensuellement, et ma motivation est tombée à moins de 10%.
Maintenant, je pense qu'il aurait été préférable de commencer par "Qu'est-ce que torch.nn vraiment?" au lieu de partir du début. ..
J'avais un tel sentiment, alors j'ai commencé le tutoriel et acheté un livre. Après avoir recherché diverses choses, j'ai choisi les deux livres suivants.
Je vais lire ceci attentivement en le copiant.
Alors, après tout, c'est MNIST au début, non? Donc, en vous référant au code officiel de PyTorch, extrayez uniquement les parties nécessaires et modifiez-les pour que vous puissiez les comprendre ** J'ai essayé de.
Pour le moment, je le fais avec Windows 10 + Anaconda + CUDA.
import
import torch
import torch.nn as nn
import torch.optim as optim
from torch.optim.lr_scheduler import StepLR
from torchvision import datasets, transforms
from torchsummary import summary
En gros, c'est toujours un échantillon, mais j'ai ajouté "résumé de la torche" pour confirmation. Malheureusement, il ne peut pas être installé avec conda, je l'ai donc installé avec pip. De plus, la version de torchvision ne correspondait pas et je n'ai pas pu l'installer à partir de l'interface graphique. (Installé avec conda)
seed = 1
epochs = 14
batch_size = 64
log_interval = 100
lr = 1.0
gamma = 0.7
Dans l'exemple, c'était un argument, mais je n'ai extrait que les variables nécessaires et leur ai fait des valeurs fixes. La valeur est le nombre par défaut. (J'ai changé seulement log_interval)
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(1, 32, kernel_size=3, stride=1)
self.conv2 = nn.Conv2d(32, 64, kernel_size=3, stride=1)
self.relu = nn.ReLU(inplace=True)
self.maxpool = nn.MaxPool2d(kernel_size=2)
self.dropout1 = nn.Dropout2d(0.25)
self.dropout2 = nn.Dropout2d(0.5)
self.flatten = nn.Flatten()
self.fc1 = nn.Linear(9216, 128)
self.fc2 = nn.Linear(128, 10)
self.softmax = nn.Softmax(dim=1)
def forward(self, x):
x = self.conv1(x)
x = self.relu(x)
x = self.conv2(x)
x = self.relu(x)
x = self.maxpool(x)
x = self.flatten(x)
x = self.fc1(x)
x = self.relu(x)
x = self.dropout1(x)
x = self.fc2(x)
x = self.relu(x)
x = self.dropout2(x)
output = self.softmax(x)
return output
J'en ai fait une variable interne avec \ _ \ _ init__ () autant que possible. Le dernier est Softmax ().
J'ai également pensé à écrire le modèle avec l'API séquentielle, mais j'ai l'impression que je vais jouer avec lui en fonction de cela, alors je l'ai laissé comme API fonctionnelle.
def train(model, loss_fn, device, train_loader, optimizer, epoch):
model.train()
for batch_idx, (data, target) in enumerate(train_loader):
data, target = data.to(device), target.to(device)
optimizer.zero_grad()
output = model(data)
loss = loss_fn(output, target)
loss.backward()
optimizer.step()
if batch_idx % log_interval == 0:
print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
epoch, batch_idx * len(data), len(train_loader.dataset),
100. * batch_idx / len(train_loader), loss.item()/len(data)))
C'est essentiellement un échantillon. La fonction de perte est maintenant spécifiée par l'appelant.
J'aime le mécanisme de rotation de l'époque du côté de l'appelant et de rotation du lot ici car il est facile à comprendre.
def test(model, loss_fn, device, test_loader):
model.eval()
test_loss = 0
correct = 0
with torch.no_grad():
for data, target in test_loader:
data, target = data.to(device), target.to(device)
output = model(data)
test_loss += loss_fn(output, target) # sum up batch loss
pred = output.argmax(dim=1, keepdim=True) # get the index of the max log-probability
correct += pred.eq(target.view_as(pred)).sum().item()
test_loss /= len(test_loader.dataset)
print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
test_loss, correct, len(test_loader.dataset),
100. * correct / len(test_loader.dataset)))
Encore une fois, j'ai décidé de spécifier la fonction de perte du côté de l'appelant.
Il semble que PyTorch n'ait pas le concept de «prédire», donc je pense que le code ici sera utile lors de la déduction en utilisant le modèle entraîné plus tard. (Je n'ai pas encore écrit le code d'inférence)
view_as () est trop pratique et je suis surpris.
torch.manual_seed(seed)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
Tout d'abord, intégrez une graine aléatoire et spécifiez l'environnement d'exécution (CUDA).
transform=transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.0,), (1.0,))
])
kwargs = {'batch_size': batch_size,
'num_workers': 1,
'pin_memory': True,
'shuffle': True}
dataset1 = datasets.MNIST('../data', train=True, download=True, transform=transform)
dataset2 = datasets.MNIST('../data', train=False, transform=transform)
train_loader = torch.utils.data.DataLoader(dataset1,**kwargs)
test_loader = torch.utils.data.DataLoader(dataset2, **kwargs)
Chargez ensuite le jeu de données MNIST. Lors de la lecture, la moyenne est de 0 et l'écart type est de 1. (J'ai changé cela de l'exemple)
Maintenant, préparez un chargeur de données. Celui-ci est assez pratique. J'espère que ce gars élargira les données. (Pas encore examiné)
Je suis également heureux que la variable objective n'ait pas besoin d'être au format one-hot.
model = Net().to(device)
summary(model, (1,28,28))
loss_fn = nn.CrossEntropyLoss()
optimizer = optim.Adadelta(model.parameters(), lr=lr)
scheduler = StepLR(optimizer, step_size=1, gamma=gamma)
J'ai créé un modèle et affiché son contenu. résumé de la torche, excellent. Ceux qui aiment les keras sont incontournables. Je ne peux pas être soulagé si je ne vois pas ça. Au fait, cette fois, il sera affiché comme ceci.
----------------------------------------------------------------
Layer (type) Output Shape Param #
================================================================
Conv2d-1 [-1, 32, 26, 26] 320
ReLU-2 [-1, 32, 26, 26] 0
Conv2d-3 [-1, 64, 24, 24] 18,496
ReLU-4 [-1, 64, 24, 24] 0
MaxPool2d-5 [-1, 64, 12, 12] 0
Flatten-6 [-1, 9216] 0
Linear-7 [-1, 128] 1,179,776
ReLU-8 [-1, 128] 0
Dropout2d-9 [-1, 128] 0
Linear-10 [-1, 10] 1,290
ReLU-11 [-1, 10] 0
Dropout2d-12 [-1, 10] 0
Softmax-13 [-1, 10] 0
================================================================
Total params: 1,199,882
Trainable params: 1,199,882
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.00
Forward/backward pass size (MB): 1.04
Params size (MB): 4.58
Estimated Total Size (MB): 5.62
----------------------------------------------------------------
Je suis satisfait de l'affichage familier. À propos, il convient de noter que l'ordre de l'arrangement est différent. Comme c'était (lot, hauteur, largeur, canal) tout le temps, je pense que quelque chose ne va pas avec (lot, canal, hauteur, largeur).
N'oubliez pas de préparer la fonction de perte. J'utilise CrossEntropyLoss () pour le modèle Softmax ().
Après cela, décidez de l'algorithme d'optimisation et de la manière d'ajuster le taux d'apprentissage. Ce serait bien de pouvoir intégrer facilement un mécanisme pour modifier le taux d'apprentissage.
for epoch in range(1, epochs + 1):
train(model, loss_fn, device, train_loader, optimizer, epoch)
test(model, loss_fn, device, test_loader)
scheduler.step()
Je continuerai à apprendre avec l'époque. Apprentissage → Évaluation → Ajustement du taux d'apprentissage C'est très facile à comprendre.
torch.save(model.state_dict(), "mnist_cnn.pt")
model.load_state_dict(torch.load("mnist_cnn.pt"))
En prime, j'ai écrit sur la façon de sauvegarder et de charger le modèle entraîné. J'ai regardé le contenu avec un éditeur binaire, mais c'était rafraîchissant.
Je ne suis pas encore familier avec lui, mais j'ai senti qu'il avait les caractéristiques suivantes.
--Facile à saisir le flux ――Peut décrire en détail
J'étudierai plus dur!