728x90

딥러닝 수학5에서 다룬 내용을 가지고 실습을 하는 시간을 가졌습니다.

먼저 데이터를 생성하는데 y= 5x 라는 방정식 데이터를 100개 만듭니다. 

(5는 실제 theta이고, 학습을 통해서 따로 설정한 세타 초기값 -1이 5로 어떻게 변해가는지를 실습할 예정)

 

import matplotlib.pyplot as plt
import numpy as np

from dataset_generator import dataset_generator #강의에서 제공됨을 알립니다.
import basic_nodes as nodes #딥러닝 수학5에서 만들었던 node들 입니다.

#dataset preparation
dataset_gen = dataset_generator()
dataset_gen.set_coefficient([5,0]) # y = 5x

x_data,y_data = dataset_gen.make_dataset()

 

그 다음 단계로는 node들과 하이퍼 파라미터를 결정합니다. 

노드들은 위 그림처럼 각 단계 연산과정에서 사용됩니다. 

#model implementation
node1 = nodes.mul_node()

# square error loss implementation
node2 = nodes.minus_node()
node3=  nodes.square_node()

# Hyper parameter
epochs =5 #100개의 샘플을 5번 epoch => 500번 iteration
lr =0.01
th = -1 #arbitrary 세타, (초기값) 타겟 세타:5, 초기 세타:-1

#세타의 변화를 보기 위한 list 생성
loss_list =[]
th_list =[]

 

다음 단계는 forward입니다.

100개의 데이터가 있을때, 100개 데이터를 한번씩 업데이트를 완료 했을 경우를 1epoch라고 합니다.

그러면 epoch=5 는 100번 업데이터 *5 이므로 총 500번 iteration이 발생합니다.

for epoch in range(epochs): #1epoch 마다 100번씩 업데이트
    for data_idx in range(len(x_data)): #100개 데이터가 들어 있는 x_data
        x,y = x_data[data_idx], y_data[data_idx]
        
        #forward 실행
        z1 = node1.forward(th, x) # z1 = th * x
        z2 = node2.forward(y,z1) # z2 = y - z1
        l = node3.forward(z2) #l= (z2)**2

 

다음은 backward 단계입니다.

 

for epoch in range(epochs): #1epoch 마다 100번씩 업데이트
    for data_idx in range(len(x_data)): #100개 데이터가 들어 있는 x_data
        x,y = x_data[data_idx], y_data[data_idx]
        
        #forward 실행
        z1 = node1.forward(th, x) # z1 = th * x
        z2 = node2.forward(y,z1) # z2 = y - z1
        l = node3.forward(z2) #l= (z2)**2
        
        #backward 실행
        dz2 = node3.backward(1)#z2에 대한 편미분을 넘긴다
        dy, dz1 = node2.backward(dz2) #z2= y-z1이므로 각각 편미분은 1,-1 이다.
        dth , dx = node1.backward(dz1) #node1.backward(dz1) 값은 각각 세타와 x에게 할당된다.
        
        #gradient descent를 이용한 th 업데이트
        th = th -lr*dth
        
        th_list.append(th)
        loss_list.append(l)

 

다음은 학습된 결과를 시각화 하는 작업입니다.

#Result Visualization
fig, ax = plt.subplots(2,1, figsize=(30,10)) #2열,1행
ax[0].plot(th_list)
ax[1].plot(loss_list)

title_font = {'size':30,'alpha':0.8, 'color':'navy'}
label_font = {'size':20,'alpha':0.8}
plt.style.use('seaborn')

ax[0].set_title(r'$\theta$', fontdict=title_font)
ax[1].set_title("Loss", fontdict=title_font)
ax[1].set_xlabel('Iteration', fontdict=label_font)

200쯤에서 세타가 거의 5로 학습이 되었으며, loss값도 제로에 가깝게 되었습니다.

그러면 200interation (2epoch) 만을 가지고 직선으로 재 시각화를 해봅니다. 컬러는 무지개색이며

점은 실제값을 가리킵니다.

import matplotlib.cm as cm
N_line = 200
cmap = cm.get_cmap('rainbow', lut = N_line)

fig, ax = plt.subplots(1,1,figsize=(10,10))
ax.scatter(x_data,y_data) #실제값

test_th = th_list[:N_line]
x_range = np.array([np.min(x_data),np.max(x_data)]) #최소값과 최대값으로 선분 잇기

for line_idx in range(N_line):
    pred_line = np.array([x_range[0]*test_th[line_idx],x_range[1]*test_th[line_idx]]) #x*세타 형식
    ax.plot(x_range, pred_line, color =cmap(line_idx), alpha=0.1)

초기값이였던 -1(보라색)이 학습이 되어가면서 실제값과 비슷한 위치로 가까워 졌음을 알수가 있었습니다.

import matplotlib.pyplot as plt
import numpy as np

