강의영상

- (1/5) 회귀모형 소개, 손실 함수

- (2/5) 경사하강법, 경사하강법을 이용하여 회귀계수 1회 업데이트

- (3/5) 회귀계수 반복 업데이트

- (4/5) 학습률

- (5/5) 사과영상

import

import torch 
import numpy as np 
import matplotlib.pyplot as plt 

로드맵

- 회귀분석 $\to$ 로지스틱 $\to$ 심층신경망(DNN) $\to$ 합성곱신경망(CNN)

Data

- model: $y_i= w_0+w_1 x_i +\epsilon_i = 2.5 + 4x_i +\epsilon_i, \quad i=1,2,\dots,n$

- model: ${\bf y}={\bf X}{\bf W} +\boldsymbol{\epsilon}$

  • ${\bf y}=\begin{bmatrix} y_1 \\ y_2 \\ \dots \\ y_n\end{bmatrix}, \quad {\bf X}=\begin{bmatrix} 1 & x_1 \\ 1 & x_2 \\ \dots \\ 1 & x_n\end{bmatrix}, \quad {\bf W}=\begin{bmatrix} 2.5 \\ 4 \end{bmatrix}, \quad \boldsymbol{\epsilon}= \begin{bmatrix} \epsilon_1 \\ \dots \\ \epsilon_n\end{bmatrix}$
torch.manual_seed(43052)
n=100
ones= torch.ones(n)
x,_ = torch.randn(n).sort()
X = torch.vstack([ones,x]).T
W = torch.tensor([2.5,4])
ϵ = torch.randn(n)*0.5
y = X@W + ϵ
ytrue = X@W
plt.plot(x,y,'o')
plt.plot(x,ytrue,'--')
[<matplotlib.lines.Line2D at 0x7f259112c0d0>]

학습이란?

- 파란점만 주어졌을때, 주황색 점선을 추론하는것. 좀 더 정확하게 말하면 given data로 $\begin{bmatrix} \hat{w}_0 \\ \hat{w}_1 \end{bmatrix}$를 최대한 $\begin{bmatrix} 2.5 \\ 4 \end{bmatrix}$와 비슷하게 찾는것.

  • given data : $\big\{(x_i,y_i) \big\}_{i=1}^{n}$

  • parameter: ${\bf W}=\begin{bmatrix} w_0 \\ w_1 \end{bmatrix}$

  • estimated parameter: ${\bf \hat{W}}=\begin{bmatrix} \hat{w}_0 \\ \hat{w}_1 \end{bmatrix}$

- 더 쉽게 말하면 아래의 그림을 보고 적당한 추세선을 찾는것이다.

plt.plot(x,y,'o')
[<matplotlib.lines.Line2D at 0x7f2591013f40>]

- 시도: $(\hat{w}_0,\hat{w}_1)=(-5,10)$을 선택하여 선을 그려보고 적당한지 판단.

  • $\hat{y}_i=-5 +10 x_i$ 와 같이 $y_i$의 값을 적합시키겠다는 의미
plt.plot(x,y,'o')
plt.plot(x,-5+10*x,'--')
[<matplotlib.lines.Line2D at 0x7f2590ff7cd0>]

- 벡터표현으로 주황색점선을 계산

What=torch.tensor([-5.0,10.0])
plt.plot(x,y,'o')
plt.plot(x,X@What,'--')
[<matplotlib.lines.Line2D at 0x7f2590f69730>]

파라메터를 학습하는 방법 (적당한 선으로 업데이트 하는 방법)

- 이론적으로 추론 <- 회귀분석시간에 배운것

- 컴퓨터의 반복계산을 이용하여 추론 (경사하강법) <- 우리가 오늘 파이토치로 실습해볼 내용.

(1) initial value: 임의의 선을 일단 그어본다.

What= torch.tensor([-5.0,10.0],requires_grad=True)
What
tensor([-5., 10.], requires_grad=True)
  • 처음에는 ${\bf \hat{W}}=\begin{bmatrix} \hat{w}_0 \\ \hat{w}_1 \end{bmatrix}=\begin{bmatrix} -5 \\ 10 \end{bmatrix} $ 를 대입해서 주황색 점선을 적당히 그려보자는 의미

  • 끝에 requires_grad=True는 나중에 미분을 위한 것

