専門ユニット2/山内研セミナー(2021/12/14)

関連サイトと資料

プログラム

Defining the loss function

from torch import nn
from torch.utils.data import TensorDataset
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn.functional as F
import torch
   
class Net(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(1, 20, 5, 1)
        self.conv2 = nn.Conv2d(20, 50, 5, 1)
        self.fc1 = nn.Linear(4*4*50, 500)
        self.fc2 = nn.Linear(500, 10)
   
    def forward(self, x):
        x = F.relu(self.conv1(x))
        x = F.max_pool2d(x, 2, 2)
        x = F.relu(self.conv2(x))
        x = F.max_pool2d(x, 2, 2)
        x = x.view(-1, 4*4*50)
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        return F.log_softmax(x, dim=1)
   
model = Net()
   
# path to store data and/or load from
path2data = './data'
   
# loading MNIST training dataset
train_data=datasets.MNIST(path2data, train=True, download=True)
   
# extract data and targets
x_train, y_train = train_data.data, train_data.targets
if len(x_train.shape) == 3:
    x_train = x_train.unsqueeze(1)
    
# loading validation data
val_data = datasets.MNIST(path2data, train=False, download=True)
   
# extract data and targets
x_val, y_val = val_data.data, val_data.targets
if len(x_val.shape) == 3:
    x_val = x_val.unsqueeze(1)
   
# wrap tensors into a dataset
train_ds = TensorDataset(x_train, y_train)
val_ds = TensorDataset(x_val, y_val)
     
# create a data loader from dataset
train_dl = DataLoader(train_ds, batch_size=8)
val_dl = DataLoader(val_ds, batch_size=8)
   
loss_func = nn.NLLLoss(reduction="sum")
   
for xb, yb in train_dl:
    xb=xb.type(torch.float)
    # get model output
    out=model(xb)
    # calculate loss value
    loss = loss_func(out, yb)
    print (loss.item())
   
    # compute gradients
    loss.backward()
    break
    

Defining the optimizer

from torch import optim
opt = optim.Adam(model.parameters(), lr=1e-4)
  
# update model parameters
opt.step()
  
# set gradients to zero
opt.zero_grad()
    

Training and evaluation

# ミニバッチあたりの損失値を計算
def loss_batch(loss_func, xb, yb, yb_h, opt=None):  
    # obtain loss
    loss = loss_func(yb_h, yb)
    
    # obtain performance metric
    metric_b = metrics_batch(yb,yb_h)
    
    if opt is not None:
        loss.backward()
        opt.step()
        opt.zero_grad()
  
    return loss.item(), metric_b
    
# ミニバッチごとの精度を計算
def metrics_batch(target, output):
    # obtain output class
    pred = output.argmax(dim=1, keepdim=True)
    # print(pred)
    
    # compare output class with target class
    # print(target.view_as(pred))
  
    corrects=pred.eq(target.view_as(pred)).sum().item()
    return corrects
    
# データセットの損失とメトリック値を計算
def loss_epoch(model,loss_func,dataset_dl,opt=None):
    loss=0.0
    metric=0.0
    len_data=len(dataset_dl.dataset)
    for xb, yb in dataset_dl:
        xb=xb.type(torch.float)
        
        # obtain model output
        yb_h=model(xb)
   
        loss_b, metric_b = loss_batch(loss_func, xb, yb, yb_h, opt)
        loss+=loss_b
        if metric_b is not None:
            metric += metric_b
    loss/=len_data
    metric/=len_data
    return loss, metric
    
def train_val(epochs, model, loss_func, opt, train_dl, val_dl):
    for epoch in range(epochs):
        model.train()
        train_loss, train_metric=loss_epoch(model,loss_func,train_dl,opt)
        
            
        model.eval()
        with torch.no_grad():
            val_loss, val_metric=loss_epoch(model,loss_func,val_dl)
        
        accuracy=100*val_metric
   
        print("epoch: %d, train loss: %.6f, val loss: %.6f, accuracy: %.2f" %(epoch, train_loss,val_loss,accuracy))
    
import time
t1 = time.time()
  
# call train_val function
num_epochs = 10
train_val(num_epochs, model, loss_func, opt, train_dl, val_dl)
  
t2 = time.time()
elapsed_time = t2 - t1
print(f'経過時間: {elapsed_time} [sec]')
    

Storing and loading models

# define a path2weights
path2weights = "./models/weights1.pt"
  
# store state_dict to file
torch.save(model.state_dict(), path2weights)
    
# define model; weights are randomly initiated
model2 = Net()
  
weights2 = torch.load(path2weights)
model2.load_state_dict(weight2)
    


# define a path2models
path2model = "./models/model1.pt"
  
# store model and weights into a file
torch.save(model, path2model)
    
# define model; weights are randomly initiated
model3 = Net()
  
model3 = torch.load(path2model)
    

Deploying the model

n = 100
x = x_val[n]
y = y_val[n]
plt.imshow(x.numpy()[0],cmap="gray")
plt.show()
    
# we use unsqueeze to expand dimensions to 1*C*H*W
x = x.unsqueeze(0)
  
# convert to torch.float32
x = x.type(torch.float)
    
# get model output
output = model3(x)
  
# get predicted class
pred = output.argmax(dim=1, keepdim=True)
print (pred.item(), y.item())
    

Google Colaboratory

from google.colab import drive
drive.mount('/content/drive')
    
from torch import nn
from torch.utils.data import TensorDataset
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn.functional as F
from torch import optim
import torch
import time
import os
     
class Net(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(1, 20, 5, 1)
        self.conv2 = nn.Conv2d(20, 50, 5, 1)
        self.fc1 = nn.Linear(4*4*50, 500)
        self.fc2 = nn.Linear(500, 10)
  
    def forward(self, x):
        x = F.relu(self.conv1(x))
        x = F.max_pool2d(x, 2, 2)
        x = F.relu(self.conv2(x))
        x = F.max_pool2d(x, 2, 2)
        x = x.view(-1, 4*4*50)
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        return F.log_softmax(x, dim=1)
   
def metrics_batch(target, output):
    # obtain output class
    pred = output.argmax(dim=1, keepdim=True)
    
    # compare output class with target class
    corrects=pred.eq(target.view_as(pred)).sum().item()
    return corrects
  
def loss_batch(loss_func, xb, yb,yb_h, opt=None):  
    # obtain loss
    loss = loss_func(yb_h, yb)
    
    # obtain performance metric
    metric_b = metrics_batch(yb,yb_h)
    
    if opt is not None:
        loss.backward()
        opt.step()
        opt.zero_grad()
  
    return loss.item(), metric_b
  
def loss_epoch(model, loss_func, dataset_dl, device, opt=None):
    loss=0.0
    metric=0.0
    len_data=len(dataset_dl.dataset)
    for xb, yb in dataset_dl:
        xb=xb.type(torch.float).to(device)
        
        # obtain model output
        yb_h=model(xb).to(device)
        yb=yb.to(device)
   
        loss_b,metric_b=loss_batch(loss_func, xb, yb,yb_h, opt)
        loss+=loss_b
        if metric_b is not None:
            metric+=metric_b
    loss/=len_data
    metric/=len_data
    return loss, metric
      
def train_val(epochs, model, loss_func, opt, train_dl, val_dl, device):
    for epoch in range(epochs):
        model.train()
        train_loss, train_metric=loss_epoch(model, loss_func, train_dl, device, opt)
        
            
        model.eval()
        with torch.no_grad():
            val_loss, val_metric=loss_epoch(model, loss_func, val_dl, device)
        
        accuracy=100*val_metric
   
        print(f'epoch: {epoch}, train loss: {train_loss:.6}, val loss: {val_loss:.6}, accuracy: {accuracy:.2}')
   
if __name__ == '__main__':
    model = Net()
    device = torch.device("cuda:0")
    model.to(device)
   
    # path to store data and/or load from
    path2data = '/content/drive/MyDrive/data'
    if os.path.exists(path2data) == False:
      os.makedirs(path2data)
   
    # loading MNIST training dataset
    train_data=datasets.MNIST(path2data, train=True, download=True)
   
    # extract data and targets
    x_train, y_train = train_data.data, train_data.targets
    if len(x_train.shape) == 3:
        x_train = x_train.unsqueeze(1)
    
    # loading validation data
    val_data = datasets.MNIST(path2data, train=False, download=True)
   
    # extract data and targets
    x_val, y_val = val_data.data, val_data.targets
    if len(x_val.shape) == 3:
        x_val = x_val.unsqueeze(1)
   
    # wrap tensors into a dataset
    train_ds = TensorDataset(x_train, y_train)
    val_ds = TensorDataset(x_val, y_val)
    
    # create a data loader from dataset
    train_dl = DataLoader(train_ds, batch_size=8)
    val_dl = DataLoader(val_ds, batch_size=8)
   
    loss_func = nn.NLLLoss(reduction="sum")
    opt = optim.Adam(model.parameters(), lr=1e-4)
   
    t1 = time.time()
  
    num_epochs=10
    train_val(num_epochs, model, loss_func, opt, train_dl, val_dl, device)
   
    t2 = time.time()
    elapsed_time = t2-t1
    print(f'経過時間: {elapsed_time} [sec]')
   
    # define a path2model
    path2model="/content/drive/MyDrive/model.pt"
   
    # store model and weights into a file
    torch.save(model, path2model)
    


import matplotlib.pyplot as plt
  
n = 100
x = x_val[n]
y = y_val[n]
plt.imshow(x.numpy()[0],cmap="gray")
plt.show()
    
  
# we use unsqueeze to expand dimensions to 1*C*H*W
x = x.unsqueeze(0)
  
# convert to torch.float32
x = x.type(torch.float).to(device)
  
# get model output
output = model(x)
  
# get predicted class
pred = output.argmax(dim=1, keepdim=True)
print(pred.item(), y.item())