AITech 학습정리-[DAY 13] Convolutional Neural Networks
과거의 것들/AI Tech boostcamp

AITech 학습정리-[DAY 13] Convolutional Neural Networks

=========================

학습내용

[DLBasic] CNN - Convolution은 무엇인가?

 



중요한건 어떤 새로운 Neural Networks(아키텍쳐)를 봤을 때 이 네트워크의 layer 별로 몇 개의 parameter로 이루어져 있고 전체 parameter의 숫자가 몇 개인지를 항상 감을 갖고있는게 중요하다.

수를 직접 손으로 계산해보는 실습..

Stride 얼마나 dense하게 찍을지. output 크기도 그에따라 줄어들겠지.


dense layer 넘어가는 쪽 이해 안감. 찾아보고 물어봐야지..

 

1*1*channel*(원하는 차원크기) 크기의 convolution 할 때도 있는데 차원 줄여서 파라미터 수 줄이기 위해 사용한다. 1*1*channel*1 로 하면 채널 1로 줄이기 가능. e.g. bottleneck architecture

 

 

실습..

전엔 input dimension 을 정해주고 hidden layer는 하나였으나 좀 더 복잡하게 만들어서 convolution layer의 channel도 정할 수 있고(32,64,55,...) fully connected layer 도 hidden dimension 정할 수 있다(1,10,26,...). 

 

 

Convolutional Neural Network (CNN)

 
 
 
 
[-]
 
 
 
import numpy as np
import matplotlib.pyplot as plt
import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
%matplotlib inline
%config InlineBackend.figure_format='retina'
print ("PyTorch version:[%s]."%(torch.__version__))
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
print ("device:[%s]."%(device))
 
 
 
 
 
PyTorch version:[1.7.0+cu101]. device:[cuda:0].
 
 
 
 

Dataset

 
 
 
 
[-]
 
 
 
from torchvision import datasets,transforms
mnist_train = datasets.MNIST(root='./data/',train=True,transform=transforms.ToTensor(),download=True)
mnist_test = datasets.MNIST(root='./data/',train=False,transform=transforms.ToTensor(),download=True)
print ("mnist_train:\n",mnist_train,"\n")
print ("mnist_test:\n",mnist_test,"\n")
print ("Done.")
 
 
 
 
 
mnist_train: Dataset MNIST Number of datapoints: 60000 Root location: ./data/ Split: Train StandardTransform Transform: ToTensor() mnist_test: Dataset MNIST Number of datapoints: 10000 Root location: ./data/ Split: Test StandardTransform Transform: ToTensor() Done.
 
 
 
 

Data Iterator

 
 
 
 
[-]
 
 
 
BATCH_SIZE = 256
train_iter = torch.utils.data.DataLoader(mnist_train,batch_size=BATCH_SIZE,shuffle=True,num_workers=1)
test_iter = torch.utils.data.DataLoader(mnist_test,batch_size=BATCH_SIZE,shuffle=True,num_workers=1)
print ("Done.")
 
 
 
 
 
 
Done.
 
 
 
 

Define Model

 
 
 
 
[-]
 
 
 