yhat=X@What
yhat
tensor([-29.8211, -28.6215, -24.9730, -21.2394, -19.7919, -19.6354, -19.5093,
        -19.4352, -18.7223, -18.0793, -16.9040, -16.0918, -16.0536, -15.8746,
        -14.4690, -14.3193, -13.6426, -12.8578, -12.5486, -12.4213, -11.9484,
        -11.1034, -10.8296, -10.6210, -10.5064, -10.0578,  -9.8063,  -9.7380,
         -9.7097,  -9.6756,  -8.8736,  -8.7195,  -8.6880,  -8.1592,  -7.7752,
         -7.7716,  -7.7339,  -7.7208,  -7.6677,  -7.1551,  -7.0004,  -6.8163,
         -6.7081,  -6.5655,  -6.4480,  -6.3612,  -6.0566,  -5.6031,  -5.5589,
         -5.2137,  -4.3446,  -4.3165,  -3.8047,  -3.5801,  -3.4793,  -3.4325,
         -2.3545,  -2.3440,  -1.8434,  -1.7799,  -1.5386,  -1.0161,  -0.8103,
          0.4426,   0.5794,   0.9125,   1.1483,   1.4687,   1.4690,   1.5234,
          1.6738,   2.0592,   2.1414,   2.8221,   3.1536,   3.6682,   4.2907,
          4.8037,   4.8531,   4.9414,   5.3757,   5.3926,   5.6973,   6.0239,
          6.1261,   6.5317,   7.2891,   8.4032,   8.4936,   9.2794,   9.9943,
         10.0310,  10.4369,  11.7886,  15.8323,  17.4440,  18.9350,  21.0560,
         21.0566,  21.6324], grad_fn=<MvBackward>)
plt.plot(x,y,'o')
plt.plot(x,yhat.data,'--')
[<matplotlib.lines.Line2D at 0x7f2590ecd910>]

(2) 첫번째 수정: 적당한 선의 '적당한 정도'를 판단하고 더 적당한 선으로 업데이트 한다.

- '적당한 정도'를 판단하기 위한 장치: loss function 도입!

$loss=\sum_{i=1}^{n}(y_i-\hat{y}_i)^2=\sum_{i=1}^{n}(y_i-(\hat{w}_0+\hat{w}_1x_i))^2$

$=({\bf y}-{\bf\hat{y}})^\top({\bf y}-{\bf\hat{y}})=({\bf y}-{\bf X}{\bf \hat{W}})^\top({\bf y}-{\bf X}{\bf \hat{W}})$

- loss 함수의 특징

  • $y_i \approx \hat{y}_i$ 일수록 loss값이 작다.
  • $y_i \approx \hat{y}_i$ 이 되도록 $(\hat{w}_0,\hat{w}_1)$을 잘 찍으면 loss값이 작다.
  • (중요) 주황색 점선이 '적당할 수록' loss값이 작다.
loss=torch.sum((y-yhat)**2) 
loss
tensor(8587.6875, grad_fn=<SumBackward0>)

- 우리의 목표: 이 loss(=8587.6875)을 더 줄이자. $\to$ 아예 모든 조합 $(\hat{w}_0,\hat{w}_1)$에 대하여 가장 작은 loss를 찾으면 좋겠다.

- 문제의 치환: 생각해보니까 우리의 문제는 아래와 같이 수학적으로 단순화 되었다.

  • 적당해보이는 주황색 선을 찾자 $\to$ $loss(w_0,w_1)$를 최소로하는 $(w_0,w_1)$의 값을 찾자.

- 수정된 목표: $loss(w_0,w_1)$를 최소로 하는 $(w_0,w_1)$을 구하라.

  • 단순한 수학문제가 되었다. 마치 $loss(w)=w^2-2w+3$ 을 최소화하는 $w$를 찾으라는 것과 같음.

- 우리의 무기: 경사하강법, 벡터미분


($\ast$) 잠시 경사하강법을 리뷰하자.

경사하강법 아이디어 (1차원)

(step 1) 임의의 점을 찍는다.

(step 2) 그 점에서 순간기울기를 구한다. (접선) <-- 미분

(step 3) 순간기울기(=미분계수)의 부호를 살펴보고 부호와 반대방향으로 움직인다. (순간기울기와 같은 방향으로 움직이면 점점 커질테니까)

(팁) 기울기의 절대값 크기와 비례하여 보폭(=움직이는 정도)을 조절한다.

경사하강법 아이디어 (2차원)

- 경사하강법 아이디어 (1차원)

(step 1) 임의의 점을 찍는다.

(step 2) 그 점에서 순간기울기를 구한다. (접평면) <-- 편미분

(step 3) 순간기울기(=미분계수)의 부호를 살펴보고 부호와 반대방향으로 각각 움직인다. (순간기울기와 같은 방향으로 움직이면 점점 커질테니까)

(팁) 기울기의 절대값 크기와 비례하여 보폭(=움직이는 정도)을 각각 조절한다.

loss를 줄이도록 ${\bf W}$를 개선하는 방법

- $수정값 \leftarrow 원래값 - 기울어진크기(=미분계수) \times \alpha $

  • 여기에서 $\alpha$는 전체적인 보폭의 크기를 결정한다. 즉 $\alpha$값이 클수록 한번의 update에 움직이는 양이 크다.

- ${\bf W} \leftarrow {\bf W} - \alpha \times \frac{\partial}{\partial {\bf W}}loss(w_0,w_1)$

  • 마이너스의 의미: 기울기의 부호를 보고 반대방향으로 움직여라.

  • $\frac{\partial}{\partial {\bf W}}loss(w_0,w_1):$ 기울기의 절대값 크기와 비례하여 움직이는 정도를 조정하라.

  • $\alpha$의 의미: 전체적인 보폭의 속도를 조절, $\alpha$가 크면 전체적으로 빠르게 움직인다. 다리의 길이로 비유할 수 있다.


