[데이터분석] 매니폴드(manifold)란?


매니폴드를 설명할 때 대표적인 예시로 나오는게 스위스 롤이다.


 swiss roll manifold에 대한 이미지 검색결과


스위스롤의 특징을 보면 3차원의 공간에 롤처럼 말린형태로 데이터가 분포해 있다.

이 데이터 공간에 개미가 한마리 살고 있다고 가정해보자. 우리는 롤 안쪽에서 바깥쪽의 거리를 계산할 때, 공간상에서 가로지르는 유클리디안 방식으로 거리를 구하기 때문에 거리가 가깝다. 하지만 개미의 입장에서는 점프를 할 수 없기 때문에 롤을 따라서 바깥으로 도달하기위한 거리는 훨씬 멀다. 그리고 개미의 입장에서는 비선형적인 곡선도 국부적으로는 직선으로 근사되기 때문에 평면으로 느낄 것이다. (매니폴드 상의 임의의 점도 미소 구간에서는 유클리디안 공간) 우리가 사는 세상을 지도로 보면 2차원이지만 실제로는 구 형태의 3차원 매니폴드에 있는 것과 같다.

매니폴드 학습이라는 단어의 주관적인 이해는 '눈을 감고(학습이되지 않은 상태에서) 비유클리디안 형태를 만져가며(데이터를 이용해) 모양을 이해해(모델을 학습해) 나간다'라고 이해하고 있다. 매니폴드 학습을 하게되면 학습된 모델의 latent vector(기저 벡터)는 우리가 생각하는 차원과 다를 수 있으며, 위의 스위스롤도 신경망 모델의 입장에선 경우에 따라 펼친 모양으로 학습을 하게 될 것이다.


위 그림에서 선이 없고 점만 있다고 가정하면 단순한 데이터의 분포로 보일 수 도 있다. 하지만 실제로는 꼬여있는 실처럼 실선은 매니폴드를 나타낸다. 그리고 그 선이 모델이 학습해야할 매니폴드이다. 이 선을 고차원으로 projection하면 그림에서 실의 한쪽 끝을 잡고 들어올린다고 생각해볼수 있다. 그러면 꼬인 실이 펴지게 된다. 이와 비슷하게 차원을 높임으로써 매니폴드 학습을 쉽게할 수도 있다. 실제로 신경망 모델은 중간 층의 차원을 높임으로써 매니폴드 학습을 한다.





[통계, 머신러닝] 차원의 저주


차원의 저주란 차원이 증가함에 따라 탐색해야될 공간이 급격히 늘어나서 알고리즘 계산에 한계가 오는 경우를 말한다. 또는, 차원이 늘어남에 따라 기존의 데이터의 밀도가 급격히 줄어들어 예측력이 떨어지는 경우도 차원의 저주라고 한다.

예를 들어 아래의 세 점은 D1 차원에서만 설명할 땐 거리가 가까웠지만 D2라는 차원을 이용하는 순간 거리가 멀어졌다. 실제로는 그림보다 훨씬 거리가 늘어날 수 있고, 차원이 늘어날수록 기하급수적으로 데이터가 희박해진다.


이 경우 예측이 불안정해지고 과적합 위험이 커진다. 차원의 저주를 해결하는 방법은 데이터를 충분히 확보하는 것이지만 차원이 많이 증가하면 필요한 훈련 데이터의 수도 기하급수적으로 늘어나는 한계가 있다.


K-최근접이웃회귀와 차원의 저주

KNN 회귀는 주어진 K 값과 x0에 대해 x0에 가장 가까운 K개의 훈련 관측치 을 식별한다. 그다음 내 모든 훈련 관측치들에 대한 반응변수 값들의 평균을 사용하여 f(x0)을 추정한다.

KNN 분류는 가장 가까운 k개의 데이터를 보고 개수가 많은 class로 분류한다.

[출처 : 위키백과]


따라서 새로운 초록 점은 k=3 일땐 빨간색 세모와 같은 클래스가 되고, k=5 일땐 파란색 네모와 같은 클래스가 된다. 이 거리를 구할 때 유클리디안 거리를 사용하고, 단위에 따른 영향을 제거하기 위해 표준화를 한다. 또는, 데이터의 밀도를 고려하여 마할라노비스 거리(Mahalanobis distance)를 사용하기도 한다.