class ConvolutionalNeuralNetworkClass(nn.Module):
    """
        Convolutional Neural Network (CNN) Class
    """
    def __init__(self,name='cnn',xdim=[1,28,28],
                 ksize=3,cdims=[32,64],hdims=[1024,128],ydim=10,
                 USE_BATCHNORM=False):
        super(ConvolutionalNeuralNetworkClass,self).__init__()
        self.name = name
        self.xdim = xdim
        self.ksize = ksize
        self.cdims = cdims
        self.hdims = hdims
        self.ydim = ydim
        self.USE_BATCHNORM = USE_BATCHNORM
 
        # Convolutional layers
        self.layers = []
        prev_cdim = self.xdim[0]
        for cdim in self.cdims: # for each hidden layer
            self.layers.append(
                nn.Conv2d(in_channels=prev_cdim, 
                          out_channels=cdim, 
                          kernel_size=self.ksize, 
                          stride=(1,1), 
                          padding = self.ksize//2)) # convlution 
            if self.USE_BATCHNORM:
                self.layers.append(nn.BatchNorm2d(cdim)) # batch-norm
            self.layers.append(nn.ReLU(True))  # activation
            self.layers.append(nn.MaxPool2d(kernel_size=(2,2), stride=(2,2))) # max-pooling 반씩 
줄어듬.
            self.layers.append(nn.Dropout2d(p=0.5))  # dropout
            prev_cdim = cdim
 
        # Dense layers
        self.layers.append(nn.Flatten())
        prev_hdim = prev_cdim*(self.xdim[1]//(2**len(self.cdims)))*(self.xdim[2]//(2**len(self.cdims)))
        for hdim in self.hdims:
            self.layers.append(nn.Linear(in_features=prev_hdim,out_features=hdim,bias=True))
            self.layers.append(nn.ReLU(True))  # activation
            prev_hdim = hdim
        # Final layer (without activation)
        self.layers.append(nn.Linear(prev_hdim,self.ydim,bias=True))
 
        # Concatenate all layers 
        self.net = nn.Sequential()
        for l_idx,layer in enumerate(self.layers):
            layer_name = "%s_%02d"%(type(layer).__name__.lower(),l_idx)
            self.net.add_module(layer_name,layer) # add_module로 하면 이름을 정할 수 있다.
        self.init_param() # initialize parameters
        
    def init_param(self):
        for m in self.modules():
            if isinstance(m,nn.Conv2d): # init conv
                nn.init.kaiming_normal_(m.weight)
                nn.init.zeros_(m.bias)
            elif isinstance(m,nn.BatchNorm2d): # init BN
                nn.init.constant_(m.weight,1)
                nn.init.constant_(m.bias,0)
            elif isinstance(m,nn.Linear): # lnit dense
                nn.init.kaiming_normal_(m.weight)
                nn.init.zeros_(m.bias)
            
    def forward(self,x):
        return self.net(x)
 
C = ConvolutionalNeuralNetworkClass(
    name='cnn',xdim=[1,28,28],ksize=3,cdims=[32,64],
    hdims=[32],ydim=10).to(device)
loss = nn.CrossEntropyLoss()
optm = optim.Adam(C.parameters(),lr=1e-3)
print ("Done.")
 
 
 
 
 
Done.
 
 
 
 

Check Parameters

 
 
 
 
[-]
 
 
 
np.set_printoptions(precision=3)
n_param = 0
for p_idx,(param_name,param) in enumerate(C.named_parameters()):
    if param.requires_grad:
        param_numpy = param.detach().cpu().numpy() # to numpy array 
        n_param += len(param_numpy.reshape(-1))
        print ("[%d] name:[%s] shape:[%s]."%(p_idx,param_name,param_numpy.shape))
        print ("    val:%s"%(param_numpy.reshape(-1)[:5]))
print ("Total number of parameters:[%s]."%(format(n_param,',d')))
 
 
 
 
 
[0] name:[net.conv2d_00.weight] shape:[(32, 1, 3, 3)]. val:[-0.191 0.231 -0.233 -0.51 0.569] [1] name:[net.conv2d_00.bias] shape:[(32,)]. val:[0. 0. 0. 0. 0.] [2] name:[net.conv2d_04.weight] shape:[(64, 32, 3, 3)]. val:[-0.224 0.097 0.033 -0.074 0.069] [3] name:[net.conv2d_04.bias] shape:[(64,)]. val:[0. 0. 0. 0. 0.] [4] name:[net.linear_09.weight] shape:[(32, 3136)]. val:[-0.01 0. -0.004 -0.014 0.036] [5] name:[net.linear_09.bias] shape:[(32,)]. val:[0. 0. 0. 0. 0.] [6] name:[net.linear_11.weight] shape:[(10, 32)]. val:[ 0.002 -0.098 0.602 -0.159 -0.134] [7] name:[net.linear_11.bias] shape:[(10,)]. val:[0. 0. 0. 0. 0.] Total number of parameters:[119,530].
 
 
 
 

Simple Forward Path of the CNN Model

 
 
 
 
[-]
 
 
 
np.set_printoptions(precision=3)
torch.set_printoptions(precision=3)
x_numpy = np.random.rand(2,1,28,28)
x_torch = torch.from_numpy(x_numpy).float().to(device)
y_torch = C.forward(x_torch) # forward path
y_numpy = y_torch.detach().cpu().numpy() # torch tensor to numpy array
print ("x_torch:\n",x_torch)
print ("y_torch:\n",y_torch)
print ("\nx_numpy %s:\n"%(x_numpy.shape,),x_numpy)
print ("y_numpy %s:\n"%(y_numpy.shape,),y_numpy)
 
 
 
 
 
x_torch: tensor([[[[0.832, 0.092, 0.883, ..., 0.518, 0.857, 0.329], [0.507, 0.042, 0.117, ..., 0.556, 0.129, 0.265], [0.174, 0.292, 0.475, ..., 0.829, 0.979, 0.218], ..., [0.282, 0.411, 0.070, ..., 0.920, 0.611, 0.670], [0.761, 0.811, 0.610, ..., 0.129, 0.965, 0.678], [0.597, 0.974, 0.725, ..., 0.823, 0.549, 0.100]]], [[[0.411, 0.552, 0.258, ..., 0.474, 0.562, 0.701], [0.209, 0.785, 0.735, ..., 0.343, 0.672, 0.141], [0.918, 0.407, 0.145, ..., 0.256, 0.780, 0.665], ..., [0.436, 0.135, 0.259, ..., 0.339, 0.478, 0.831], [0.710, 0.124, 0.351, ..., 0.419, 0.237, 0.607], [0.815, 0.562, 0.221, ..., 0.850, 0.439, 0.960]]]], device='cuda:0') y_torch: tensor([[-9.450, 1.399, -2.171, 1.377, 0.800, -2.896, -0.381, -1.442, 6.086, 1.033], [-0.622, 2.164, -3.625, 1.081, 3.955, -2.082, -0.372, 1.162, 2.020, 0.465]], device='cuda:0', grad_fn=<AddmmBackward>) x_numpy (2, 1, 28, 28): [[[[0.832 0.092 0.883 ... 0.518 0.857 0.329] [0.507 0.042 0.117 ... 0.556 0.129 0.265] [0.174 0.292 0.475 ... 0.829 0.979 0.218] ... [0.282 0.411 0.07 ... 0.92 0.611 0.67 ] [0.761 0.811 0.61 ... 0.129 0.965 0.678] [0.597 0.974 0.725 ... 0.823 0.549 0.1 ]]] [[[0.411 0.552 0.258 ... 0.474 0.562 0.701] [0.209 0.785 0.735 ... 0.343 0.672 0.141] [0.918 0.407 0.145 ... 0.256 0.78 0.665] ... [0.436 0.135 0.259 ... 0.339 0.478 0.831] [0.71 0.124 0.351 ... 0.419 0.237 0.607] [0.815 0.562 0.221 ... 0.85 0.439 0.96 ]]]] y_numpy (2, 10): [[-9.45 1.399 -2.171 1.377 0.8 -2.896 -0.381 -1.442 6.086 1.033] [-0.622 2.164 -3.625 1.081 3.955 -2.082 -0.372 1.162 2.02 0.465]]
 
 
 
 

Evaluation Function

 
 
 
 
[-]
 
 
 
def func_eval(model,data_iter,device):
    with torch.no_grad():
        n_total,n_correct = 0,0
        model.eval() # evaluate (affects DropOut and BN)
        for batch_in,batch_out in data_iter:
            y_trgt = batch_out.to(device)
            model_pred = model(batch_in.view(-1,1,28,28).to(device))
            _,y_pred = torch.max(model_pred.data,1)
            n_correct += (y_pred==y_trgt).sum().item()
            n_total += batch_in.size(0)
        val_accr = (n_correct/n_total)
        model.train() # back to train mode 
    return val_accr
print ("Done")
 
 
 
 
 
Done
 
 
 
 

Initial Evaluation

 
 
 
 
[-]
 
 
 
C.init_param() # initialize parameters
train_accr = func_eval(C,train_iter,device)
test_accr = func_eval(C,test_iter,device)
print ("train_accr:[%.3f] test_accr:[%.3f]."%(train_accr,test_accr))
 
 
 
 
 
 
train_accr:[0.102] test_accr:[0.111].
 
 
 
 

Train

 
 
 
 
[-]
 
 
 
print ("Start training.")
C.init_param() # initialize parameters
C.train() # to train mode 
EPOCHS,print_every = 10,1
for epoch in range(EPOCHS):
    loss_val_sum = 0
    for batch_in,batch_out in train_iter:
        # Forward path
        y_pred = C.forward(batch_in.view(-1,1,28,28).to(device))
        loss_out = loss(y_pred,batch_out.to(device))
        # Update
        optm.zero_grad()      # reset gradient 
        loss_out.backward()      # backpropagate
        optm.step()      # optimizer update
        loss_val_sum += loss_out
    loss_val_avg = loss_val_sum/len(train_iter)
    # Print
    if ((epoch%print_every)==0) or (epoch==(EPOCHS-1)):
        train_accr = func_eval(C,train_iter,device)
        test_accr = func_eval(C,test_iter,device)
        print ("epoch:[%d] loss:[%.3f] train_accr:[%.3f] test_accr:[%.3f]."%
               (epoch,loss_val_avg,train_accr,test_accr))
print ("Done")
 
 
 
 
 
Start training. epoch:[0] loss:[0.602] train_accr:[0.952] test_accr:[0.954]. epoch:[1] loss:[0.178] train_accr:[0.973] test_accr:[0.973]. epoch:[2] loss:[0.132] train_accr:[0.979] test_accr:[0.981]. epoch:[3] loss:[0.104] train_accr:[0.984] test_accr:[0.983]. epoch:[4] loss:[0.093] train_accr:[0.986] test_accr:[0.985]. epoch:[5] loss:[0.080] train_accr:[0.988] test_accr:[0.986]. epoch:[6] loss:[0.073] train_accr:[0.989] test_accr:[0.987]. epoch:[7] loss:[0.069] train_accr:[0.990] test_accr:[0.988]. epoch:[8] loss:[0.062] train_accr:[0.991] test_accr:[0.989]. epoch:[9] loss:[0.058] train_accr:[0.991] test_accr:[0.988]. Done
 
 
 
 

Test

 
 
 
[-]
 
 
 
n_sample = 25
sample_indices = np.random.choice(len(mnist_test.targets),n_sample,replace=False)
test_x = mnist_test.data[sample_indices]
test_y = mnist_test.targets[sample_indices]
with torch.no_grad():
    C.eval() # to evaluation mode 
    y_pred = C.forward(test_x.view(-1,1,28,28).type(torch.float).to(device)/255.)
y_pred = y_pred.argmax(axis=1)
plt.figure(figsize=(10,10))
for idx in range(n_sample):
    plt.subplot(5, 5, idx+1)
    plt.imshow(test_x[idx], cmap='gray')
    plt.axis('off')
    plt.title("Pred:%d, Label:%d"%(y_pred[idx],test_y[idx]))
plt.show()    
print ("Done")
 
 
 
 
 
Done
[0] name:[net.conv2d_00.weight] shape:[(32, 1, 3, 3)].  # 3*3*1 conv 필터가 32개
    val:[-0.191  0.231 -0.233 -0.51   0.569]
[1] name:[net.conv2d_00.bias] shape:[(32,)].
    val:[0. 0. 0. 0. 0.]
[2] name:[net.conv2d_04.weight] shape:[(64, 32, 3, 3)]. # 3*3*32 conv 필터가 64개
    val:[-0.224  0.097  0.033 -0.074  0.069]
[3] name:[net.conv2d_04.bias] shape:[(64,)].
    val:[0. 0. 0. 0. 0.]
[4] name:[net.linear_09.weight] shape:[(32, 3136)]. # 3136 입력 32 출력
    val:[-0.01   0.    -0.004 -0.014  0.036]
[5] name:[net.linear_09.bias] shape:[(32,)].
    val:[0. 0. 0. 0. 0.]
[6] name:[net.linear_11.weight] shape:[(10, 32)].
    val:[ 0.002 -0.098  0.602 -0.159 -0.134]
[7] name:[net.linear_11.bias] shape:[(10,)].
    val:[0. 0. 0. 0. 0.]
Total number of parameters:[119,530].

 

[DLBasic] Modern CNN - 1x1 convolution의 중요성

ILSVRC라는 Visual Recognition Challenge와 대회에서 수상을 했던 5개 Network 들의 주요 아이디어와 구조에 대해 배웁니다.

Network list

  • AlexNet
    • 최초로 Deep Learning을 이용하여 ILSVRC에서 수상.
  • VGGNet
  • GoogLeNet
    • Inception blocks 을 제안.
  • ResNet
    • Residual connection(Skip connection)이라는 구조를 제안.
    • h(x) = f(x) + x 의 구조
  • DenseNet
    • Resnet과 비슷한 아이디어지만 Addition이 아닌 Concatenation을 적용한 CNN.

네트워크는 깊은데 어떻게 파라미터 수가 줄어드나? 하는 테크닉

AlexNet

Key ideas  

  • Rectified Linear Unit (ReLU) activation  
  • GPI implementation (2 GPUs)  
  • Local response normalization, Overlapping pooling  
  • Data augmentation  
  • Dropout

ReLU Activation  

  • Preserves properties of linear models  
  • Easy to optimize with gradient descent  
  • Good generalization  
  • Overcome the vanishing gradient problem

 

gradient로 조정하는데 sigmoid와 tanh는 0에서 멀어질수록 gradient가 0에 가까워짐. relu는 그런게 없어서 vashing 하지 않고 잘 된다.

 

VGGNet

3*3 conv만 썼다. 왜?


Receptive field 는 입력 space를 고려하는 정도. 그러니까 3*3하면 가로3 세로3 크기만큼의 입력을 conv가 계산해서 반환해주고 5*5하면 가로5 세로5 크기만큼의 입력을 conv가 계산해서 반환해주니까 이 입력값을 보는 정도.

근데 5*5를 보는게 3*3을 두번 하는거랑 5*5를 한번하는 거랑 같은데 3*3 두번 하는게 파라미터 갯수가 더 적다.

 

GoogLeNet

중간중간에 1*1 conv 을 중간에 잘 사용하면 파라미터를 줄일 수 있다.


GoogLeNet 파라미터는 AlexNet의 1/10 도 안되는데 레이어는 3배 더 깊어짐

 

ResNet

네트워크가 커짐에 따라 overfitting은 아닌데 학습이 안되더라. 그래서 identity map (skip connection) 이란걸 추가함.

x를 출력값 f(x)에 더해준다. 궁극적으로 원하는건 이 convolution layer와 학습하고자 하는 어떤 quentity는 residual, 차이만 학습하는 거다. 왜냐면 내가 x에다가 f(x)를 더했으니까 실제로 f(x)가 학습하는거는 그 차이만 학습하길 원하는 것. 이렇게 residual을 더한게 resnet.

차원이 다를 수 있으니까 1*1 conv.

이렇게 1*1 conv 을 넣어줘서 내가 원하는 channel로 늘리거나 줄일수 있고, parameter 수도 줄일 수 있다.

 

DenseNet

정보가 섞이니까 그냥 2개를 더하지 말고 concat 해보자. 이미 channel 이 똑같으니까. 근데 채널이 2배, 4배, 8배... 로 기하급수적으로 늘어니까 중간에 한번 씩 1*1 conv로 채널을 줄여주자.

간단한 문제에서 효과가 있던적이 많다. 그래서 왠만한 문제는 ResNet 이나 DenseNet을 사용해보자.

 

Key takeaways

  • VGG: repeated 3x3 blocks
  • GoogLeNet: 1x1 convolution
  • ResNet: skip-connection
  • DenseNet: concatenation

 

[DLBasic] Computer Vision Applications

 

Semantic Segmentation

저 물체가 뭐고 화면의 어느 픽셀까지인가

convolutionalization. 그냥 dense layer 없애고 바로 결과 하자. 두개 다 결과는 똑같더라.


가장 큰 특징은 input dimension. 특히나 input의 spatial dimension 에 independent 하다. input image에 상관없이 돌아간다. output이 커지면 이거에 비례해서 뒷단의 network가 커지게 됨. 뒷단의 spatial dimension이. 왜 그러나면 convolution이 가지는 shared parameter의 성질때문에. convolution은 input image에 independent 하게 커지던 작아지던 상관없이 동일한 convolution filter가 동일하게 찍기 때문에 찍어져서 나오는 resulting spatial dimension만 같이 커지지 여전히 동작을 시킬수 있다. 그리고 그 동작이 마치 heap map과 같은 효과가 있는 것.

주의할 점은 spatial dimension이 많이 줄어들었다. 원래 100*100 이었으면 출력은 10*10 밖에 안된다. 하지만 flat layer로 단순히 분류만 할 수 있었던게 heat map처럼 나올 수 있는 가능성.

그래서 upsample을 해준다. 늘릴수 있는 방법이 여러가지.

 

Deconvolution (conv transpose)

convolution의 역. spatial dimension을 키워준다.

사실 엄밀히 하면 역으로 만들 순 없다. 그냥 역이라고 생각하면 계산이 편해짐.

padding을 많이 줘서 늘려준다.

FCN

 

 

Detection

아까랑 같지만 per pixel 이 아니라 bound로

R-CNN

r-cnn의 문제는 한 이미지당 2000개의 class들을 다 돌려줘야 함.

SPPNet 은 한번만 cnn 돌리고 boundary에 대해서만 sub로 돌리자.

Fast R_CNN. SPPNet 과 거의 동일함. 뒷단에 RoI feature vector 라는 것을 통해 neural network를 통해 bounding box regressor 과 classification을 했다.

 

Faster R-CNN

bounding box를 뽑아내는 region proposal 도 학습을 하자. 왜냐하면 bounding box 를 뽑아내는 selective search는 내가 지금 풀고싶어 하는 detection에 맞지가 않는다. 이건 그냥 임의의 방법을 동작하는 알고리즘 박스를 뽑는 동작이기 때문에. 그래서 Faster R-CNN은 bounding box를 뽑는, candidate를 뽑는 것도 network로 학습하자. Region Proposal Network + Fast R-CNN = Faster R-CNN

RPN은 이미지에서 특정 위치가 bounding box로써 의미가 있는지 없는지. 물체가 잇을 것 같다. region perpose. 미리 정해놓은 bound box의 크기 anchor boxes. 이 박스안에 있을 것 같다. 여기서 얼마나 바뀔지.

RPN은 이미지의 모든 영역을 돌아가며 찍는건데. 해당하는 영역에 이미지가 과연 물체가 들어있을지 안들어있을지를 이 kennel이 Fully Conv가 들고있게 되는것. 9개의 region size중에서 고른다. 각각의 region size 마다 bounding box를 얼마나 키우고 줄일지 위치 크기 4. 해당 박스가 쓸모가 있을지 2.

 

YOLO

아까처럼 나누고 다 통과시켜보는게 아닌 이미지 한장에 결과가 딱 나오는거라 빠르다. bounding box sampling이 따로 없다.

 

아까처럼 anchor 9개로 정한게 아니라 그냥 5개의 박스 x/y/w/h를 정해보고 그 box가 쓸모가 있는지 없는지. 동시에 이 박스 중점에 있는 물체가 어떤 클래스인지 예측. 원래라면 bounding box를 찾고 그 sub image를 따로 돌려야 했는데 얘는 두개를 동시에. 두 정보를 취합하면 box와 그게 뭔지.

그리드 크기 S*S, 채널방향으로 보면 5개. bounding box가 B개가 있고 B개의 bounding box마다 박스에 대한 property, x/y offset, w,h, 쓸지말지 confidant . + 동시에 C개의 클래스 property가 나온다.

 

 

 

 

데이터셋 수집

google image downloads

 

 

 

 

========================

퀴즈/과제

 

Convolutional Neural Network

 
 
 
 
[-]
 
 
 
import numpy as np
import torch
import os
from torch import nn, optim
from torch.nn import functional as F
from torchvision import datasets, transforms
import matplotlib.pyplot as plt
%matplotlib inline  
%config InlineBackend.figure_format='retina'
print ("PyTorch version:[%s]."%(torch.__version__))
 
# Device Configuration
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
print ("This notebook use [%s]."%(device))
 
 
 
 
 
 
PyTorch version:[1.7.0+cu101]. This notebook use [cuda:0].
 
 
 
 

Set hyper-parameter

 
 
 
 
[-]
 
 
 
EPOCHS = 20
BATCH_SIZE=16
LEARNING_RATE=0.001
 
 
 
 
 
 
 
 
 
 
 

Prepare dataset

 
 
 
 
[-]
 
 
 
# MNIST dataset
from torchvision import datasets, transforms, models
 
# TODO: Define transforms for the training data and testing data
train_transforms = transforms.Compose([transforms.RandomRotation(30),
                                       transforms.RandomResizedCrop(224),
                                       transforms.RandomHorizontalFlip(),
                                       transforms.ToTensor(),
                                       transforms.Normalize([0.485, 0.456, 0.406],
                                                            [0.229, 0.224, 0.225])])
 
test_transforms = transforms.Compose([transforms.Resize(255),
                                      transforms.CenterCrop(224),
                                      transforms.ToTensor(),
                                      transforms.Normalize([0.485, 0.456, 0.406],
                                                           [0.229, 0.224, 0.225])])
 
DATASET_PATH = "dataset"
# Pass transforms in here, then run the next cell to see how the transforms look
train_data = datasets.ImageFolder(DATASET_PATH + '/train', transform=train_transforms)
test_data = datasets.ImageFolder(DATASET_PATH + '/test', transform=test_transforms)
 
train_iter = torch.utils.data.DataLoader(train_data, batch_size=BATCH_SIZE, shuffle=True, 
num_workers=1)
test_iter = torch.utils.data.DataLoader(train_data, batch_size=BATCH_SIZE, shuffle=True, num_workers=1)
 
 
print("Preparing dataset done!")
 
 
 
 
 
 
Preparing dataset done!
 
 
 
 

Define Model

 
 
 
 
[-]
 
 
 
# our model
class Model(nn.Module):
    def __init__(self, input_size = [3, 224, 224],
                 hidden_size=[32,64], 
                 num_classes=119, init_weight="he", init_bias="zero"):
        super(Model, self).__init__()
 
        self.init_weight = init_weight
        self.init_bias = init_bias
 
        layer_list = []
        prev_channel = input_size[0]
        
        for idx in range(len(hidden_size)):
            layer_list.append(nn.Conv2d(prev_channel, hidden_size[idx], kernel_size=3, stride=1, 
padding=1))
            layer_list.append(nn.BatchNorm2d(hidden_size[idx]))
            layer_list.append(nn.ReLU(True))
            layer_list.append(nn.MaxPool2d(kernel_size=2, stride=2))
            prev_channel = hidden_size[idx]
        
        layer_list.append(nn.Flatten())
        feature_size = int(input_size[1]/ 2**len(hidden_size))
        layer_list.append(nn.Linear(feature_size*feature_size*prev_channel, 119))
        
        self.net = nn.Sequential(*layer_list)
 
        self.init_params()
 
    def init_params(self):
        
        init_weight_method = {
        "he": nn.init.kaiming_normal_, 
        "xavier": nn.init.xavier_normal_
        }
        assert self.init_weight in init_weight_method.keys(), f'Select the weight initialization 
method in {list(init_weight_method.keys())}'
        
        init_bias_method = {
            "zero": nn.init.zeros_, 
            "uniform": nn.init.uniform_
        }
        assert self.init_bias in init_bias_method.keys(), f'Select the bias initialization method in 
{list(init_bias_method.keys())}'
 
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                init_weight_method[self.init_weight](m.weight)
                init_bias_method[self.init_bias](m.bias)
            elif isinstance(m, nn.BatchNorm2d):
                nn.init.constant_(m.weight, 1)
                nn.init.constant_(m.bias, 0)
                
    def forward(self, X):
        return self.net(X)
 
 
 
 
 
 
 
 
 
 
 

Calculate Parameters

 
 
 
 
[-]
 
 
 
model = Model(hidden_size=[64,32,64]).to(device)
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=LEARNING_RATE)
 
 
 
 
 
 
 
 
 
[-]
 
 
 
total_params = 0
for param_name, param in model.named_parameters():
    if param.requires_grad:
        total_params += len(param.reshape(-1))
print(f"Number of Total Parameters: {total_params:,d}")
 
 
 
 
 
 
Number of Total Parameters: 6,010,135
 
 
 
 

Define help function

 
 
 
 
[-]
 
 
 
def test_eval(model, data_iter, batch_size):
    with torch.no_grad():
        test_loss = 0
        total = 0
        correct = 0
        model.eval()
        for batch_img, batch_lab in data_iter:
            X = batch_img.view(-1, 3, 224, 224).to(device)
            Y = batch_lab.to(device)
            y_pred = model(X)
            _, predicted = torch.max(y_pred.data, 1)
            correct += (predicted == Y).sum().item()
            total += batch_img.size(0)
        val_acc = (100 * correct / total)
        model.train()
    return val_acc
 
 
 
 
 
 
 
 
 
 

Train model

 
 
 
 
[-]
 
 
 
# Training Phase
print_every = 1
best_accuracy = 0
print("Start training !")
checkpoint_dir = "weights"
 
if os.path.exists(checkpoint_dir):
    model = torch.load( f'{checkpoint_dir}/model.pt') 
    model.load_state_dict(
        torch.load( f'{checkpoint_dir}/model_state_dict.pt')) 
    checkpoint = torch.load(f'{checkpoint_dir}/all.tar')  
#     model.load_state_dict(checkpoint['model'])
    optimizer.load_state_dict(checkpoint['optimizer'])
    
else:
    model = Model(hidden_size=[64, 32, 64]).to(device)
    criterion = nn.CrossEntropyLoss()
    optimizer = optim.Adam(model.parameters(), lr=LEARNING_RATE)
 
 
# Training loop
for epoch in range(EPOCHS):
    loss_val_sum = 0
    for batch_img, batch_lab in train_iter:
 
        X = batch_img.view(-1, 3, 224, 224).to(device)
        Y = batch_lab.to(device)
        
        # Inference & Calculate los
        y_pred = model.forward(X)
        loss = criterion(y_pred, Y)
        
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        
        loss_val_sum += loss
        
    if ((epoch%print_every)==0) or (epoch==(EPOCHS-1)):
        # accr_val = M.test(x_test, y_test, batch_size)
        loss_val_avg = loss_val_sum / len(train_iter)
        accr_val = test_eval(model, test_iter, BATCH_SIZE)
        print(f"epoch:[{epoch+1}/{EPOCHS}] cost:[{loss_val_avg:.3f}] test_accuracy:[{accr_val:.3f}]")
 
    if accr_val > best_accuracy:
        if not os.path.exists(checkpoint_dir):
            os.mkdir(checkpoint_dir)
        print(f"Model saved : acc - {accr_val}")
 
        torch.save(model, f'{checkpoint_dir}/model.pt')  
        torch.save(model.state_dict(), 
                   f'{checkpoint_dir}/model_state_dict.pt')  
        torch.save({
                'model': model.state_dict(),
                'optimizer': optimizer.state_dict()
            }, f'{checkpoint_dir}/all.tar')  
 
print("Training Done !")
 
 
 
 
 
 
 
 
 
 
 

Test model

 
 
 
 
[-]
 
 
 
test_iter = torch.utils.data.DataLoader(train_data, batch_size=BATCH_SIZE, shuffle=True, num_workers=1)
data_iter = iter(test_iter)
images, labels = next(data_iter)
 
 
 
 
 
 
 
 
 
 
[-]
 
 
 
def imshow(image, ax=None, title=None, normalize=True):
    """Imshow for Tensor."""
    if ax is None:
        fig, ax = plt.subplots()
    image = image.numpy().transpose((1, 2, 0))
 
    if normalize:
        mean = np.array([0.485, 0.456, 0.406])
        std = np.array([0.229, 0.224, 0.225])
        image = std * image + mean
        image = np.clip(image, 0, 1)
 
    ax.imshow(image)
    ax.spines['top'].set_visible(False)
    ax.spines['right'].set_visible(False)
    ax.spines['left'].set_visible(False)
    ax.spines['bottom'].set_visible(False)
    ax.tick_params(axis='both', length=0)
    ax.set_xticklabels('')
    ax.set_yticklabels('')
    ax.set_title(title)
    return ax
 
 
 
 
 
 
 
 
[-]
 
 
 
n_sample = 16
# sample_indices = np.random.choice(len(mnist_test.targets), n_sample, replace=False)
test_x = images[:n_sample]
test_y = labels[:n_sample]
 
with torch.no_grad():
    model.eval()
    y_pred = model.forward(test_x.view(-1, 3, 224, 224).type(torch.float).to(device))
    model.train()
    
y_pred = y_pred.argmax(axis=1)
 
plt.figure(figsize=(20, 20))
 
for idx in range(n_sample):
    ax = plt.subplot(4, 4, idx+1)
    title = f"Predict: {y_pred[idx]}, Label: {test_y[idx]}"
    imshow(test_x[idx], ax, title)
 
plt.show()
 
 
 
 

=========================

피어세션

crossvalildation overfitting 방지

bagging 병렬 boosting 직렬 로 생각하기도 한다.

optimizer는 경험으로 알아보는게 좋은 것 같다.

label smoothing 신기해서 써보고 싶다.

 

cost = bias^2 + variance + noise 가 틀릴수도 있다는 요새 말.

노이즈가 끼면 잘 학습되는걸 어떻게 생각해야할지 모르겠음.

CNN 미분이 간단히 된게 신기했다.

 

data augmentation 이 공감된다. 실제로 많이 쓰인다.

noise robustness. 노이즈 표현 효과. 이 구현을 어떻게 하는지 대충 감 잡힘. 공감.

label smoothing. cutout cutmix. 알아서 좋았다.

CNN 완전히 처음 봐서 신기함. 활성함수가 1이 될수도 있나? 가중치 크기가 고정이 되서 결과값을 낸다는 것을 이해함. 이런 연산이 어디에도 똑같이 적용된다. 채널이 다르다면 쪼개서라도 같게 하더라. 근데 배수가 아니라면 어떻게 쪼갤까.. 이 생각은 틀리고 입력채널과 conv채널은 무조건 같아야 됨.

backpropagation.

 

early stopping. 얘보다 작은애가 나오면 멈추겠다. 기준을 정하더라.

 

델타는 끝에서 온거

 

CNN 에 대한거

https://untitledtblog.tistory.com/150

 

colab은 linux ubuntu 였고 공유파일이라도 colab ipynb랑 구글드라이브에 연결할 수 있고.

 

bts 뷔,bts 슈가,bts 제이홉,bts 정국,bts 정국,bts 진,bts 지민, bts RM

 

===============================

후기

시간이 슬슬 없어진다.

이렇게 자기전에 남은 시간을 환경구축이나 다른거 쉬엄쉬엄 하면서도 써야 할것 같다.