- 우리의 목표: loss=8587.6875 인데, 이걸 줄이는 것이 목표라고 했었음. 이것을 줄이는 방법이 경사하강법이다.

- 경사하강법으로 loss를 줄이기 위해서는 $\frac{\partial}{\partial {\bf W}}loss(w_0,w_1)$의 계산이 필요한데, 이를 위해서 벡터미분이 필요하다.

loss.backward() 
  • 미분해라! 뭘로? requires_grad=True를 가진 텐서로!!
    loss=torch.sum((y-yhat)**2)= torch.sum((y-X@What)**2)
    # 이었고 
    What=torch.tensor([-5.0,10.0],requires_grad=True)
    # 이므로 결국 What으로 미분하라는 의미. 
    # 미분한 식이 나오는 것이 아니고, 
    # 그 식에 (-5.0, 10.0)을 대입한 계수값이 계산됨.
    
  • 정확하게 말하면 미분을 활용하여 $(-5,10)$에서의 순간기울기를 구했다는 의미임.
What.grad.data
tensor([-1342.2523,  1188.9307])
  • 이것이 의미하는건 $(-5,10)$에서의 순간기울기가 $(-1342.2523, 1188.9307)$ 이라는 의미

- 잘계산한것이 맞는가? 손계산으로 검증하여 보자.

  • $loss(w_0,w_1)=(y-\hat{y})^\top (y-\hat{y})=(y-XW)^\top (y-XW)$

  • $\frac{\partial}{\partial W}loss(w_0,w_1)=-2X^\top y+2X^\top X W$

- 2 * X.T @ y + 2 * X.T @ X @ What
tensor([-1342.2522,  1188.9305], grad_fn=<AddBackward0>)
alpha=0.001 
print('수정전: ' + str(What.data))
print('수정하는폭: ' +str(-alpha * What.grad.data))
print('수정후: ' +str(What.data-alpha * What.grad.data))
print('*참값: (2.5,4)' )
수정전: tensor([-5., 10.])
수정하는폭: tensor([ 1.3423, -1.1889])
수정후: tensor([-3.6577,  8.8111])
*참값: (2.5,4)
Wbefore = What.data
Wafter = What.data-alpha * What.grad.data 
Wbefore, Wafter
(tensor([-5., 10.]), tensor([-3.6577,  8.8111]))
plt.plot(x,y,'o')
plt.plot(x,X@Wbefore,'--',color='b') #수정전: 파란점선
plt.plot(x,X@Wafter,'--',color='r') #수정후: 빨간점선
plt.title("before: blue // after: red")
Text(0.5, 1.0, 'before: blue // after: red')

(3) Learn (=estimate $\bf\hat{W})$:

What= torch.tensor([-5.0,10.0],requires_grad=True)
alpha=0.001 
for epoc in range(30): 
    What.grad=None
    yhat=X@What 
    loss=torch.sum((y-yhat)**2)
    loss.backward() 
    What.data = What.data-alpha * What.grad.data 
What.data ## true: (2.5,4) 
tensor([2.4290, 4.0144])
plt.plot(x,y,'o')
plt.plot(x,(X@What.data),'--')
[<matplotlib.lines.Line2D at 0x7f25887040a0>]

파라메터의 수정과정을 관찰할 수 없을까? (학습과정 모니터링)

- 기록을 해보자.

losses = [] # 기록하고 싶은것 1  
yhats = [] # 기록하고 싶은것 2 
Whats = [] # 기록하고 싶은것 3 
What= torch.tensor([-5.0,10.0],requires_grad=True)
alpha=0.001 
for epoc in range(30): 
    Whats=Whats+[What.data.tolist()] 
    What.grad=None
    yhat=X@What 
    yhats=yhats+[yhat.data.tolist()]
    loss=torch.sum((y-yhat)**2)
    losses = losses + [loss.item()]
    loss.backward() 
    What.data = What.data-alpha * What.grad.data 

- $\hat{y}$ 관찰

plt.plot(x,y,'o')
plt.plot(x,yhats[3],'--')
[<matplotlib.lines.Line2D at 0x7f258867d6d0>]
plt.plot(x,y,'o')
plt.plot(x,yhats[10],'--')
[<matplotlib.lines.Line2D at 0x7f25885eb490>]
plt.plot(x,y,'o')
plt.plot(x,yhats[15],'--')
[<matplotlib.lines.Line2D at 0x7f25885ce730>]

- $\hat{\bf W}$

