본문 바로가기

Andrew Ng(Deep Learning)

앤드류 응 교수 딥러닝 학습일지-(4)

반응형

 

딥러닝 학습일지 4번으로 돌아왔습니다. 지금 일본 여행 와있는데 한창 딥러닝이랑 프론트 공부하고 있을 때 와서 좀 흐름이 깨진듯해서 아쉽네.이도저도 아닌 느낌? 그래도 일단 4번째 딥러닝 공부일지를 써놓겠습니다.


 

이번 시간에 주로 배우는 내용은 벡터화입니다. 말 그대로 벡터로 만들어준다는 뜻입니다. 

앞에서 계속 다룬 z=wTx+b를 처리하는 것을 예로 들어볼게요.

Non-Vectorization

#Non-Vectorization
z=0
for i in range(n_x):
    z+=w[i]*x[i]
z+=b
 

다음과 같은 과정을 통해 wTx+b를 구하게 됩니다. 

벡터화를 이용한 코드는 다음과 같습니다. 

import numpy as np
z=np.dot(w,x)+b
 

가장 큰 차이점은 for문을 사용하지 않는다는 것입니다. 

순차적으로 계산하는 for문과 달리 numpy는 병렬적으로 처리를 하게 됩니다. 

그렇기 때문에 벡터화를 하면 속도가 훨씬 빠르게 됩니다.

이는 실제로 코드로도 확인을 할 수 있다.

import numpy as np
import time
a=np.random.rand(10000000)
b=np.random.rand(10000000)
 

일단 numpy와 time 모듈을 import 해준다.

numpy의 random.rand를 이용해서 임의의 리스트를 만들어준다.

먼저, 이해를 위해 벡터화를 하지 않은 코드를 보여주겠다.

time1=time.time() #현재 시간 측정
c=0
for i in range(10000000):  #반복문 돌리면서 구하기
    c+=a[i]*b[I] 
time2 = time.time()# 현재 시간 측정
print("Non_Vectorized Version: " + str(1000*(time2-time1))+"ms") #걸린 시간 구하기
print(c)
 

다음 코드를 사용하면 

Non_Vectorized Version: 1819.8752403259277ms

2500474.959519

의 출력값을 알 수 있다. 

이젠 벡터화를 이용한 코드를 사용하겠다.

time1=time.time()
c=np.dot(a,b)
time2=time.time()

print("Vectorized Version: " + str(1000*(time2-time1))+"ms")
 

Vectorized Version: 5.259037017822266ms

2500474.959519

시간 차이가 많이 남을 알 수 있다.

이는 numpy가 병렬화를 이용하기 때문이다. 이 때문에 딥러닝에서 병렬화를 이용하는 프로세서인 GPU가 많이 활용된다고 한다.

이 강의를 듣고 든 의문점은 그래서 "벡터화가 어떻게 시간을 단축화 하는데에 쓰인다는 거야..?" 였다.

언제나처럼 다음 강의를 통해 응 교수님은 해답을 주신다.


일단 더 많은 벡터화 예제들에 대해서 알려주십니다.

v=[v1,v2,...vn]이라는 행렬이 있을 때에, u=[exp(v1),exp(v2)...exp(vn)]이라는 행렬을 만들고 싶다고 생각해보자.

병렬화를 사용하지 않으면 다음과 같이 코드를 짜야한다.

import numpy as np
import math
import time
a=np.random.rand(10000)
 

위의 코드는 공통으로 넣어줘야하는 코드이다.

병렬화를 이용하지 않고 for문을 이용한 코드는 다음과 같다.

time1=time.time()
v=np.zeros((10000,1))
for i in range(len(a)):
    v[i]=math.exp(a[i])
time2=time.time()

print(str((time2-time1)*1000)+"ms")
 

걸린 시간 결과는 다음과 같다.

 

3.299236297607422ms

 

반면 병렬화를 이용한 코드는 다음과 같다.

time1=time.time()
v=np.exp(a)
time2=time.time()

print(str((time2-time1)*1000)+"ms")
 

걸린 시간 결과는 다음과 같다.

0.029802322387695312ms

압도적으로 빠른 것을 확인 할 수 있다.


이후에는 로지스틱 회귀에서의 벡터화에 대해 나온다. 이 강의를 들으면 이제서야 어떻게 벡터화를 병렬적으로 처리해서 시간을 줄이는지에 대해 알 수 있다. 

 
사진 삭제

사진 설명을 입력하세요.

로지스틱 회귀에서는 n개의 훈련 샘플이 있다면, 위의 그림과 같은 과정을 전부 거쳐 가야한다. 

기존에는 이를 for문을 활용하여 해결하였지만, 벡터화를 이용하여 해결한다.

우선 x를 하나의 벡터로 만들어준다.

x=[x^(1),x^(2),x^(3),...x^(n)]으로 만들어준다. 

이후 tranpose한 w를 곱해준 후 b를 더한다. 코드로 나타내면

Z = np.dot(np.transpose(W), X) + b
 

다음과 같이 나타낼 수 있다.

for문을 돌리지 않고 다음과 같이 한 줄로 모든 과정을 나타낼 수 있는 것이 정말 아름답고 멋있다. 

그럼 z=[z^(1),z^(2),z^(3),...z^(n)]의 형태가 나오고 각각의 z^(n)=wTx^(i)+b가 된다. 대단하다 정말.

이후에 시그모이드 함수를 만들어준후 시그모이드 함수에 넣어주면 위의 과정이 정말 간략하게 해결된다.

다만 한가지 주의 해야할 점은 b는 상수이고 앞의 np.tranpose는 행렬인데 마음대로 더해도 되냐는 것이다.

정말 신기하게도 파이썬은 broadcasting을 통해 알아서 차원을 알맞게 맞춰준다.

 

다음 파트에서는 로지스틱 회귀 경사 계산을 벡터화하는 방법에 대해서 나옵니다. 

이는 기존의 방법과 아예 동일하기에, 실습 파일을 통해서 보여드리겠습니다.

 


이번 강의를 마지막으로, 실습이 주어지는데 다음 블로그 글에서는 실습을 어떻게 진행하였는지로 찾아 뵙겠습니다!

 

반응형