NumPy Master Class

Chapter4 Vectorization: Notebook2 1-dim Vectorization Example2

Shin's Lab 2020. 1. 9. 19:29
4_2_1dim_Vectorization_Example2

NumPy Master Class

Chapter4 Vectorization

Notebook2 1-dim Vectorization Example2

이번 notebook에서는 1-dimensional vectorization에 익숙해져야 더 높은 차원의 vectorization을 쉽게 이용할 수 있으므로 2가지 연습을 더 해보려고 한다.

1. Mean Square Error
2. Binary Cross Entropy
In [1]:
import numpy as np
import matplotlib.pyplot as plt
import time

Mean Square Error

우리가 흔히 MSE라고 부르는 Mean Square Error는 다음과 같은 식을 통해 구한다.

$MSE = \frac{1}{N} \sum_{i=1}^{N} (x^{(i)} - y^{(i)})^{2}$

먼저 다음과 같이 Error를 구할 data를 만들어보자.

In [10]:
n_data = 5000000
x_data = np.random.randn(n_data)
y_data = np.random.randn(n_data)

print("x_data[:5]:", x_data[:5])
print("y_data[:5]:", y_data[:5])
x_data[:5]: [ 1.00570714 -0.75556159 -0.48778013  0.31380528  0.60775238]
y_data[:5]: [-0.70677337  0.34879298  0.86662903  0.47356055 -0.30250752]

그리고 먼저 위의 MSE를 for loop을 이용해서 구해보면 다음과 같다.

In [11]:
tic = time.time()

square_sum = 0
for i in range(n_data):
    square_sum += (x_data[i] - y_data[i])*(x_data[i] - y_data[i])
MSE = square_sum / n_data
print("MSE: ", MSE)

toc = time.time()
for_time = toc - tic
print("Elapsed Time:", for_time, 'sec')
MSE:  1.999963383633311
Elapsed Time: 4.2392377853393555 sec

그리고 Vectorization을 이용하면 다음과 같다.

In [13]:
tic = time.time()

MSE = np.mean(np.power(x_data - y_data, 2))
print("MSE: ", MSE)

toc = time.time()
vec_time = toc - tic
print("Elapsed Time:", vec_time, 'sec')
MSE:  1.9999633836334298
Elapsed Time: 0.06562089920043945 sec

이 두 결과를 비교하면 다음과 같다.

In [14]:
print("Elapsed Time Ratio: ", for_time/vec_time)
Elapsed Time Ratio:  64.60194598051113

저번처럼 200배의 차이는 나지 않지만 1분 VS 1시간 관점에서 보면 충분히 비약적인 발전이 있음을 알 수 있다.


Binary Cross Entropy

다음 예제는 Binary Cross Entropy(BCE)이고, 이 BCE는 두 확률분포가 얼마나 닮아있는지 수치적으로 구하는 값이다.

$BCE = -\frac{1}{N} \sum_{i=1}^{N}(y^{(i)}*\log{x^{(i)}} + (1- y^{(i)})*(\log({1 - x^{(i)}})))$

가 된다. 식의 의미를 모르는 독자들은 굳이 의미까지 이해할 필요는 없다.

BCE는 확률분포가 필요하기 때문에 다음과 같이 0과 1사이의 data를 만들어보자.

In [15]:
n_data = 5000000
x_data = np.random.rand(n_data)
y_data = np.random.rand(n_data)

print("x_data[:5]:", x_data[:5])
print("y_data[:5]:", y_data[:5])
x_data[:5]: [0.81366947 0.80375486 0.81354654 0.53809821 0.93671709]
y_data[:5]: [0.94083929 0.54304959 0.22789704 0.92122947 0.23008166]

그리고 이 data에 대하여 Vectorization 전과 후를 비교해보자.

In [19]:
tic = time.time()

log_sum = 0
for i in range(n_data):
    log_sum += y_data[i]*np.log(x_data[i]) + (1-y_data[i])*np.log(1-x_data[i])
BCE = -1*log_sum/n_data

print("BCE: ", BCE)
toc = time.time()
for_time = toc - tic
print("Elapsed Time:", for_time, 'sec')
BCE:  0.9997791517460576
Elapsed Time: 18.42511510848999 sec
In [20]:
tic = time.time()

BCE = -1*np.mean(y_data*np.log(x_data) + (1-y_data)*np.log(1-x_data))

print("BCE: ", BCE)
toc = time.time()
vec_time = toc - tic
print("Elapsed Time:", for_time, 'sec')
BCE:  0.9997791517461639
Elapsed Time: 18.42511510848999 sec
In [21]:
print("Elapsed Time Ratio: ", for_time/vec_time)
Elapsed Time Ratio:  70.86290579920114

이번 결과는 약 70배의 성능 차이를 보여줬다. 이번에도 충분히 비약적인 성능개선이 이뤄진 것을 알 수 있다.

위와 같이 1-dimensional data에 대해서 2가지 예를 들어봤는데, 모두 비약적인 성능개선을 확인할 수 있었다. 위의 내용이 어려운 독자들도 있을 것이고, 너무 당연하게 느껴지는 독자들도 있을 것이다. 하지만 어느 경우에나 이렇게 Vectorization을 습관화하게 된다면 다른 사람들보다 좋은 프로그램을 만들 수 있을 것이고, 남들과 비교하여 강점을 드러내는 부분이 될 테니 어렵더라도 꾸준히 잘 따라와줬으면 하는 바람이 있다.