Whats
[[-5.0, 10.0],
 [-3.657747745513916, 8.81106948852539],
 [-2.554811716079712, 7.861191749572754],
 [-1.649186372756958, 7.101552963256836],
 [-0.9060714244842529, 6.49347448348999],
 [-0.29667866230010986, 6.006272315979004],
 [0.2027742564678192, 5.615575313568115],
 [0.6119104623794556, 5.302003383636475],
 [0.9469034671783447, 5.050129413604736],
 [1.2210699319839478, 4.847657680511475],
 [1.4453645944595337, 4.684779167175293],
 [1.6287915706634521, 4.553659439086914],
 [1.778746247291565, 4.448036193847656],
 [1.90129816532135, 4.3628973960876465],
 [2.0014259815216064, 4.294229507446289],
 [2.0832109451293945, 4.238814353942871],
 [2.149996757507324, 4.194070339202881],
 [2.204521894454956, 4.157923698425293],
 [2.249027729034424, 4.128708839416504],
 [2.285348415374756, 4.105085849761963],
 [2.31498384475708, 4.0859761238098145],
 [2.339160442352295, 4.070511341094971],
 [2.3588807582855225, 4.057991027832031],
 [2.3749637603759766, 4.0478515625],
 [2.3880786895751953, 4.039637088775635],
 [2.3987717628479004, 4.032979965209961],
 [2.40748929977417, 4.027583599090576],
 [2.414595603942871, 4.023208141326904],
 [2.4203879833221436, 4.019659042358398],
 [2.4251089096069336, 4.016779899597168]]
plt.plot(losses)
[<matplotlib.lines.Line2D at 0x7f25885296d0>]

Animation

plt.rcParams['figure.figsize'] = (10,4)
plt.rcParams["animation.html"] = "jshtml" 
from matplotlib import animation

fig = plt.figure()
ax1 = fig.add_subplot(1, 2, 1)
ax2 = fig.add_subplot(1, 2, 2, projection='3d')

## ax1: 왼쪽그림 
ax1.plot(x,y,'o')
line, = ax1.plot(x,yhats[0]) 
## ax2: 오른쪽그림 
_w0 = np.arange(-6, 11, 0.5) ## 파란색곡면을 그리는 코드 (시작) 
_w1 = np.arange(-6, 11, 0.5)
w1,w0 = np.meshgrid(_w1,_w0)
l=w0*0
for i in range(len(_w0)):
    for j in range(len(_w1)):
        l[i,j]=torch.sum((y-_w0[i]-_w1[j]*x)**2)
ax2.plot_surface(w0, w1, l, rstride=1, cstride=1, color='b',alpha=0.35) ## 파란색곡면을 그리는 코드(끝) 
ax2.scatter(2.5,4,torch.sum((y-2.5-4*x)**2),s=200,color='red',marker='*') ## 최소점을 표시하는 코드 (붉은색 별) 
ax2.scatter(np.array(Whats)[0,0],np.array(Whats)[0,1],losses[0],color='b') ## 업데이트되는 What을 표시하는 점 (파란색 동그라미) 
ax2.azim = 40  ## 3d plot의 view 조절 
ax2.dist = 8   ## 3d plot의 view 조절 
ax2.elev = 5   ## 3d plot의 view 조절 

def animate(epoc):
    line.set_ydata(yhats[epoc])
    ax2.scatter(np.array(Whats)[epoc,0],np.array(Whats)[epoc,1],losses[epoc],color='grey')
    return line

ani = animation.FuncAnimation(fig, animate, frames=30)
plt.close()
ani
</input>

$\alpha$에 대하여 ($\alpha$는 학습률)

(1) $\alpha$가 너무 작다면? $\to$ 비효율적이다.

losses = [] # 기록하고 싶은것 1  
yhats = [] # 기록하고 싶은것 2 
Whats = [] # 기록하고 싶은것 3 
alpha=0.0001 

What= torch.tensor([-5.0,10.0],requires_grad=True)
for epoc in range(30): 
    Whats=Whats+[What.data.tolist()] 
    What.grad=None
    yhat=X@What 
    yhats=yhats+[yhat.data.tolist()]
    loss=torch.sum((y-yhat)**2)
    losses = losses + [loss.item()]
    loss.backward() 
    What.data = What.data-alpha * What.grad.data 
fig = plt.figure()
ax1 = fig.add_subplot(1, 2, 1)
ax2 = fig.add_subplot(1, 2, 2, projection='3d')

## ax1: 왼쪽그림 
ax1.plot(x,y,'o')
line, = ax1.plot(x,yhats[0]) 
## ax2: 오른쪽그림 
_w0 = np.arange(-6, 11, 0.5) ## 파란색곡면을 그리는 코드 (시작) 
_w1 = np.arange(-6, 11, 0.5)
w1,w0 = np.meshgrid(_w1,_w0)
l=w0*0
for i in range(len(_w0)):
    for j in range(len(_w1)):
        l[i,j]=torch.sum((y-_w0[i]-_w1[j]*x)**2)
ax2.plot_surface(w0, w1, l, rstride=1, cstride=1, color='b',alpha=0.35) ## 파란색곡면을 그리는 코드(끝) 
ax2.scatter(2.5,4,torch.sum((y-2.5-4*x)**2),s=200,color='red',marker='*') ## 최소점을 표시하는 코드 (붉은색 별) 
ax2.scatter(np.array(Whats)[0,0],np.array(Whats)[0,1],losses[0],color='b') ## 업데이트되는 What을 표시하는 점 (파란색 동그라미) 
ax2.azim = 40  ## 3d plot의 view 조절 
ax2.dist = 8   ## 3d plot의 view 조절 
ax2.elev = 5   ## 3d plot의 view 조절 