다시 본론으로 돌아와서, KNN 알고리즘은 유클리디안 거리를 사용하기 때문에 차원이 증가할수록 주어진 관측치에 가까운 이웃이 없는 현상이 발생한다. 이로인해 회귀에서는 차원이 4이상이면 선형회귀보다도 못한 성능을 낸다. 차원이 낮은 경우에도 해석력 관점에서 선형회귀를 더 선호할 수도 있다.



[Regression] Ridge and Lasso Regression in Python (3) - Lasso


이번엔 Ridge Regression을 파이썬으로 구현해서 파라미터값에 따른 회귀식의 차이를 살펴보겠습니다.


L2와 L1 Regularization은 이전 포스팅의 내용을 참고해주세요.


1. 데이터를 생성합니다.


import numpy as np
import pandas as pd
from matplotlib.pylab import rcParams
rcParams['figure.figsize'] = 8, 5
from sklearn.linear_model import Ridge
import matplotlib.pyplot as plt

x = np.array([i*np.pi/180 for i in range(60, 300, 4)])
np.random.seed(10)
y = np.sin(x) + np.random.normal(0, 0.15, len(x))
data = pd.DataFrame(np.column_stack([x, y]), columns=['x', 'y'])
plt.plot(data['x'], data['y'], '.')
for i in range(2, 16): # power
colname = 'x_%d'%i #new var will be x_power
data[colname] = data['x']**i

2. 케이스를 구분하고 결과값을 저장할 테이블을 만듭니다.

Polynomial regression과 마찬가지로 predictors에 차수를 확장시켜 컬럼명(feature name)을 저장합니다.

파라미터값인 alpha_ridge를 케이스 별로 나눕니다.

# Initialize predictors to be set of 15 powers of x
predictors=['x']
predictors.extend(['x_%d'%i for i in range(2,16)])

# Set the different values of alpha to be tested
alpha_ridge = [1e-15, 1e-10, 1e-8, 1e-4, 1e-3,1e-2, 1, 5, 10, 20] #파라미터값인 alpha_ridge를 케이스 별로 나눕니다.

# Initialize the dataframe for storing coefficients.
col = ['rss', 'intercept'] + ['coef_x_%d'%i for i in range(1,16)]
ind = ['alpha_%.2g'%alpha_ridge[i] for i in range(0,10)]
coef_matrix_ridge = pd.DataFrame(index=ind, columns=col)

models_to_plot = {1e-15:231, 1e-10:232, 1e-4:233, 1e-3:234, 1e-2:235, 5:236}

3. Lasso regression 함수를 작성합니다.

여기서 추가로 필요한 파라미터는 alpha입니다. Ridge와 거의 같습니다.

def lasso_regression(data, predictors, alpha, models_to_plot):
# Fit the model
lassoreg= Lasso(alpha=alpha, normalize=True)
lassoreg.fit(data[predictors], data['y'])
y_pred = lassoreg.predict(data[predictors])

# Check if a plot is to be made for the entered alpha
if alpha in models_to_plot:
plt.subplot(models_to_plot[alpha])
plt.tight_layout()
plt.plot(data['x'], y_pred)
plt.plot(data['x'], data['y'], '.')
plt.title('Plot for alpha: %.3g'%alpha)

# Return the result in pre-defined format
rss = sum((y_pred-data['y'])**2)
ret = [rss]
ret.extend([lassoreg.intercept_])
ret.extend(lassoreg.coef_)
return ret

4. 결과 테이블을 계산합니다.

for i in range(10):
coef_matrix_ridge.iloc[i, ] = lasso_regression(data, predictors, alpha_ridge[i], models_to_plot)


계수를 보면 α값이 작을수록 계수값이 작습니다. Ridge와는 반대입니다. 그리고 α값이 큰 경우에 계수 값이 0이 되기도 합니다.

Lasso의 Cost function은 아래와 같습니다. 가중치의 절대값에 파라미터가 곱해져있는 형태입니다.



마찬가지로 미분을 해보면 좌극한에서는 -1, 우극한에서는 1의 기울기를 갖는데 0에서는 미분이 불가능합니다.


