Introduction to pytorch (1) Introduction to pytorch
Fish Cat Classifier
task
Design a classifier to distinguish fish from cats.
🐟 | 🐱 |
---|---|
![]() | ![]() |
data
ImageNet: A standard collection of images used to train neural networks that contains more than 14 million images and 2000 image categories.
github has the download code, but I'm always not running right, so I've just downloaded the pictures from other sources. Extraction Code: pypt)
dataset and data loader
pytorch uses dataset and data loader to establish a connection between data and a neural network.
Datasets that conform to the following classes can be trained by feeding neural networks.
class Dataset(object): def __getitem__(self, index): raise NotImplementedError def __len__(self): raise NotImplementedError
len: Returns the length of the data.
getitem: Returns the corresponding tensor and label for each batch_size.
Establishing training datasets
import torch import torch.nn as nn import torch.optim as optim import torch.utils.data import torch.nn.functional as F import torchvision from torchvision import transforms from PIL import Image train_data_path = "./train/" transforms = transforms.Compose([ transforms.Resize(64), # Convert to 64*64 transforms.ToTensor(), # Convert image to tensor transforms.Normalize(mean=[0.485, 0.456, 0.406], # normalize std=[0.229, 0.224, 0.225]) ]) train_data = torchvision.datasets.ImageFolder(root=train_data_path, transform=transforms)
Establish validation and test datasets
val_data_path = "./val/" val_data = torchvision.datasets.ImageFolder(root=val_data_path, transform=transforms) test_data_path = "./test/" test_data = torchvision.datasets.ImageFolder(root=test_data_path, transform=transforms)
Create dataloder
batch_size = 64 train_data_loader = torch.utils.data.DataLoader(train_data, batch_size=batch_size) val_data_loader = torch.utils.data.DataLoader(val_data, batch_size=batch_size) test_data_loader = torch.utils.data.DataLoader(test_data, batch_size=batch_size)
batch_size
Understand the number of data fed to the network each time. A larger batch_size allows the program to learn global information better, but takes up more memory space. The pytorch default batch_size is 1.
Setting up a neural network
It contains:
- One input layer: processes the input tensor
- Output layer: used to determine type
- Hidden Layer
# Define Neural Network class net(nn.Module): def __init__(self): super(net, self).__init__() self.fc1 = nn.Linear(12288, 84) # 64*64*3 self.fc2 = nn.Linear(84, 20) self.fc3 = nn.Linear(20, 2) def forward(self, x): x = nn.ReLU(self.fc1(x)) x = nn.ReLU(self.fc2(x)) x = nn.Softmax(self.fc3(x)) return x
- init() is used to set up network layers
- forward() is used to describe the flow of data in training or prediction
lossfunction
pytorch sets loss function to determine how to update the network to achieve the desired results.
pytorch contains the vast majority of loss function functions and can also use custom functions.
CrossEntropyLoss is chosen as the loss function. It combines nn.LogSoftmax() and nn.NLLLoss() functions.
softmax:
S
i
=
e
i
∑
i
e
i
S_i=\frac{e^i}{\sum_{i}e^i}\quad
Si=∑ieiei
Cross-Entropy:
∑
i
p
i
l
o
g
(
p
i
)
\sum_{i}p_ilog(p_i)
i∑pilog(pi)
So modify forward.
def forward(self): # Convert to 1D vector x = x.view(-1, 12288) x = F.relu(self.fc1(x)) x = F.relu(self.fc2(x)) x = self.fc3(x) return x
optimizing
Use the optimizer to keep up with each training of the neural network.
The models included SGD (Random Gradient Decrease), AdaGrad (Learning Rate is different for each parameter), RMSProp (Setting Decay Factor), and Adam (Self-designed Learning Rate).
net = net() optimizer = optim.Adam(net.parameters(), lr=0.001)
train
def train(model, loss_fn, device, optimizer, epochs=20): train_loss = 0.0 val_loss = 0.0 model.train() # Training mode for epoch in range(epochs): for batch in train_data_loader: optimizer.zero_grad() # Empty last calculated gradient inputs, traget = batch inputs, traget = inputs.to(device), traget.to(device) # Put the tensor on the gpu, if possible output = model.forward(inputs) loss = loss_fn(output, traget) # Calculating loss loss.backward() # Reverse Propagation optimizer.step() # Update Weights train_loss += loss.data.item() train_loss /= len(train_data) model.eval() # Test mode num_correct = 0 num_examples = 0 for batch in val_data_loader: inputs, traget = batch inputs, traget = inputs.to(device), traget.to(device) output = model.forward(inputs) loss = loss_fn(output, traget) val_loss += loss.data.item() correct = torch.eq(torch.max(F.softmax(output, dim=1), dim=1)[1], traget).view(-1) num_correct += sum(correct).item() num_examples += correct.shape[0] val_loss /= len(val_data) print( 'epoch[{}|{}],train_loss:{:.4f},val_loss:{:.4f},accuary:{:.4f}' .format(epoch + 1, epochs, train_loss, val_loss, num_correct / num_examples))
parameter
simnet = net() device = 'cuda' if torch.cuda.is_available() else 'cpu' simnet.to(device) optimizer = optim.Adam(simnet.parameters(), lr=0.001) train(model=simnet, optimizer=optimizer, loss_fn=torch.nn.CrossEntropyLoss(), device=device)
Forecast
# test labels = ['cat', 'fish'] img = Image.open('train/cat/19.jpg') img = img_transforms(img) img = img.unsqueeze(0) pre = simnet(img.to(device)) pre = pre.argmax() print(labels[pre])
Model Save
# save torch.save(simnet, "/cat_fish_classification") # load simnet = torch.load('cat_fish_classification') # save model parameter torch.save(simnet.state_dict(), 'cat_fish_classification') # load simnet = net() simnet_state_dict = torch.load('cat_fish_classification') simnet.load_state_dict(simnet_state_dict)
torch.save() made a mistake. The exact reason is not clear. Leave a hole first.
All Code
import torch import torch.nn as nn import torch.optim as optim import torch.utils.data import torch.nn.functional as F import torchvision from torchvision import transforms from PIL import Image def check_image(path): try: im = Image.open(path) return True except: return False img_transforms = transforms.Compose([ transforms.Resize((64, 64)), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ]) train_data_path = "./train/" train_data = torchvision.datasets.ImageFolder(root=train_data_path, transform=img_transforms, is_valid_file=check_image) val_data_path = "./val/" val_data = torchvision.datasets.ImageFolder(root=val_data_path, transform=img_transforms, is_valid_file=check_image) test_data_path = "./test" test_data = torchvision.datasets.ImageFolder(root=test_data_path, transform=img_transforms, is_valid_file=check_image) batch_size = 64 train_data_loader = torch.utils.data.DataLoader(train_data, batch_size=batch_size) val_data_loader = torch.utils.data.DataLoader(val_data, batch_size=batch_size) test_data_loader = torch.utils.data.DataLoader(test_data, batch_size=batch_size) # Define Neural Network class net(nn.Module): def __init__(self): super(net, self).__init__() self.fc1 = nn.Linear(12288, 84) # 64*64*3 self.fc2 = nn.Linear(84, 20) self.fc3 = nn.Linear(20, 2) def forward(self, x): x = x.view(-1, 12288) x = F.relu(self.fc1(x)) x = F.relu(self.fc2(x)) x = self.fc3(x) return x # model = net() def train(model, loss_fn, device, optimizer, epochs=20): train_loss = 0.0 val_loss = 0.0 model.train() # Training mode for epoch in range(epochs): for batch in train_data_loader: optimizer.zero_grad() # Empty last calculated gradient inputs, traget = batch inputs, traget = inputs.to(device), traget.to(device) # Put the tensor on the gpu, if possible output = model.forward(inputs) loss = loss_fn(output, traget) # Calculating loss loss.backward() # Reverse Propagation optimizer.step() # Update Weights train_loss += loss.data.item() train_loss /= len(train_data) model.eval() # Test mode num_correct = 0 num_examples = 0 for batch in val_data_loader: inputs, traget = batch inputs, traget = inputs.to(device), traget.to(device) output = model.forward(inputs) loss = loss_fn(output, traget) val_loss += loss.data.item() correct = torch.eq(torch.max(F.softmax(output, dim=1), dim=1)[1], traget).view(-1) num_correct += sum(correct).item() num_examples += correct.shape[0] val_loss /= len(val_data) print( 'epoch[{}|{}],train_loss:{:.4f},val_loss:{:.4f},accuary:{:.4f}' .format(epoch + 1, epochs, train_loss, val_loss, num_correct / num_examples)) if __name__ == '__main__': simnet = net() device = 'cuda' if torch.cuda.is_available() else 'cpu' simnet.to(device) optimizer = optim.Adam(simnet.parameters(), lr=0.001) train(model=simnet, optimizer=optimizer, loss_fn=torch.nn.CrossEntropyLoss(), device=device) # test labels = ['cat', 'fish'] img = Image.open('train/cat/19.jpg') img = img_transforms(img) img = img.unsqueeze(0) pre = simnet(img.to(device)) pre = pre.argmax() print(labels[pre]) # save torch.save(simnet, "/cat_fish_classification") # load simnet = torch.load('cat_fish_classification') # save model parameter torch.save(simnet.state_dict(), 'cat_fish_classification') # load simnet = net() simnet_state_dict = torch.load('cat_fish_classification') simnet.load_state_dict(simnet_state_dict)