def animate(epoc):
    line.set_ydata(yhats[epoc])
    ax2.scatter(np.array(Whats)[epoc,0],np.array(Whats)[epoc,1],losses[epoc],color='grey')
    return line

ani = animation.FuncAnimation(fig, animate, frames=30)
plt.close()
ani
</input>

(2) $\alpha$가 크다면? $\to$ 다른의미에서 비효율적이다 + 위험하다..

losses = [] # 기록하고 싶은것 1  
yhats = [] # 기록하고 싶은것 2 
Whats = [] # 기록하고 싶은것 3 
alpha=0.0083  

What= torch.tensor([-5.0,10.0],requires_grad=True)
for epoc in range(30): 
    Whats=Whats+[What.data.tolist()] 
    What.grad=None
    yhat=X@What 
    yhats=yhats+[yhat.data.tolist()]
    loss=torch.sum((y-yhat)**2)
    losses = losses + [loss.item()]
    loss.backward() 
    What.data = What.data-alpha * What.grad.data 
fig = plt.figure()
ax1 = fig.add_subplot(1, 2, 1)
ax2 = fig.add_subplot(1, 2, 2, projection='3d')

## ax1: 왼쪽그림 
ax1.plot(x,y,'o')
line, = ax1.plot(x,yhats[0]) 
## ax2: 오른쪽그림 
_w0 = np.arange(-6, 11, 0.5) ## 파란색곡면을 그리는 코드 (시작) 
_w1 = np.arange(-6, 11, 0.5)
w1,w0 = np.meshgrid(_w1,_w0)
l=w0*0
for i in range(len(_w0)):
    for j in range(len(_w1)):
        l[i,j]=torch.sum((y-_w0[i]-_w1[j]*x)**2)
ax2.plot_surface(w0, w1, l, rstride=1, cstride=1, color='b',alpha=0.35) ## 파란색곡면을 그리는 코드(끝) 
ax2.scatter(2.5,4,torch.sum((y-2.5-4*x)**2),s=200,color='red',marker='*') ## 최소점을 표시하는 코드 (붉은색 별) 
ax2.scatter(np.array(Whats)[0,0],np.array(Whats)[0,1],losses[0],color='b') ## 업데이트되는 What을 표시하는 점 (파란색 동그라미) 
ax2.azim = 40  ## 3d plot의 view 조절 
ax2.dist = 8   ## 3d plot의 view 조절 
ax2.elev = 5   ## 3d plot의 view 조절 

def animate(epoc):
    line.set_ydata(yhats[epoc])
    ax2.scatter(np.array(Whats)[epoc,0],np.array(Whats)[epoc,1],losses[epoc],color='grey')
    return line

ani = animation.FuncAnimation(fig, animate, frames=30)
plt.close()
ani
</input>

(3) $\alpha=0.0085$

losses = [] # 기록하고 싶은것 1  
yhats = [] # 기록하고 싶은것 2 
Whats = [] # 기록하고 싶은것 3 
alpha=0.0085 

What= torch.tensor([-5.0,10.0],requires_grad=True)
for epoc in range(30): 
    Whats=Whats+[What.data.tolist()] 
    What.grad=None
    yhat=X@What 
    yhats=yhats+[yhat.data.tolist()]
    loss=torch.sum((y-yhat)**2)
    losses = losses + [loss.item()]
    loss.backward() 
    What.data = What.data-alpha * What.grad.data 
fig = plt.figure()
ax1 = fig.add_subplot(1, 2, 1)
ax2 = fig.add_subplot(1, 2, 2, projection='3d')

## ax1: 왼쪽그림 
ax1.plot(x,y,'o')
line, = ax1.plot(x,yhats[0]) 
## ax2: 오른쪽그림 
_w0 = np.arange(-6, 11, 0.5) ## 파란색곡면을 그리는 코드 (시작) 
_w1 = np.arange(-6, 11, 0.5)
w1,w0 = np.meshgrid(_w1,_w0)
l=w0*0
for i in range(len(_w0)):
    for j in range(len(_w1)):
        l[i,j]=torch.sum((y-_w0[i]-_w1[j]*x)**2)
ax2.plot_surface(w0, w1, l, rstride=1, cstride=1, color='b',alpha=0.35) ## 파란색곡면을 그리는 코드(끝) 
ax2.scatter(2.5,4,torch.sum((y-2.5-4*x)**2),s=200,color='red',marker='*') ## 최소점을 표시하는 코드 (붉은색 별) 
ax2.scatter(np.array(Whats)[0,0],np.array(Whats)[0,1],losses[0],color='b') ## 업데이트되는 What을 표시하는 점 (파란색 동그라미) 
ax2.azim = 40  ## 3d plot의 view 조절 
ax2.dist = 8   ## 3d plot의 view 조절 
ax2.elev = 5   ## 3d plot의 view 조절 

