山内セミナーⅠ(2020/08/05)work

Building models

Defining a linear layer

test10.py
from torch import nn
import torch
   
# input tensor dimension 64*1000
input_tensor = torch.randn(64, 1000)
    
# linear layer with 1000 inputs and 100 outputs
linear_layer = nn.Linear(1000, 100)
    
# output of the linear layer
output = linear_layer(input_tensor)
print(output.size())
    

Defining models using nn.Sequential

test11.py
from torch import nn
   
# define a two-layer model
model = nn.Sequential(nn.Linear(4, 5), nn.ReLU(), nn.Linear(5, 1),)
print(model)
    

Defining models using nn.Module

test12.py
import torch.nn.functional as F
from torch import nn
   
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__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()
print(model)
    

Moving the model to a CUDA device

test13.py
import torch.nn.functional as F
from torch import nn
   
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__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()
print(next(model.parameters()).device)
    

test14.py
import torch.nn.functional as F
from torch import nn
import torch
   
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__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()
if torch.cuda.is_available() == True:
    device = torch.device("cuda:0")
    model.to(device)
    print(next(model.parameters()).device)
else:
    print('GPUが有効ではないです!')
    

Printing the model summary

test15.py
import torch.nn.functional as F
from torch import nn
import torch
from torchsummary import summary
   
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__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()
summary(model, input_size=(1, 28, 28))
    

Defining the loss function and optimizer

Defining the loss function

test16.py
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
    

Training and evaluation

test17.py(GPUなし)
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
   
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,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))
   
if __name__ == '__main__':
    t1 = time.time()
   
    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")
    opt = optim.Adam(model.parameters(), lr=1e-4)
   
    num_epochs=5
    train_val(num_epochs, model, loss_func, opt, train_dl, val_dl)
   
    t2 = time.time()
    elapsed_time = t2-t1
    print('経過時間:{0} [sec]'.format(elapsed_time))
    

GPUあり
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
   
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)
        yb=yb.to(device)
        
        # 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, 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("epoch: %d, train loss: %.6f, val loss: %.6f, accuracy: %.2f" %(epoch, train_loss,val_loss,accuracy))
   
if __name__ == '__main__':
    t1 = time.time()
  
    device = torch.device("cuda:0")
    model = Net()
    model.to(device)
   
    # 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")
    opt = optim.Adam(model.parameters(), lr=1e-4)
  
    num_epochs=5
    train_val(num_epochs, model, loss_func, opt, train_dl, val_dl, device)
  
    t2 = time.time()
    elapsed_time = t2-t1
    print('経過時間:{0} [sec]'.format(elapsed_time))
    

Storing and loading models

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
   
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,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))
   
if __name__ == '__main__':
    t1 = time.time()
   
    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")
    opt = optim.Adam(model.parameters(), lr=1e-4)
   
    num_epochs=10
    train_val(num_epochs, model, loss_func, opt, train_dl, val_dl)
   
    t2 = time.time()
    elapsed_time = t2-t1
    print('経過時間:{0} [sec]'.format(elapsed_time))
   
    # define a path2model
    path2model="./models/model.pt"
   
    # store model and weights into a file
    torch.save(model, path2model)
    

Deploying the model

test19.py
from torch import nn
from torchvision import datasets
import torch.nn.functional as F
import matplotlib.pyplot as plt
   
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)
   
if __name__ == '__main__':
    # define model: weights are randomly initiated
    _model = Net()
  
    path2model="./models/model.pt"
    _model=torch.load(path2model)
  
    # path to store data and/or load from
    path2data = './data'
       
    # 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)
   
    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=_model(x)
   
    # get predicted class
    pred = output.argmax(dim=1, keepdim=True)
    print (pred.item(), y.item())