0에서 미분이 되지 않는 문제를 해결하는 방법인 Proximal gradient methods를 사용합니다. Sλt(x)는 Soft-thresholding operator라고 합니다.


S(x)를 x대신 w로 치환하여 아래의 g(wj)로 보면 됩니다. 꼭 람다가 λ/2가 되어야 하는 것은 아니고 그냥 λ여도 됩니다.(알고리즘의 차이인 걸로 추정됨)

즉, 미분이 안되는 미소 구간에 대해서는 가중치가 0이 된다는 뜻입니다.


미소구간을 결정하는 것은 λ이고 위의 Python 코드에서는 α입니다. 기울기가 큰 상태에서 큰 step(α)으로 기울기를 조정하는데 가중치의 크기가 +-α/2 구간으로 들어가게 되면 가중치가 0이 되어버립니다. 


또 다른 설명으로는, 가중치 제한인 s의 범위에 따른 해석입니다.

B-hat은 최소제곱자승법으로 구한 최소 지점입니다. s가 점점 커지다보면 B-hat에 도달하는데 이 지점은 파라미터가 0이되는 때입니다.

B-hat 주변의 타원은 RSS를 나타내는데 RSS와 파란색 영역이 닿는 부분이 계수값이 됩니다.




왼쪽 그림은 Lasso의 경우인데 Lasso는 어쩌다가 꼭지점에서 RSS가 최소가 될 수 있습니다. 그렇게 되면 그 B1의 가중치가 0이 될것입니다. 반면 오른쪽 그림의 Rigde는 원이기 때문에 축에서 만나지 않으므로 가중치가 0이되는 일이 없습니다.


도움이 되셨다면 공감 부탁드려요!

[Regression] Ridge and Lasso Regression in Python(2)


이번엔 Ridge Regression을 파이썬으로 구현해서 파라미터값에 따른 회귀식의 차이를 살펴보겠습니다.


L2와 L1 Regularization은 이전 포스팅의 내용을 참고해주세요.


1. 데이터를 생성합니다.


import numpy as np
import pandas as pd
from matplotlib.pylab import rcParams
rcParams['figure.figsize'] = 8, 5
from sklearn.linear_model import Ridge
import matplotlib.pyplot as plt

x = np.array([i*np.pi/180 for i in range(60, 300, 4)])
np.random.seed(10)
y = np.sin(x) + np.random.normal(0, 0.15, len(x))
data = pd.DataFrame(np.column_stack([x, y]), columns=['x', 'y'])
plt.plot(data['x'], data['y'], '.')
for i in range(2, 16): # power
colname = 'x_%d'%i #new var will be x_power
data[colname] = data['x']**i

2. 케이스를 구분하고 결과값을 저장할 테이블을 만듭니다.

Polynomial regression과 마찬가지로 predictors에 차수를 확장시켜 컬럼명(feature name)을 저장합니다.

파라미터값인 alpha_ridge를 케이스 별로 나눕니다.

# Initialize predictors to be set of 15 powers of x
predictors=['x']
predictors.extend(['x_%d'%i for i in range(2,16)])

# Set the different values of alpha to be tested
alpha_ridge = [1e-15, 1e-10, 1e-8, 1e-4, 1e-3,1e-2, 1, 5, 10, 20] #파라미터값인 alpha_ridge를 케이스 별로 나눕니다.

# Initialize the dataframe for storing coefficients.
col = ['rss', 'intercept'] + ['coef_x_%d'%i for i in range(1,16)]
ind = ['alpha_%.2g'%alpha_ridge[i] for i in range(0,10)]
coef_matrix_ridge = pd.DataFrame(index=ind, columns=col)

models_to_plot = {1e-15:231, 1e-10:232, 1e-4:233, 1e-3:234, 1e-2:235, 5:236}

3. Ridge regression 함수를 작성합니다.

여기서 추가로 필요한 파라미터는 alpha입니다.

def ridge_regression(data, predictors, alpha, models_to_plot):
# Fit the model
ridgereg = Ridge(alpha=alpha, normalize=True)
ridgereg.fit(data[predictors], data['y'])
y_pred = ridgereg.predict(data[predictors])