def animate(epoc):
    line.set_ydata(yhats[epoc])
    ax2.scatter(np.array(Whats)[epoc,0],np.array(Whats)[epoc,1],losses[epoc],color='grey')
    return line

ani = animation.FuncAnimation(fig, animate, frames=30)
plt.close()
ani
</input>

(4) $\alpha=0.01$

losses = [] # 기록하고 싶은것 1  
yhats = [] # 기록하고 싶은것 2 
Whats = [] # 기록하고 싶은것 3 
alpha=0.01

What= torch.tensor([-5.0,10.0],requires_grad=True)
for epoc in range(30): 
    Whats=Whats+[What.data.tolist()] 
    What.grad=None
    yhat=X@What 
    yhats=yhats+[yhat.data.tolist()]
    loss=torch.sum((y-yhat)**2)
    losses = losses + [loss.item()]
    loss.backward() 
    What.data = What.data-alpha * What.grad.data 
fig = plt.figure()
ax1 = fig.add_subplot(1, 2, 1)
ax2 = fig.add_subplot(1, 2, 2, projection='3d')

## ax1: 왼쪽그림 
ax1.plot(x,y,'o')
line, = ax1.plot(x,yhats[0]) 
## ax2: 오른쪽그림 
_w0 = np.arange(-6, 11, 0.5) ## 파란색곡면을 그리는 코드 (시작) 
_w1 = np.arange(-6, 11, 0.5)
w1,w0 = np.meshgrid(_w1,_w0)
l=w0*0
for i in range(len(_w0)):
    for j in range(len(_w1)):
        l[i,j]=torch.sum((y-_w0[i]-_w1[j]*x)**2)
ax2.plot_surface(w0, w1, l, rstride=1, cstride=1, color='b',alpha=0.35) ## 파란색곡면을 그리는 코드(끝) 
ax2.scatter(2.5,4,torch.sum((y-2.5-4*x)**2),s=200,color='red',marker='*') ## 최소점을 표시하는 코드 (붉은색 별) 
ax2.scatter(np.array(Whats)[0,0],np.array(Whats)[0,1],losses[0],color='b') ## 업데이트되는 What을 표시하는 점 (파란색 동그라미) 
ax2.azim = 40  ## 3d plot의 view 조절 
ax2.dist = 8   ## 3d plot의 view 조절 
ax2.elev = 5   ## 3d plot의 view 조절 

def animate(epoc):
    line.set_ydata(yhats[epoc])
    ax2.scatter(np.array(Whats)[epoc,0],np.array(Whats)[epoc,1],losses[epoc],color='grey')
    return line

ani = animation.FuncAnimation(fig, animate, frames=30)
plt.close()
ani
</input>

- 학습률($\alpha$)를 조정하며 실습해보고 스크린샷 제출

다루기 싫지만 해야하는 사소한 문제들

(A1) 손실함수

- $\sum_{i=1}^{n}(y_i-\hat{y}_i)^2$ 대신에

  • $\frac{1}{n}\sum_{i=1}^{n}(y_i-\hat{y}_i)^2$
  • $\frac{1}{2n}\sum_{i=1}^{n}(y_i-\hat{y}_i)^2$

중 하나를 사용하여도 상관없다.

(A2) 별표로 표시된 점이 정말 $(2.5,4.0)$일까? $\Longleftrightarrow$ l이 정말 $w_0=2.5$, $w_1=4.0$에서 최소화 되는가?

- np.argmin 소개

_a=np.array([0,2,5,2,3,4])
np.argmin(_a)
0
np.argmin(l)
598

이건 무슨 값이지??

- 왜 이런일이 생기는가?

_X=np.array([[1,6,3],[1,-5,5]])
_X
array([[ 1,  6,  3],
       [ 1, -5,  5]])
np.argmin(_X)
4

- array의 구조가 너무 컴퓨터 위주의 숫자임.. $\to$ np.unravel_index() 함수사용

np.unravel_index(4,_X.shape)
(1, 1)

- 이것을 응용하면

np.unravel_index(np.argmin(l),l.shape)
(17, 20)
_w0[17],_w1[20]
(2.5, 4.0)

- (2.5,4.0)에서 l이 최소값을 가지는 것이 맞긴함

- 그런데 이론적으로 그래야 하는 것은 아님.

torch.sum((y-2.5-4.0*x)**2)
tensor(26.6494)
XX=np.matrix(X)
yy=np.matrix(y).T
(XX.T*XX).I * XX.T * yy
matrix([[2.4458692],
        [4.004343 ]], dtype=float32)
torch.sum((y-2.4458692-4.004343*x)**2)
tensor(26.3600)
  • 진짜로 (2.4458692,4.004343) 에서의 로스가 더 작음

- $n$이 커질수록 (2.4458692, 4.004343) 의 값은 점점 (2.5,4.0)의 값에 가까워 진다.

(A3) 행벡터와 열벡터

- 아래의 매트릭스를 관찰하자.