from dataset_generator import dataset_generator
# from dataset_generator import dataset_generator
import basic_nodes as nodes

#dataset preparation
dataset_gen = dataset_generator()
dataset_gen.set_coefficient([5,0]) # y = 5x

x_data,y_data = dataset_gen.make_dataset()

#model implementation
node1 = nodes.mul_node()

# square error loss implementation
node2 = nodes.minus_node()
node3=  nodes.square_node()

# Hyper parameter
epochs =5 #100개의 샘플을 5번 epoch => 500번 iteration
lr =0.01
th = -1 #arbitrary 세타, (초기값) 타겟 세타:5, 초기 세타:-1

#세타의 변화를 보기 위한 list 생성
loss_list =[]
th_list =[]

for epoch in range(epochs): #1epoch 마다 100번씩 업데이트
    for data_idx in range(len(x_data)): #100개 데이터가 들어 있는 x_data
        x,y = x_data[data_idx], y_data[data_idx]
        
        #forward 실행
        z1 = node1.forward(th, x) # z1 = th * x
        z2 = node2.forward(y,z1) # z2 = y - z1
        l = node3.forward(z2) #l= (z2)**2
        
        #backward 실행
        dz2 = node3.backward(1)#z2에 대한 편미분을 넘긴다
        dy, dz1 = node2.backward(dz2) #z2= y-z1이므로 각각 편미분은 1,-1 이다.
        dth , dx = node1.backward(dz1) #node1.backward(dz1) 값은 각각 세타와 x에게 할당된다.
        
        #gradient descent를 이용한 th 업데이트
        th = th -lr*dth
        
        th_list.append(th)
        loss_list.append(l)

#Result Visualization
fig, ax = plt.subplots(2,1, figsize=(30,10)) #2열,1행
ax[0].plot(th_list)
ax[1].plot(loss_list)

title_font = {'size':30,'alpha':0.8, 'color':'navy'}
label_font = {'size':20,'alpha':0.8}
plt.style.use('seaborn')

ax[0].set_title(r'$\theta$', fontdict=title_font)
ax[1].set_title("Loss", fontdict=title_font)
ax[1].set_xlabel('Iteration', fontdict=label_font)

import matplotlib.cm as cm
N_line = 200
cmap = cm.get_cmap('rainbow', lut = N_line)

fig, ax = plt.subplots(1,1,figsize=(10,10))
ax.scatter(x_data,y_data)

test_th = th_list[:N_line]
x_range = np.array([np.min(x_data),np.max(x_data)])

for line_idx in range(N_line):
    pred_line = np.array([x_range[0]*test_th[line_idx],x_range[1]*test_th[line_idx]])
    ax.plot(x_range, pred_line, color =cmap(line_idx), alpha=0.1)
    """
    x_Data의 최소,최대점 두점을 가지고 선분을 그어서 시각화를 한다.
    세타 5로 갈수록 Loss가 감소한다.
    """

 

 

딥러닝 학습 할때 loss값이 위 그림처럼 커졌다 작아 졌다를 반복하는데

이 이유는 100개의 샘플 때문입니다.

보라색 선은 초기값 -1일때의 예측 선입니다. 예측선과 1번 샘플과의 loss값 차이가 얼마 나지 않습니다.

이 작은 loss로 업데이트를 하면 작은 것만큼 조금 업데이트가 될것입니다. 

그런데 두번째 샘플을 골랐는데 loss값이 커진걸 알수 있습니다. 이렇게 되면 업데이트가 많이 되서 예측선이 크게 움직일 것입니다. 이렇게 샘플에 따라 loss값이 크고 작아 지기때문에 파동처럼 왔다갔다 하게 됩니다.

 

learning late Tuning

실습에서 사용된 lr =0.01 보라색을 먼저 보면

초기에는 loss값이 작은 데이터들이 뽑힌 이유로 업데이트가 자잘하게 움직이디가 갑자기 크게 업데이트가 된 부분이 있습니다. 업데이트가 크게 움직였다는 뜻은 loss가 크다는 뜻입니다. 

그렇다면 lr을 높힌다면 어떻게 되는지 빨간색 그래프를 통해 알아보겠습니다.

lr=0.04일때는 0.01와는 다르게 크게 업데이트 되었습니다. 하지만 자칫 반대쪽으로 발산할 경우가 있으므로 주의가 필요합니다. 큰 lr과 큰 loss가 만나면 발산할 여지가 크다는 걸 알수가 있겠습니다.

 

lr을 높히게 되면 세타값이 커졌다 작아졌다 왔다갔다 불안정하게 학습 되다가 5로 수렴하게 되었습니다.

만일 데이터샘플이 커지거나 lr이 더 커진다면 발산할 여지가 큽니다.  또한 중간에 아웃라이어를 만나게 되면 값이 갑자기 튈 가능성도 있습니다.

728x90

+ Recent posts