# Check if a plot is to be made for the entered alpha
if alpha in models_to_plot:
plt.subplot(models_to_plot[alpha])
plt.tight_layout()
plt.plot(data['x'], y_pred)
plt.plot(data['x'], data['y'], '.')
plt.title('Plot for alpha: %.3g'%alpha)

# Return the result in pre-defined format
rss = sum((y_pred-data['y'])**2)
ret = [rss]
ret.extend([ridgereg.intercept_])
ret.extend(ridgereg.coef_)
return ret

4. 결과 테이블을 계산합니다.

for i in range(10):
coef_matrix_ridge.iloc[i, ] = ridge_regression(data, predictors, alpha_ridge[i], models_to_plot)

계수를 잘 보면 α값이 작을수록 계수값이 커집니다. α값이 큰 경우 언더피팅이 발생하고 rss값이 큰 것을 알 수 있습니다.

pd.options.display.float_format = '{:,.2g}'.format
print(coef_matrix_ridge)
plt.show()

적당한 α값을 찾는 것이 중요합니다.

Ridge regression의 특징은 계수를 0으로 만들지는 않는다는 것입니다.


왜 계수가 0이 되지않는지 확인하기 위해 Cost function으로 돌아가보겠습니다.

Cost function을 최소화하는 방법 중 Gradient descent method를 생각해보겠습니다.

Cost function을 미분하면 아래와 같은 식이 나옵니다.

식을 다시 쓰면 아래와 같습니다.

wj 오른쪽을 제외하고 wj만 보면 일정한 비율로 t+1에서의 계수값이 작아진다는 것을 알 수 있습니다. 1-2λη가 계수의 크기보다 작아지면 부정확할 수 있다는 경고가 발생합니다.


즉, 계수가 %의 비율로 작아진다는 뜻입니다. 어떤 계수 값이 %로 작아진다고해도 0은 되지 않기때문에 L2 가중치 규제는 계수가 0이 되지 않습니다.

또 다른 설명으로는, 가중치 제한인 s의 범위에 따른 해석입니다.

B-hat은 최소제곱자승법으로 구한 최소 지점입니다. s가 점점 커지다보면 B-hat에 도달하는데 이 지점은 파라미터가 0이되는 때입니다.

B-hat 주변의 타원은 RSS를 나타내는데 RSS와 파란색 영역이 닿는 부분이 계수값이 됩니다.



왼쪽 그림은 Lasso의 경우인데 Lasso는 어쩌다가 꼭지점에서 RSS가 최소가 될 수 있습니다. 그렇게 되면 그 B1의 가중치가 0이 될것입니다. 반면 오른쪽 그림의 Rigde는 원이기 때문에 축에서 만나지 않으므로 가중치가 0이되는 일이 없습니다.


도움이 되셨다면 공감 부탁드려요!

[Regression] Ridge and Lasso Regression in Python(1) - Polynomial


이번에는 Ridge와 Lasso Regression을 파이썬으로 구현해보도록 하겠습니다.


1. 데이터를 생성합니다.

그리고 모델의 복잡도를 비교하기 위해 x의 차수를 높혀가며 선형 회귀식을 만들어 보려고 합니다.

rcParams는 figure의 사이즈를 지정하기 위해 사용합니다.


import numpy as np
import pandas as pd
import random
from matplotlib.pylab import rcParams
rcParams['figure.figsize'] = 8, 5
from sklearn.linear_model import LinearRegression
import matplotlib.pyplot as plt

x = np.array([i*np.pi/180 for i in range(60, 300, 4)])
np.random.seed(10)
y = np.sin(x) + np.random.normal(0, 0.15, len(x))
data = pd.DataFrame(np.column_stack([x, y]), columns=['x', 'y'])
plt.plot(data['x'], data['y'], '.')
for i in range(2, 16): # power
colname = 'x_%d'%i #new var will be x_power
data[colname] = data['x']**i

만들어진 데이터는 가우시안 에러를 가진 사인 곡선입니다.


2. 모델의 차수 별 계수와 절편 값을 테이블로 만들기 위해 dataframe을 만듭니다.

#Initialize a dataframe to store the results:
col = ['rss','intercept'] + ['coef_x_%d'%i for i in range(1, 16)]
ind = ['model_pow_%d'%i for i in range(1, 16)]
coef_matrix_simple = pd.DataFrame(index=ind, columns=col)