XX
matrix([[ 1.        , -2.482113  ],
        [ 1.        , -2.3621461 ],
        [ 1.        , -1.9972954 ],
        [ 1.        , -1.6239362 ],
        [ 1.        , -1.4791915 ],
        [ 1.        , -1.4635365 ],
        [ 1.        , -1.450925  ],
        [ 1.        , -1.4435216 ],
        [ 1.        , -1.3722302 ],
        [ 1.        , -1.3079282 ],
        [ 1.        , -1.1903973 ],
        [ 1.        , -1.109179  ],
        [ 1.        , -1.1053556 ],
        [ 1.        , -1.0874591 ],
        [ 1.        , -0.94689655],
        [ 1.        , -0.9319339 ],
        [ 1.        , -0.8642649 ],
        [ 1.        , -0.78577816],
        [ 1.        , -0.7548619 ],
        [ 1.        , -0.74213064],
        [ 1.        , -0.6948388 ],
        [ 1.        , -0.610345  ],
        [ 1.        , -0.5829591 ],
        [ 1.        , -0.56210476],
        [ 1.        , -0.55064297],
        [ 1.        , -0.50577736],
        [ 1.        , -0.48062643],
        [ 1.        , -0.4737953 ],
        [ 1.        , -0.47096547],
        [ 1.        , -0.46755713],
        [ 1.        , -0.3873588 ],
        [ 1.        , -0.37194738],
        [ 1.        , -0.3687963 ],
        [ 1.        , -0.31592152],
        [ 1.        , -0.27751535],
        [ 1.        , -0.27715707],
        [ 1.        , -0.27338728],
        [ 1.        , -0.27207515],
        [ 1.        , -0.2667671 ],
        [ 1.        , -0.21550845],
        [ 1.        , -0.20004053],
        [ 1.        , -0.18163072],
        [ 1.        , -0.17081414],
        [ 1.        , -0.1565458 ],
        [ 1.        , -0.14479806],
        [ 1.        , -0.13611706],
        [ 1.        , -0.10566129],
        [ 1.        , -0.06031348],
        [ 1.        , -0.05588722],
        [ 1.        , -0.02136729],
        [ 1.        ,  0.06554431],
        [ 1.        ,  0.06835173],
        [ 1.        ,  0.11953046],
        [ 1.        ,  0.14198998],
        [ 1.        ,  0.15207446],
        [ 1.        ,  0.15675156],
        [ 1.        ,  0.26455274],
        [ 1.        ,  0.26559785],
        [ 1.        ,  0.3156574 ],
        [ 1.        ,  0.32201108],
        [ 1.        ,  0.346143  ],
        [ 1.        ,  0.39839193],
        [ 1.        ,  0.4189721 ],
        [ 1.        ,  0.5442578 ],
        [ 1.        ,  0.557936  ],
        [ 1.        ,  0.591254  ],
        [ 1.        ,  0.61482644],
        [ 1.        ,  0.64686656],
        [ 1.        ,  0.64689904],
        [ 1.        ,  0.6523392 ],
        [ 1.        ,  0.6673753 ],
        [ 1.        ,  0.7059195 ],
        [ 1.        ,  0.7141374 ],
        [ 1.        ,  0.78221494],
        [ 1.        ,  0.8153611 ],
        [ 1.        ,  0.8668233 ],
        [ 1.        ,  0.9290748 ],
        [ 1.        ,  0.98036987],
        [ 1.        ,  0.9853081 ],
        [ 1.        ,  0.99413556],
        [ 1.        ,  1.0375688 ],
        [ 1.        ,  1.039256  ],
        [ 1.        ,  1.0697267 ],
        [ 1.        ,  1.1023871 ],
        [ 1.        ,  1.112612  ],
        [ 1.        ,  1.1531745 ],
        [ 1.        ,  1.2289088 ],
        [ 1.        ,  1.3403202 ],
        [ 1.        ,  1.3493598 ],
        [ 1.        ,  1.4279404 ],
        [ 1.        ,  1.4994265 ],
        [ 1.        ,  1.503098  ],
        [ 1.        ,  1.5436871 ],
        [ 1.        ,  1.6788615 ],
        [ 1.        ,  2.083233  ],
        [ 1.        ,  2.2444    ],
        [ 1.        ,  2.393501  ],
        [ 1.        ,  2.6056044 ],
        [ 1.        ,  2.605658  ],
        [ 1.        ,  2.66324   ]], dtype=float32)

- 두번째 col을 선택하고 싶다.

