선형회귀모델에 대한 PyTorch를 이용한 두가지 접근

아래와 같은 식을 회귀하는 모델을 구하는 두가지 접근을 PyTorch로 살펴본다.

    $$y=1+5a+7b$$

즉, 입력값(a, b)에 대한 출력값 y가 100개 주어지고, 이 데이터를 통해 상수항인 1과 계수 5, 7을 구하는 것이 문제다. 물론 y에는 오차가 반영되어 있다. 첫번째 접근은 다음과 같다. 손실함수는 평균최소제곱을, 역전파를 통한 최적값 수렴을 위한 기울기를 구해 반영한 학습률은 0.01을 사용했다. 아래의 코드의 경우 기울기를 구하기 위한 방법을 PyTorch의 역전파를 이용한 것이다.

import torch
from matplotlib import pyplot as plt

weight_true = torch.Tensor([1,5,7]) # y = 1 + 5a + 7b
X = torch.cat([torch.ones(100,1),torch.randn(100,2)], 1)
y = torch.mv(X, weight_true) + torch.randn(100)
weight = torch.randn(3, requires_grad=True)

lr = 0.01

losses = []

for epoch in range(1000):
    weight.grad = None

    y_pred = torch.mv(X, weight)
    loss = torch.mean((y - y_pred)**2)
    loss.backward()

    weight.data = weight.data - lr*weight.grad.data

    losses.append(loss.item())

print(weight)

plt.plot(losses)
plt.show()

두번째 접근은 다음과 같다. 앞서 직접 하나 하나 개발자가 지정했던 것들에 대한 모듈을 사용한 경우이다.

import torch
from torch import nn, optim
from matplotlib import pyplot as plt

weight_true = torch.Tensor([1,5,7]) # y = 1 + 5a + 7b
X = torch.cat([torch.ones(100,1),torch.randn(100,2)], 1)
y = torch.mv(X, weight_true) + torch.randn(100)

net = nn.Linear(in_features=3, out_features=1, bias=False)
optimizer = optim.SGD(net.parameters(), lr=0.01)
loss_fn = nn.MSELoss()

losses = []

for epoch in range(1000):
    optimizer.zero_grad()

    y_pred = net(X)
    loss = loss_fn(y_pred.view_as(y), y)
    loss.backward()

    optimizer.step()

    losses.append(loss.item())

print(net.weight)

plt.plot(losses)
plt.show()

두 경우 모두 실행하면 아래와 같은 손실값에 대한 그래프와 추론된 상수와 두계수 값이 콘솔에 출력된다.

tensor([0.9295, 4.9402, 7.0627], requires_grad=True)

함수들에 대한 그래프 시각화

선형 함수에 대한 정의와 그래프 시각화는 다음 코드와 같다.

import numpy as np
import matplotlib.pylab as plt

def identity_func(x):
    return x

x = np.arange(-10, 10, 0.01)
plt.plot(x, identity_func(x), linestyle='-', label="identity")
plt.ylim(-10, 10)
plt.legend()
plt.show() 

결과는 다음과 같다.

기울기와 y절편을 고려한 선형 함수의 정의는 다음과 같다.

import numpy as np
import matplotlib.pylab as plt
  
def linear_func(x):
    return 2 * x + 1 
 
x = np.arange(-10, 10, 0.01)
plt.plot(x, linear_func(x), linestyle='-', label="linear_func")
plt.ylim(-10, 10)
plt.legend()
plt.show() 

결과는 다음과 같다.

계단함수에 대한 정의는 다음과 같다.

import numpy as np
import matplotlib.pylab as plt
 
def binarystep_func(x):
    return (x>=0)*1
 
x = np.arange(-10, 10, 0.01)
plt.plot(x, binarystep_func(x), linestyle='-', label="binarystep_func")
plt.ylim(-5, 5)
plt.legend()
plt.show() 

결과는 다음과 같다.

로지스틱(Logistic) 또는 시그모이드(Sigmoid)라고 불리는 함수 정의는 다음과 같다.

import numpy as np
import matplotlib.pylab as plt

def softstep_func(x):
    return 1 / (1 + np.exp(-x))

x = np.arange(-10, 10, 0.01)
plt.plot(x, softstep_func(x), linestyle='-', label="softstep_func")
plt.ylim(0, 1)
plt.legend()
plt.show()     

결과는 다음과 같다.

TanH 함수 정의 다음과 같다.

import numpy as np
import matplotlib.pylab as plt
 
def tanh_func(x):
    return np.tanh(x)
 
x = np.arange(-10, 10, 0.01)
plt.plot(x, tanh_func(x), linestyle='-', label="tanh_func")
plt.ylim(-1, 1)
plt.legend()
plt.show()     

그래프는 다음과 같다.

ArcTan 함수 정의는 다음과 같다.

import numpy as np
import matplotlib.pylab as plt

def arctan_func(x):
    return np.arctan(x)
 
x = np.arange(-10, 10, 0.01)
plt.plot(x, arctan_func(x), linestyle='-', label="arctan_func")
plt.ylim(-1.5, 1.5)
plt.legend()
plt.show()     

그래프는 다음과 같다.

Soft Sign 함수는 다음과 같다.

import numpy as np
import matplotlib.pylab as plt
 
def softsign_func(x):
    return x / ( 1+ np.abs(x) )
 
x = np.arange(-10, 10, 0.01)
plt.plot(x, softsign_func(x), linestyle='-', label="softsign_func")
plt.ylim(-1, 1)
plt.legend()
plt.show()     