#Define the powers for which a plot is required:
models_to_plot = {1:231,3:232,6:233,9:234,12:235,15:236}

models_to_plot은 1차는 2*3 grid의 첫번째, 3차는 grid의 두번째에 띄우기 위한 Dictionary 입니다.


3. Polynomial regression을 하기위해 linear_regression 함수를 만듭니다.

predictors는 몇개의 항(차수)를 사용할지 정하여 feature 명을 저장합니다.

linreg로 차수만큼 테이블의 컬럼과 데이터를 불러와서 피팅시킵니다.

그리고 다시 training 데이터를 넣어 모델 예측값을 구합니다.


rss는 예측과 실체값의 차이 즉 MSE 입니다.

def linear_regression(data, power, models_to_plot):
# initialize predictors:
predictors=['x']
if power >= 2:
predictors.extend(['x_%d'%i for i in range(2, power+1)])
#Fit the model
linreg = LinearRegression(normalize=True)
linreg.fit(data[predictors], data['y']) # 차수만큼 테이블의 컬럼을 불러와서 피팅시킨다.
y_pred = linreg.predict(data[predictors]) # ligreg 모델에 데이터를 넣었을때 나오는 y 값

#Check if a plot is to be made for the enterted power
if power in models_to_plot:
plt.subplot(models_to_plot[power])
plt.tight_layout() # plot과 window 여백 제거
plt.plot(data['x'], y_pred)
plt.plot(data['x'], data['y'], '.')
plt.title('Plot for power: %d' % power)

#Return the result in pre-defined format
rss = sum((y_pred - data['y'])**2)
ret = [rss]
ret.extend([linreg.intercept_])
ret.extend(linreg.coef_)
return ret

아래 코드를 실행시키면 coef_matrix가 채워집니다.

for i in range(1,16):
coef_matrix_simple.iloc[i-1, 0:i+2] = linear_regression(data, power=i, models_to_plot=models_to_plot)


아래는 결과값입니다. 15차까지 다 나오지는 않았지만 차수가 높아질 수록 계수의 절대값의 크기가 커지고 모델의 복잡도가 증가합니다.

Ridge와 Lasso를 사용하여 가중치 규제를 하는 이유가 이것입니다. 계수의 절대값이 점점 커지기 때문에 가중치 값을 줄이고 모델의 복잡도를 줄일 필요가 있습니다.

가중치가 크다는 말은 무엇일까요? 큰 가중치는 그 feature를 강조한다는 뜻입니다. 하지만 가중치가 점점 커지다 보면 모델이 training data에 모두 예측하려합니다.



따라서 차수가 높아질수록 과적합 현상이 일어납니다.



도움이 되셨다면 공감 부탁드려요!


[가중치 규제] L1 & L2 Regularization Method


데이터가 충분하지 않을 때, 데이터의 노이즈를 학습하여 모델이 과적합되는 경우가 있습니다.

아래 그림은 Underfitting부터 Overfitting이 되는 과정을 보여줍니다.



가중치 규제는 모델이 복잡해지지 않도록 모델 복잡도에 벌점(penalty)를 주는 것입니다. 여기서 복잡해진다는 말은 불필요한 항이 많아진다는 뜻입니다.

Regularization parameter인 람다는 절편을 제외한 항에 벌점을 주어 모델을 더 general하게 해줍니다.



● Cost function에 규제 항 추가하기


① 계수(가중치)의 절대값에 비례하는 penalty 추가 : L1 규제 → Lasso Regression



      • L1 규제는 일부 계수 값을 완전히 0으로 만들 수 있다.

② 계수(가중치)의 제곱에 비례하는 penalty 추가 : L2 규제 → Ridge Regression


      • L2 규제는 계수 값을 작게 만들지만 완전히 0이 되진 않는다.


※ 가중치 규제의 특징

      • 만약 λ가 0이면 OLS 형태가 된다.

      • 만약 λ가 너무 크면 Under fitting이 된다.

      • 중요하지 않은 항의 계수를 0으로 만들기 때문에 주요변수 선택에도 활용된다.

      • 적절한 λ값을 찾는 것이 중요하다.