XX[:,1]
matrix([[-2.482113  ],
        [-2.3621461 ],
        [-1.9972954 ],
        [-1.6239362 ],
        [-1.4791915 ],
        [-1.4635365 ],
        [-1.450925  ],
        [-1.4435216 ],
        [-1.3722302 ],
        [-1.3079282 ],
        [-1.1903973 ],
        [-1.109179  ],
        [-1.1053556 ],
        [-1.0874591 ],
        [-0.94689655],
        [-0.9319339 ],
        [-0.8642649 ],
        [-0.78577816],
        [-0.7548619 ],
        [-0.74213064],
        [-0.6948388 ],
        [-0.610345  ],
        [-0.5829591 ],
        [-0.56210476],
        [-0.55064297],
        [-0.50577736],
        [-0.48062643],
        [-0.4737953 ],
        [-0.47096547],
        [-0.46755713],
        [-0.3873588 ],
        [-0.37194738],
        [-0.3687963 ],
        [-0.31592152],
        [-0.27751535],
        [-0.27715707],
        [-0.27338728],
        [-0.27207515],
        [-0.2667671 ],
        [-0.21550845],
        [-0.20004053],
        [-0.18163072],
        [-0.17081414],
        [-0.1565458 ],
        [-0.14479806],
        [-0.13611706],
        [-0.10566129],
        [-0.06031348],
        [-0.05588722],
        [-0.02136729],
        [ 0.06554431],
        [ 0.06835173],
        [ 0.11953046],
        [ 0.14198998],
        [ 0.15207446],
        [ 0.15675156],
        [ 0.26455274],
        [ 0.26559785],
        [ 0.3156574 ],
        [ 0.32201108],
        [ 0.346143  ],
        [ 0.39839193],
        [ 0.4189721 ],
        [ 0.5442578 ],
        [ 0.557936  ],
        [ 0.591254  ],
        [ 0.61482644],
        [ 0.64686656],
        [ 0.64689904],
        [ 0.6523392 ],
        [ 0.6673753 ],
        [ 0.7059195 ],
        [ 0.7141374 ],
        [ 0.78221494],
        [ 0.8153611 ],
        [ 0.8668233 ],
        [ 0.9290748 ],
        [ 0.98036987],
        [ 0.9853081 ],
        [ 0.99413556],
        [ 1.0375688 ],
        [ 1.039256  ],
        [ 1.0697267 ],
        [ 1.1023871 ],
        [ 1.112612  ],
        [ 1.1531745 ],
        [ 1.2289088 ],
        [ 1.3403202 ],
        [ 1.3493598 ],
        [ 1.4279404 ],
        [ 1.4994265 ],
        [ 1.503098  ],
        [ 1.5436871 ],
        [ 1.6788615 ],
        [ 2.083233  ],
        [ 2.2444    ],
        [ 2.393501  ],
        [ 2.6056044 ],
        [ 2.605658  ],
        [ 2.66324   ]], dtype=float32)
  • 정상적을 잘 선택되었다.

- 이제 XX에서 첫번째 row를 선택하고 싶다면?

XX[0,:]
matrix([[ 1.      , -2.482113]], dtype=float32)

- X에 관심을 가져보자.

- 첫번째 row를 뽑고싶다면?

X[0,:]
tensor([ 1.0000, -2.4821])

- 두번째 col을 뽑고 싶다면?

X[:,1]
tensor([-2.4821, -2.3621, -1.9973, -1.6239, -1.4792, -1.4635, -1.4509, -1.4435,
        -1.3722, -1.3079, -1.1904, -1.1092, -1.1054, -1.0875, -0.9469, -0.9319,
        -0.8643, -0.7858, -0.7549, -0.7421, -0.6948, -0.6103, -0.5830, -0.5621,
        -0.5506, -0.5058, -0.4806, -0.4738, -0.4710, -0.4676, -0.3874, -0.3719,
        -0.3688, -0.3159, -0.2775, -0.2772, -0.2734, -0.2721, -0.2668, -0.2155,
        -0.2000, -0.1816, -0.1708, -0.1565, -0.1448, -0.1361, -0.1057, -0.0603,
        -0.0559, -0.0214,  0.0655,  0.0684,  0.1195,  0.1420,  0.1521,  0.1568,
         0.2646,  0.2656,  0.3157,  0.3220,  0.3461,  0.3984,  0.4190,  0.5443,
         0.5579,  0.5913,  0.6148,  0.6469,  0.6469,  0.6523,  0.6674,  0.7059,
         0.7141,  0.7822,  0.8154,  0.8668,  0.9291,  0.9804,  0.9853,  0.9941,
         1.0376,  1.0393,  1.0697,  1.1024,  1.1126,  1.1532,  1.2289,  1.3403,
         1.3494,  1.4279,  1.4994,  1.5031,  1.5437,  1.6789,  2.0832,  2.2444,
         2.3935,  2.6056,  2.6057,  2.6632])

- shape을 비교하여 보자.

XX.shape, (XX[0,:]).shape, (XX[:,1]).shape
((100, 2), (1, 2), (100, 1))
  • 이게 상식적임
X.shape, (X[0,:]).shape, (X[:,1]).shape
(torch.Size([100, 2]), torch.Size([2]), torch.Size([100]))
  • row-vec, col-vec의 구분없이 그냥 길이2인 벡터, 길이가 100인 벡터로 고려됨
  • row-vec, col-vec의 구분을 하려면 2차원이 필요한데 1차원으로 축소가 되면서 생기는 현상
  • 대부분의 경우 별로 문제가 되지 않음.
  • 수학적으로는 col-vec, row-vec를 엄밀하게 구분하는 것이 좋지만, 프로그래밍 효율을 생각하면 떄로는 구분이 모호한게 유리할 수도 있다.