그래프는 다음과 같다.

ReLU(Rectified Linear Unit) 함수는 다음과 같다.

import numpy as np
import matplotlib.pylab as plt
 
def relu_func(x):
    return (x>0)*x
 
x = np.arange(-10, 10, 0.01)
plt.plot(x, relu_func(x), linestyle='-', label="relu_func")
plt.ylim(-1, 11)
plt.legend()
plt.show()     

결과는 다음과 같다.

Leaky ReLU 함수는 다음과 같다.

import numpy as np
import matplotlib.pylab as plt
 
def leakyrelu_func(x, alpha=0.1):
    return (x>=0)*x + (x<0)*alpha*x
 
x = np.arange(-10, 10, 0.01)
plt.plot(x, leakyrelu_func(x), linestyle='-', label="leakyrelu_func")
plt.ylim(-2, 11)
plt.legend()
plt.show()   

결과는 다음과 같다.

ELU(Exponential Linear Unit) 함수는 다음과 같다.

def elu_func(x, alpha=0.9):
    return (x>=0)*x + (x<0)*alpha*(np.exp(x)-1)
 
x = np.arange(-10, 10, 0.01)
plt.plot(x, elu_func(x), linestyle='-', label="elu_func")
plt.ylim(-2, 11)
plt.legend()
plt.show()    

결과는 다음과 같다.

TreLU 함수는 다음과 같다.

import numpy as np
import matplotlib.pylab as plt
 
def trelu_func(x, thres=2):
    return (x>thres)*x
 
x = np.arange(-10, 10, 0.01)
plt.plot(x, trelu_func(x), linestyle='-', label="trelu_func")
plt.ylim(-2, 11)
plt.legend()
plt.show()     

결과는 다음과 같다.

SoftPlus 함수는 다음과 같다.

import numpy as np
import matplotlib.pylab as plt
 
def softplus_func(x):
    return np.log( 1 + np.exp(x) )
 
x = np.arange(-10, 10, 0.01)
plt.plot(x, softplus_func(x), linestyle='-', label="softplus_func")
plt.ylim(-1, 11)
plt.legend()
plt.show()     

결과는 다음과 같다.

Bent identity 함수는 다음과 같다.

import numpy as np
import matplotlib.pylab as plt
 
def bentidentity_func(x):
    return (np.sqrt(x*x+1)-1)/2+x

x = np.arange(-10, 10, 0.01)
plt.plot(x, bentidentity_func(x), linestyle='-', label="bentidentity_func")
plt.ylim(-6, 11)
plt.legend()
plt.show()

결과는 다음과 같다.

Gaussian 함수는 다음과 같다.

import numpy as np
import matplotlib.pylab as plt
 
def gaussian_func(x):
    return np.exp(-x*x)
 
x = np.arange(-10, 10, 0.01)
plt.plot(x, gaussian_func(x), linestyle='-', label="gaussian_func")
plt.ylim(-0.5, 1.5)
plt.legend()
plt.show()

결과는 다음과 같다.

사람에 대한 Detection, Segmentation @A.I-TestBed

딥러닝 모델을 활용하여 어떤 이미지에서 사람의 위치를 찾아 내는 방식은 Detection과 Segmentation으로 분류할 수 있으며, Segmentation은 다시 Instance Segmentation과 Semantic Segmentation으로 나뉩니다.

Detection은 이미지에서 사람의 위치를 사각형 영역으로 잡아주는 방식이고 Segmentation은 이미지에서 사람에 해당하는 위치를 화소(Pixel)단위로 잡아줍니다. Segmentation 방식 중 Instance는 하나의 이미지에 여러명의 사람이 있다면 각 사람(각 Instance 별로)에 대해 분리해 픽셀 위치를 잡아주고, Semantic은 이미지에서 사람이라는 의미(Semantic)를 가지는 픽셀들을 잡아줍니다.

Segmentation 방식은 Detection 보다 학습과 메모리 소비가 훨씬 더 많이 소요되며, 훈련 데이터 중 레이블을 만들기가 훨씬 어렵습니다. Detection의 레이블은 사람에 해당하는 사각형 영역만을 지정하면 되지만, Segmentation의 레이블은 사람에 해당하는 픽셀을 모두 지정해줘야 하기 때문입니다.

Detection 방식의 모델은 매우 다양한데, 대표적으로 R-CNN 등이 있으며, Segmentation 방식의 모델에는 R-CNN을 통해 먼저 위치를 사각형 영역으로 잡고 다시 이 사각형 영역에 대해서 사람에 해당하는 픽셀을 잡는 Mask R-CNN이 있으며, 그냥 처음부터 이미지의 모든 픽셀에 대해 사람인지를 잡는 FCN 모델이 있습니다. Mask R-CNN 모델은 Instance Segmentation 방식이고 FCN 모델은 Semantic Segmentation 방식입니다. FCN 모델은 Semantic Segmentation 방식의 가장 기본이 되는 모델로 이 모델을 기본으로 Semantic Segmentation 방식을 더 개선한 다양한 모델이 파생되었습니다.

아래의 동영상은 머신러닝을 테스트하기 위한 TestBed 웹페이지로써 Detection과 Segmentation에 대한 기능을 보여줍니다.

참고로 위의 동영상에서 Detection과 Instance Segmentation의 결과에 대해 추론(hypothesis)값이 90% 이상으로 잡았습니다. 이 값을 좀더 내린다면 사람으로 잡지 못한 이미지의 부분에 대해서도 검출될 것입니다.