도움이 되셨다면 공감 부탁드려요!

[Regression] Piecewise Regression with numpy



Piecewise Regression이란 하나의 식으로 전체 구간을 설명하기 어려울 경우 구간에 따라 모델을 다르게 쓰는 기법이다.

우선 데이터를 생성한다.


import numpy as np
import matplotlib.pyplot as plt
from scipy import optimize

np.random.seed(0)
x = np.random.normal(0, 1, 1000) * 10
# 조건에 맞는 값을 특정 다른 값으로 변환하기
# np.where(조건, 조건에 맞을 때 값, 조건과 다른 때 값) if 문과 비슷함. 그냥 where은 조건에 맞는 인덱스 반환
y = np.where(x < -15, -2 * x + 3, np.where(x < 10, x + 48, -4 * x + 98)) + np.random.normal(0, 3, 1000)
plt.scatter(x, y, s = 5, color = u'b', marker = '.', label = 'scatter plt')

원래는 random array가 매번 바뀌지만 np.random.seed는 괄호 안의 값에 따라 동일한 랜덤 array를 생성하도록 한다. 

a = np.array([1, 2, 3, 4, 5]) 의 배열이 있을때, np.where(a < 3)을 하면 조건에 맞게 1과 2의 인덱스 값(0, 1)을 반환한다.

3개의 parameter를 이용하는 방식도 있다.

np.where(a < 3, 10, a) 를 하면 [10, 10, 3, 4, 5]를 반환한다. 즉, 조건에 맞으면 그 배열 값을 10으로 바꾸고 아니면 원래 값으로 둔다는 식이다. if 문과 비슷하다.

x와 y를 scatter plot으로 보면 아래와 같다. 


위의 데이터에 np.piecewise를 적용하기 전에 쉬운 예로 이해를 돕고자 한다.

x = np.linspace(-2.5, 2.5, 6)
print(x) # [-2.5 -1.5 -0.5 0.5 1.5 2.5]


condlist = [x < 0, x >= 0]
print(condlist) ## [array([True, True, True, False, False, False]), array([False, False, False, True, True, True,])]


t = np.piecewise(x, [x < 0, x >= 0], [lambda x: -3*x, lambda x: 3*x])
plt.plot(range(len(x)), t)

나누고자 하는 구간이 2개이면 condlist의 조건도 2개이고 2개의 array를 반환한다. 그리고 그 condlist가 첫번째 lambda와 두번째 lambda의 input으로 입력되고, True면 계산되고 False면 0을 반환하여 두 lambda 함수의 합을 최종적으로 np.piecewise의 값으로 반환한다.



하지만 우리는 위에서 0으로 두었던 분기점을 정하지 않았기 때문에 데이터에 맞춰서 최적의 분기점을 찾도록 할 것이다.

그러면 scipy.optimize의 목적함수로 쓰일 piecewise_linear 함수를 정의해야 한다. 

condlist는 3구간으로 나올수 있도록 하고(분기점의 수만큼 조건식이 필요) 그에 대응될 lambda 함수의 모양을 짠다. lambda 함수가 이어지도록 되어있는데 k1*x + b + k2*(x-x0)에서 앞의 k1*x + b 는 분기점에서의 y값(새로운 상수항)이 되므로 이렇게 쓰지 않으면 에러가 난다.

def piecewise_linear(x, x0, x1, b, k1, k2, k3):
condlist = [x < x0, (x >= x0) & (x < x1), x >= x1]
funclist = [lambda x: k1*x + b, lambda x: k1*x + b + k2*(x-x0), lambda x: k1*x + b + k2*(x-x0) + k3*(x - x1)]
return np.piecewise(x, condlist, funclist)
p , e = optimize.curve_fit(piecewise_linear, x, y)


이 과정을 거쳐 데이터에 가장 적합한(에러가 최소화되는) x0, x1, b, k1, k2, k3이 정해지고 아래와 같이 선이 그려진다.

xd = np.linspace(-30, 30, 1000)
plt.plot(x, y, "o")
plt.plot(xd, piecewise_linear(xd, *p))





[케라스(keras)] 케라스에서 텐서보드 사용하기-Tensorboard with Keras


케라스로 만든 모델을 텐서보드에서 확인하는 방법입니다.

기존에 만든 모델에 3줄만 추가해주면 됩니다. 아래 노란색 주석을 참고해주세요.


from keras.datasets import mnist
from keras.utils import to_categorical
from tensorflow.python.keras.callbacks import TensorBoard ## TensorBoard 를 import합니다.
from time import time ## Log를 만들때 사용합니다.
from keras import layers
from keras import models

(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
# sp = np.shape(train_images) #(60000, 28, 28) 28x28 그림 60000장

train_images = train_images.reshape((60000, 28, 28, 1)) # <class 'numpy.ndarray'>
train_images = train_images.astype('float32') / 255 # <class 'numpy.ndarray'>
test_images = test_images.reshape((10000, 28, 28, 1))
test_images = test_images.astype('float32') / 255

train_labels = to_categorical(train_labels)
test_labels = to_categorical(test_labels)

model = models.Sequential() # Sequential method로 모델 구성
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1), padding='same'))
model.add(layers.MaxPooling2D(2, 2))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D(2, 2))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))

model.add(layers.Flatten())
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(10, activation='softmax'))
print(model.summary())


tensorboard = TensorBoard(log_dir="logs/{}".format(time())) ## 이 줄과

model.compile(optimizer='rmsprop',
loss='categorical_crossentropy',
metrics=['accuracy'])
model.fit(train_images, train_labels, epochs=5, batch_size=64, callbacks=[tensorboard]) ## 이 줄을 추가합니다.

test_loss, test_acc = model.evaluate(test_images, test_labels)


위의 코드를 한번 실행시키고 커맨드창을 열어 텐서보드를 실행시켜줍니다. 

현재 경로로 이동하고 tensorboard --logdir=logs(로그가 저장되어 있는 폴더명)



처음에는 커맨드라인에 나온 http://컴퓨터이름:6006으로 접속했더니 페이지가 안열렸습니다.

그래서 localhost:6006으로 다시 접속하니 정상 실행됐습니다.



사용방법은 https://www.youtube.com/watch?time_continue=1255&v=eBbEDRsCmv4에 잘 나와있습니다.


[케라스(keras)] MLP regression 다층퍼셉트론으로 회귀모델 만들기



케라스를 이용해서 다층퍼셉트론으로 Neural Network 회귀 모델을 만들어보겠습니다.


모델링에 쓰인 데이터는 비행기가 이륙할 때의 속도와 무게에 따른 이륙 전 이동 거리입니다.



데이터를 보시면 선형적인 관계가 있다는 것을 알 수 있습니다.

import numpy as np
import matplotlib.pyplot as plt
from keras import models, layers
import tensorflow as tf

우선 Sequential 형태로 레이어를 쌓겠습니다.

def build_model():
model = models.Sequential()
model.add(layers.Dense(2, activation='sigmoid', input_shape=(2,)))
model.add(layers.Dense(1))
optimizer = tf.train.RMSPropOptimizer(0.001)
model.compile(optimizer=optimizer, loss='mse', metrics=['mae', 'mae'])
return model

input_shape이 2인 것은 데이터(x1, x2)가 input node에 순차적으로 들어가기 때문입니다.

activation 함수는 sigmoid를 사용했고, optimizer의 learning rate를 0.001로 맞췄습니다.


그리고 main함수를 작성합니다.


def main():
traincsvdata = np.loadtxt('trainset.csv', unpack=True, delimiter=',', skiprows=1)
num_points = len(traincsvdata[0])
print("points : ", num_points)
train_num_colum = len(traincsvdata)
train_mean = []
train_std = []
for i in range(train_num_colum):
train_mean.append(traincsvdata[i].mean())
train_std.append(traincsvdata[i].std())
traincsvdata[i] -= traincsvdata[i].mean()
traincsvdata[i] /= traincsvdata[i].std()

csv파일을 읽어들이면 300개의 행과 3개의 컬럼을 가진 데이터를 얻을 수 있습니다. 그리고 x1, x2와 y데이터를 표준화 해줍니다.

numpy의 .mean(), std() 함수를 이용해서 순서대로 연산을 합니다. 

# x_data생성
x_data = np.array([traincsvdata[0], traincsvdata[1]])
x_data = np.array(x_data).transpose()
# y_data reshape
y_data = traincsvdata[2]
y_data = np.array(y_data).transpose()

그리고 모델의 input_shape에 맞도록 행렬을 transpose 해줍니다.

model = build_model()
model.fit(x_data, y_data, epochs=2000, batch_size=50, verbose=1, shuffle=True)
w = model.get_weights()

모델을 return받아서 학습을 시작합니다. epochs는 300행짜리 데이터를 2000번 학습시키는 것이고 batch_size는 50행씩 학습시키겠다는 것입니다. verbose는 console에 학습 진행을 보여줍니다. shuffle은 True/False 차이가 없습니다.(시간 의존적 데이터가 아니므로)

그리고 layer별 weight와 bias는 다음과 같습니다.

[array([[-0.94589883,  0.15035586],  [-0.5647819 , 0.96030337]], dtype=float32), array([0.46524414, 0.03646885], dtype=float32), array([[-2.0237916], [ 3.0606623]], dtype=float32), array([-0.3549767], dtype=float32)]


학습을 끝냈으니 test 데이터와 비교해보겠습니다.


test_csv_data = np.loadtxt('testset.csv', unpack=True, delimiter=',', skiprows=1)
test_csv_data2 = np.loadtxt('testset.csv', unpack=True, delimiter=',', skiprows=1)
test_num_colum = len(test_csv_data)

#테스트셋 정규화 진행
for i in range(test_num_colum):
test_csv_data[i] -= train_mean[i]
test_csv_data[i] /= train_std[i]

test_x_data = np.array([test_csv_data[0], test_csv_data[1]])
test_x_data = np.array(test_x_data).transpose()

prediction = model.predict(test_x_data)
prediction *= train_std[2]
prediction += train_mean[2]
plt.plot(range(len(prediction)), prediction, 'k*')
plt.plot(range(len(prediction)), test_csv_data2[2], 'mo')
plt.show()

plot에 띄워 test target 데이터와 비교하려면 표준화 한 값을 원래 스케일로 돌려야합니다. 테스트 셋을 정규화 할 때 trainset의 평균, 표준편차로 정규화 했으므로 원래 스케일로 돌릴때도 같은 숫자를 이용합니다.

순서는 표준편차를 먼저 곱하고 평균을 곱해줘야합니다.


별표는 예측값이고 파란색 점은 실제값입니다. 관계가 단순해서 그런지 나름 잘 맞는 것 같습니다.

사실 모델을 단층으로 만들어도 결과는 잘 나왔습니다.
model.add(layers.Dense(1, input_shape=(2,)))

testset.csv

trainset.csv


데이터를 이용해서 선형으로도 해보시고 optimizer나 activation function도 바꿔보세요 :)



배우는 과정이라 설명이 틀렸을 수 있습니다. 이상이 있으면 댓글 남겨주세요!


도움이 되셨으면 공감 부탁드립니다!

[데이터 시각화] Matplotlib로 3D scatter plot 그리기


trainset.csv


간단한 3D scatter plot을 그려보겠습니다.

정말 간단합니다. 


간단한 설명을 추가하자면 gca는 Get current axes 입니다.

비행기의 이륙 속도, 짐의 무게를 가지고 이륙에 필요한 거리를 계산하는 예제의 시각화 부분입니다.


import matplotlib.pyplot as plt
import numpy as np


fig = plt.figure()
ax = fig.gca(projection='3d')

# Make data.
data = np.loadtxt('./trainset.csv', unpack=True, delimiter=',', skiprows=1)
X = data[0]
Y = data[1]
Z = data[2]

# Plot the surface.

# Customize the z axis.
ax.scatter(X, Y, Z)

ax.set_xlabel('Speed(km/h)')
ax.set_ylabel('Weight(ton)')
ax.set_zlabel('Distance(m)')
plt.suptitle('Takeoff distance prediction', fontsize=16)
plt.show()




데이터는 우측 상단링크로 받으실 수 있습니다.


다음 포스팅에선 신경망(Multi-Layer Perceptron)을 이용하여 비행기 이륙거리 예측을 해보겠습니다. 

+ Recent posts