블로그 이미지
평범하게 살고 싶은 월급쟁이 기술적인 토론 환영합니다.같이 이야기 하고 싶으시면 부담 말고 연락주세요:이메일-bwcho75골뱅이지메일 닷컴. 조대협


Archive»


 

'Machine Learning'에 해당되는 글 39

  1. 2017.11.15 t-SNE를 이용한 차원 감소 (Dimension reduction)
  2. 2017.11.13 차원 감소(Dimension reduction) 와 PCA 분석
  3. 2017.10.20 수학포기자를 위한 딥러닝과 텐서플로우의 이해 (12)
  4. 2017.10.13 클러스터링 #3 - DBSCAN (밀도 기반 클러스터링)
  5. 2017.10.11 클러스터링 #2 - Hierarchical clustering (계층 분석)
  6. 2017.09.27 오토인코더를 이용한 비정상 거래 검출 모델의 구현 #4 - 오토인코더 기반의 신용카드 이상거래 검출코드와 분석 결과
  7. 2017.09.18 오토인코더를 이용한 비정상 거래 검출 모델의 구현 #2 - MNIST 오토 인코더 샘플 (1)
  8. 2017.09.11 오토 인코더를 이용한 비정상 거래 검출 모델의 구현 #1 (1)
  9. 2017.09.10 텐서플로우 하이레벨 API를 Estimator를 이용한 모델 정의 방법
  10. 2017.09.06 텐서플로우 하이레벨 API (1)
  11. 2017.08.21 Tensorflow Object Detection API를 이용한 물체 인식 #2-동물 사진을 학습 시켜보자 (1)
  12. 2017.08.16 Tensorflow Object Detection API를 이용한 물체 인식 #1-설치와 사용하기
  13. 2017.08.10 텐서플로우 트레이닝 데이타 포맷인 *.tfrecord 파일 읽고 쓰기 (1)
  14. 2017.07.20 Wide and deep network 모델 활용하기
  15. 2017.06.19 얼굴 인식 모델을 만들어보자 #3 - 학습된 모델로 예측하기 (2)
  16. 2017.06.15 연예인 얼굴 인식 모델을 만들어보자 - #2. CNN 모델을 만들고 학습시켜 보자 (11)
  17. 2017.06.10 머신러닝 시스템 프로세스와 아키텍쳐 (7)
  18. 2017.05.16 연예인 얼굴 인식 모델을 만들어보자 - #1. 학습 데이타 준비하기 (2)
  19. 2017.04.24 머신러닝 모델 개발 삽질기
  20. 2017.04.10 머신러닝 라벨 데이타 타입에 대해서
 

t-SNE를 이용한 차원 감소


조대협 (http://bcho.tistory.com)


PCA 기반 차원 감소의 문제점

앞의 글에서 차원 감소에 대한 개념과, 차원 감소 알고리즘의 하나인 PCA 알고리즘에 대해서 살펴보았다.

PCA의 경우 선형 분석 방식으로 값을 사상하기 때문에 차원이 감소되면서 군집화 되어 있는 데이타들이 뭉게져서 제대로 구별할 수 없는 문제를 가지고 있다. 아래 그림을 보자


출처 https://www.youtube.com/watch?v=NEaUSP4YerM


이 그림은 2차원에서 1차원으로 PCA 분석을 이용하여 차원을 줄인 예인데, 2차원에서는 파란색과 붉은색이 구별이 되는데, 1차원으로 줄면서 1차원상의 위치가 유사한 바람에, 두 군집의 변별력이 없어져 버렸다.

t-SNE

이런 문제를 해결하기 위한 차원 감소 방법으로는 t-SNE (티스니라고 읽음) 방식이 있는데, 대략적인 원리는 다음과 같다.


먼저 점을 하나 선택한다. 아래는 검정색점을 선택했는데, 이 점에서 부터 다른점까지의 거리를 측정한다.



다음 T 분포 그래프를 이용하여, 검정 점(기준점) 을 T 분포 상의 가운데 위치한다면, 기준점으로부터 상대점 까지 거리에 있는 T 분포의 값을 선택(위의 T 분포 그래프에서 파란점에서 위로 점섬이 올라가서 T분포 그래프상에 붉은 색으로 X 표가 되어 있는 값)하여, 이 값을 친밀도 (Similarity)로 하고, 이 친밀도가 가까운 값끼리 묶는다.


이 경우 PCA 처럼 군집이 중복되지 않는 장점은 있지만, 매번 계산할때 마다 축의 위치가 바뀌어서, 다른 모양으로 나타난다. 단 데이타의 군집성과 같은 특성들은 유지 되기 때문에 시각화를 통한 데이타 분석에는 유용하지만, 매번 값이 바뀌는 특성으로 인하여, 머신러닝 모델의 학습 피쳐로 사용하기는 다소 어려운점이 있다.


아래 그림은 같은 데이타로 t-SNE 분석을 각각 한번씩한 결과를 시각화 해서 표현한 결과 인데, 보는 것과 같이 군집에 대한 특성은 그대로 유지 되지만 값 자체는 변화가 된것을 확인할 수 있다.




sklearn 을 이용한 t-SNE 구현

전체 코드는 https://github.com/bwcho75/dataanalyticsandML/blob/master/dimension%20reduction/2.%20t-SNE%20visualization.ipynb 에 공개되어 있으니 참고하기 바란다.


# Perform the necessary imports
import matplotlib.pyplot as plt
from sklearn.manifold import TSNE

model = TSNE(learning_rate=100)
transformed = model.fit_transform(feature)

xs = transformed[:,0]
ys = transformed[:,1]
plt.scatter(xs,ys,c=labels)

plt.show()


사실 코드가 너무 간단해서 설명할것이 없다. TSNE 객체를 선언하고 학습속도 (learning_rate)를 지정한다음 fit_transform 하면 끝이다. (싸이킷런 만세…)


다음글에서는 차원 감소 방법중에 마지막을 Matrix Factorization (행렬 인수 분해) 방법에 대해서 알아보도록 하겠다.






저작자 표시 비영리
신고


차원 감소와 PCA 분석

조대협 (http://bcho.tistory.com)

차원 감소 (Dimension reduction)

데이타를 분석할때 피쳐가 많으면 데이타 분석이 어렵고, 특히 3개 이상 (3차원)의 피쳐가 존재할 경우 시각화가 어려워진다. 머신러닝의 경우에 학습용 데이타의 피쳐가 많으면, 연산량이 많아지고, 특히 학습을 위해서 더 많은 데이타가 필요해진다. 이렇게 피쳐가 많음 으로써 발생하는 문제를 차원의 저주 (Dimension Curse)라고 이야기 하는데, 이 차원의 수를 줄이는 방법을 Dimension reduction / 차원 감소 방법이라고 한다.

차원 수를 줄인 다는 것은 다른 말로는 피쳐의 수를 줄인다는 말과 같고, 앞에서 언급한 바와 같이 데이타 분석에서는 차원을 줄여서 시각화를 가능하게 해서 데이타 분석을 용이하게 할 수 있다. 데이타 분석에 있어서 여전히 사람의 눈과 직관을 통한 분석은 중요한데, 3차원이 넘어가는 데이타는 시각화가 불가능하다. 그래서 차원을 줄여서 데이타의 특성을 파악할 필요가 있고, 또한 머신러닝에 있어서 학습 데이타의 수를 줄이고, 학습에 필요한 컴퓨팅 파워를 절약하기 위해서 차원 감소는 유용한 기법이 된다.

차원 감소 방식

차원을 감소 시키는 피쳐 선택 (Feature Selection)과 피쳐 추출 (Feature extraction) 두 가지 방식이 있다. 피쳐 선택의 경우는 여러개의 피쳐중에서 데이타의 특성을 가장 잘 나타내는 주요 필드 몇개만을 선택하여 대표 피쳐로 선택하는 방법이다.

예를 들어 [7,1,2],[100,1,3],[92,1,5] 가 있을때, 이 세개의 행렬에서 각 첫번째 열과 세번째 열이 그 변화 폭이 가장 크기 때문에, 첫번째와 세번째 열만을 대표 피쳐로 사용하여 다음과 같이 선택한다. [7,2],[100,3],[92,5] 이렇게 원래 피쳐에서 부분 집합만을 선택하는 방식을 피쳐 선택 방법이라고 한다.


다음은 피쳐 추출 (Feature extraction) 방식이 있는데, 이건 원본 데이타와 전혀 다른 형태의 데이타를 추출해낸다. 예를 들어 [7,1,2] 를 일정 공식에 의해서 [3,4] 등으로 변환하여 특성을 표현하는 방법인데, 이렇게는 이해가 약간 어려우니 PCA 기반의 피쳐 추출 방법에 대해서 알아보도록 하자


PCA

PCA 분석

다음과 같은 데이타가 있다고 하자.


PCA 분석에서는 데이타의 변화의 폭이 가장 큰 축을 정하고, 그 다음 그와 직교하는 축을 구한다


그리고 데이타의 중심점에 축을 위치 시켜서 0,0을 중심으로 데이타가 양쪽으로 균등하게 퍼지도록 분포를 시켜서 축을 뒤틀어서 아래와 같이 원래의 데이타를 변화 시킨다.


이렇게 PCA 분석을 하면, 데이타의 중심축을 0,0으로 위치 시킬 수 있고, 가장 데이타의 변화의 폭이 큰 순으로 X,Y축등을 지정하여 데이타를 볼 수 있다.

PCA를 이용한 차원의 감소

그러면 PCA 분석을 이용하여 차원을 어떻게 감소 시키는가?

PCA 분석을 하더라도 단순히 축을 틀어버린것이기 때문에 차원의 수는 줄어들지 않는다. PCA 분석을 하면, 각 피쳐 (축) 별로, 값의 변화도 (Variance : 해당 축의 값이 얼마나 크게 변하는가)를 볼 수 있는데, 다음은 PCA Variance 값의 예제이다.



그래프에서 보는것과 같이 0번 피쳐의 경우 Variance가 매우 심하고, 1,2는 상대적으로 많이 약한것을 볼 수 있다. 그래서 0만 피쳐로 사용하거나 또는 0,1만 피쳐로 사용하더라도 데이타 특징의 대부분을 나타낼 수 있다.

앞의 예제 데이타에서 2차원 데이타를  PCA 분석을 해서 첫번째 피쳐가 Variance가 가장 높다고 했을 때 이를 변환하면 다음과 같이 PCA  변환된 데이타의 X축의 값만을 사용하도록 해서 2차원을 1차원으로 줄일 수 있다.




물론 차원을 줄이면, 원래 데이타가 가지고 있는 특징이 다소 사라지는 단점이 있지만, 전체적인 데이타의 특성을 파악하는 대세에는 큰 영향이 없기 때문에, 더 장점이 많다.

Sklearn을 이용한 PCA 분석과 차원 감소

그러면 이를 파이썬 sklearn 라이브러리로 구현해보자. 여기서 사용할 데이타는 IRIS 데이타를 샘플 데이타로 사용하였다. 이 예제에서는 3차원인 IRIS 데이타를 PCA 분석을 통해서 2차원으로 줄여보도록 하겠다.

원본 데이타를 생성하고 시각화 하는 코드는 다음과 같다.


from sklearn import datasets
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import pandas as pd
iris = datasets.load_iris()

labels = pd.DataFrame(iris.target)
labels.columns=['labels']
data = pd.DataFrame(iris.data,columns=['Sepal length','Sepal width','Petal length','Petal width'])

fig = plt.figure( figsize=(6,6))
ax = Axes3D(fig, rect=[0, 0, .95, 1], elev=48, azim=134)
ax.scatter(data['Sepal length'],data['Sepal width'],data['Petal length'],c=labels,alpha=0.5)
ax.set_xlabel('Sepal lenth')
ax.set_ylabel('Sepal width')
ax.set_zlabel('Petal length')
plt.show()




PCA 분석을 통해서, 각 피쳐별 Variance를 분석하는 코드는 다음과 같다.


from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import make_pipeline
import matplotlib.pyplot as plt

# Create scaler: scaler
scaler = StandardScaler()

# Create a PCA instance: pca
pca = PCA()

# Create pipeline: pipeline
pipeline = make_pipeline(scaler,pca)

# Fit the pipeline to 'samples'
pipeline.fit(data)

features = range(pca.n_components_)
plt.bar(features, pca.explained_variance_)
plt.xlabel('PCA feature')
plt.ylabel('variance')
plt.xticks(features)
plt.show()


분석을 해보면 PCA 분석에 의해서 변환된 피쳐 0,1의 Variation이 큰것을 확인할 수 있다.



그래서 PCA 변환된 피쳐중 0,1번 피쳐만 사용해서 시각화를 해보면 다음과 같다.


from sklearn.decomposition import PCA
import matplotlib.pyplot as plt

model = PCA(n_components=2)
pca_features = model.fit_transform(data)

xf = pca_features[:,0]
yf = pca_features[:,1]
plt.scatter(xf,yf,c=labels);
plt.show();


그림처럼 2차원으로 줄여도 IRIS 군집화의 특성이 어느정도 남아 있는 것을 확인할 수 있다.


다음은 1차원으로 줄여서 시각화를 한 예인데


from sklearn.decomposition import PCA
import matplotlib.pyplot as plt

model = PCA(n_components=1)
pca_features = model.fit_transform(data)

xf = pca_features[:,0]
yf = len(xf)*[0]
plt.scatter(xf,yf,c=labels);
plt.show();



2차원에 비해서 -1~4사이에 분포된 두개의 클래스 (녹색과 노랑색)이 다소 겹치는 부분이 있지만, 전체적으로 봤을때 1차원으로 변환해도 어느정도 분류 특성을 유지하고 있는 것을 볼 수 있다.


이런 중첩 현상을 줄여주는 차원 감소 기법으로는 t-SNE라는 방법이 있는데, 이는 다음글에서 설명하도록 하겠다.


저작자 표시 비영리
신고


글은 제가 텐서플로우와 딥러닝을 공부하면서 블로그에 메모해놨던 내용을 모아놓은 글입니다.

혼자 공부하면서 어려웠던 점도 있었기 때문에, 저처럼 텐서플로우와 딥러닝을 공부하시는 분들께 도움이 되고자 자료를 공개합니다.

텐서플로우 초기버전부터 작성하였기 때문에, 다소 코드가 안맞는 부분이 있을 있으니 양해 부탁드리며, 글은 개인이 스터디용으로 자유롭게 사용하실 있으며, 단체나 기타 상용 목적으로 사용은 금지 됩니다.


머신러닝 이북-수포자를 위한 머신러닝.pdf.zip


혹시 이 교재로 공부하시다가 잘못된 부분을 수정하셨으면 다른분들을 위해서 친절하게 댓글을 달아주시면 감사하겠습니다.


그리고 오프라인 스터디 그룹을 진행하시는 분들을 위해서 지원을 해드립니다.

  • 발표용 프리젠테이션 파일
  • 실습 자료
  • 온라인 실습용 https://google.qwiklabs.com/catalog 토큰
스터디 지원을 위해서는 
1. https://www.facebook.com/groups/googlecloudkorea/ 구글 클라우드 사용자 그룹에 가입 하신후
2. https://www.meetup.com/GDG-Cloud-Korea 에 가입하신 후에, 스터디 모임을 매주 진행하실때 마다 밋업을 여시면 됩니다.
그후에, 저한테 페이스북으로 연락 주시면 https://www.facebook.com/terry.cho.7 제가 자료와 함께 실습 토큰 (무료 크레딧)을 제공해 드립니다.


저작자 표시 비영리
신고

DBSCAN (밀도 기반 클러스터링)


조대협(http://bcho.tistory.com)

기본 개념

이번에는 클러스터링 알고리즘중 밀도 방식의 클러스터링을 사용하는 DBSCAN(Density-based spatial clustering of applications with noise) 에 대해서 알아보도록 한다.

앞에서 설명한 K Means나 Hierarchical 클러스터링의 경우 군집간의 거리를 이용하여 클러스터링을 하는 방법인데, 밀도 기반의 클러스터링은 점이 세밀하게 몰려 있어서 밀도가 높은 부분을 클러스터링 하는 방식이다.

쉽게 설명하면, 어느점을 기준으로 반경 x내에 점이 n개 이상 있으면 하나의 군집으로 인식하는 방식이다.


그러면 조금 더 구체적인 개념과 용어를 이해해보자

먼저 점 p가 있다고 할때, 점 p에서 부터 거리 e (epsilon)내에 점이 m(minPts) 개 있으면 하나의 군집으로 인식한다고 하자. 이 조건 즉 거리 e 내에 점 m개를 가지고 있는 점 p를 core point (중심점) 이라고 한다.

DBSCAN 알고리즘을 사용하려면 기준점 부터의 거리 epsilon값과, 이 반경내에 있는 점의 수 minPts를 인자로 전달해야 한다.


아래 그림에서 minPts = 4 라고 하면, 파란점 P를 중심으로 반경 epsilon 내에 점이 4개 이상 있으면 하나의 군집으로 판단할 수 있는데, 아래 그림은 점이 5개가 있기 때문에 하나의 군집으로 판단이 되고, P는 core point가 된다.



아래 그림에서 회색점 P2의 경우 점 P2를 기반으로 epsilon 반경내의 점이 3개 이기 때문에, minPts=4에 미치지 못하기 때문에, 군집의 중심이 되는 core point는 되지 못하지만, 앞의 점 P를 core point로 하는 군집에는 속하기 때문에 이를 boder point (경계점)이라고 한다.



아래 그림에서 P3는 epsilon 반경내에 점 4개를 가지고 있기 때문에 core point가 된다.



그런데 P3를 중심으로 하는 반경내에 다른 core point P가 포함이 되어 있는데, 이 경우 core point P와  P3는 연결되어 있다고 하고 하나의 군집으로 묶이게 된다.


마지막으로 아래 그림의 P4는 어떤 점을 중심으로 하더라도 minPts=4를 만족하는 범위에 포함이 되지 않는다. 즉 어느 군집에도 속하지 않는 outlier가 되는데, 이를 noise point라고 한다.


이를 모두 정리해보면 다음과 같은 그림이 나온다.


정리해서 이야기 하면, 점을 중심으로 epsilon 반경내에 minPts 이상수의 점이 있으면 그 점을 중심으로 군집이 되고 그 점을 core point라고 한다. Core point 가 서로 다른 core point의 군집의 일부가 되면 그 군집을 서로 연결되어 있다고 하고 하나의 군집으로 연결을 한다.

군집에는 속하지만, 스스로 core point가 안되는 점을 border point라고 하고, 주로 클러스터의 외곽을 이루는 점이 된다.

그리고 어느 클러스터에도 속하지 않는 점은 Noise point가 된다.

장점

DBSCAN 알고리즘의 장점은

  • K Means와 같이 클러스터의 수를 정하지 않아도 되며,

  • 클러스터의 밀도에 따라서 클러스터를 서로 연결하기 때문에 기하학적인 모양을 갖는 군집도 잘 찾을 수 있으며


    기하학적인 구조를 군집화한 예 (출처 : https://en.wikipedia.org/wiki/DBSCAN )

  • Noise point를 통하여, outlier 검출이 가능하다.

예제 코드

코드의 내용은 앞과 거의 유사하다.


model = DBSCAN(eps=0.3,min_samples=6)


모델 부분만 DBSCAN으로 바꿔 주고, epsilon 값은 eps에 minPts값은 min_samples 인자로 넘겨주면 된다. 이 예제에서는 각각 0.3 과 6을 주었다.


전체 코드를 보면 다음과 같다.


import pandas as pd
iris = datasets.load_iris()

labels = pd.DataFrame(iris.target)
labels.columns=['labels']
data = pd.DataFrame(iris.data)
data.columns=['Sepal length','Sepal width','Petal length','Petal width']
data = pd.concat([data,labels],axis=1)

data.head()



IRIS 데이타를 DataFrame으로 로딩 한 다음, 학습에 사용할 피쳐를 다음과 같이 feature 변수에 저장한다.


feature = data[ ['Sepal length','Sepal width','Petal length','Petal width']]
feature.head()


다음은 모델을 선언하고, 데이타를 넣어서 학습을 시킨다.


from sklearn.cluster import DBSCAN
import matplotlib.pyplot  as plt
import seaborn as sns

# create model and prediction
model = DBSCAN(min_samples=6)
predict = pd.DataFrame(model.fit_predict(feature))
predict.columns=['predict']

# concatenate labels to df as a new column
r = pd.concat([feature,predict],axis=1)


다음은 모델을 선언하고, 데이타를 넣어서 학습을 시킨다.

학습이 끝난 결과를 다음과 같이 3차원 그래프로 시각화 해보자. 아래 시각화는 3차원인데, 학습은 4차원으로 하였다. 그래서 다소 오류가 있어 보일 수 있다. 다차원 데이타를 시각화 하기위해서는 PCA나 t-SNE와 같은 차원 감소 (dimensional reduction) 기법을 사용해야 하는데,  이는 다음 글에서 다루도록한다.


from mpl_toolkits.mplot3d import Axes3D
# scatter plot
fig = plt.figure( figsize=(6,6))
ax = Axes3D(fig, rect=[0, 0, .95, 1], elev=48, azim=134)
ax.scatter(r['Sepal length'],r['Sepal width'],r['Petal length'],c=r['predict'],alpha=0.5)
ax.set_xlabel('Sepal lenth')
ax.set_ylabel('Sepal width')
ax.set_zlabel('Petal length')
plt.show()







마지막으로 Cross tabulazation 을 이용하여 모델을 검증해보면 다음과 같은 결과를 얻을 수 있다.

ct = pd.crosstab(data['labels'],r['predict'])
print (ct)



이 코드에 대한 전체 내용은 https://github.com/bwcho75/dataanalyticsandML/blob/master/Clustering/5.%20DBSCANClustering-IRIS%204%20feature-Copy1.ipynb 에서 확인할 수 있다.

저작자 표시 비영리
신고

Hierarchical clustering을 이용한 데이타 군집화


조대협 (http://bcho.tistory.com)


Hierarchical clustering (한글 : 계층적 군집 분석) 은 비슷한 군집끼리 묶어 가면서 최종 적으로는 하나의 케이스가 될때까지 군집을 묶는 클러스터링 알고리즘이다.

군집간의 거리를 기반으로 클러스터링을 하는 알고리즘이며, K Means와는 다르게 군집의 수를 미리 정해주지 않아도 된다. 참고로 이 글에서 사용된 예제 코드는 https://github.com/bwcho75/dataanalyticsandML/blob/master/Clustering/3.%20Hierarchical%20clustering-IRIS%204%20feature.ipynb 에 저장되어 있다.


예를 들어서 설명해보자

“진돗개,세퍼드,요크셔테리어,푸들, 물소, 젖소" 를 계층적 군집 분석을 하게 되면

첫번째는 중형견, 소형견, 소와 같은 군집으로 3개의 군집으로 묶일 수 있다.


이를 한번 더 군집화 하게 되면 [진돗개,셰퍼드] 와 [요크셔테리어,푸들] 군집은 하나의 군집(개)로 묶일 수 있다.


마지막으로 한번 더 군집화를 하게 되면 전체가 한군집(동물)으로 묶이게 된다.


이렇게 단계별로 계층을 따라가면서 군집을 하는 것을 계층적 군집 분석이라고 한다.

계층적 군집 분석은 Dendrogram이라는 그래프를 이용하면 손쉽게 시각화 할 수 있다.





계층형 군집화에 대한 좀 더 상세한 개념은 https://www.slideshare.net/pierluca.lanzi/dmtm-lecture-12-hierarchical-clustering?qid=94d8b25a-8cfa-421c-9ed5-03c0b33c29fb&v=&b=&from_search=1 를 보면 잘 나와 있다.


skLearn을 이용한 계층 분석 모델 구현

개념을 잡았으면 실제로 계층 분석 모델을 구현해보자.

데이타는 K Means에서 사용했던 IRIS 데이타를 똑같이 사용한다.

이번에는 4개의 피쳐를 이용해서 사용한다.


from sklearn import datasets
import pandas as pd
iris = datasets.load_iris()

labels = pd.DataFrame(iris.target)
labels.columns=['labels']
data = pd.DataFrame(iris.data)
data.columns=['Sepal length','Sepal width','Petal length','Petal width']
data = pd.concat([data,labels],axis=1)


다음은 IRIS 데이타를 이용하여 dendrogram을 그려보자

# Perform the necessary imports
from scipy.cluster.hierarchy import linkage, dendrogram
import matplotlib.pyplot as plt

# Calculate the linkage: mergings
mergings = linkage(data,method='complete')

# Plot the dendrogram, using varieties as labels
plt.figure(figsize=(40,20))
dendrogram(mergings,
          labels = labels.as_matrix(columns=['labels']),
          leaf_rotation=90,
          leaf_font_size=20,
)
plt.show()


먼저 linkage 함수를 import 한 다음 linkage 함수에 data를 넘겨주면 Hierarchical clustering을 수행한다. 이때 method=’complete’로 정했는데, 이 부분은 뒤에서 설명한다.

Hierarchical clustering 한 결과를 dendrogram 함수를 이용하여 dendrogram 그래프를 표현해 보면 다음과 같이 출력된다.




계층 분석 방식

앞의 코드에서, linkage 함수에서 method 를 사용했다. 이에 대해서 알아보자.

Hierachical clustering의 기본 원리는 두 클러스터 사이의 거리를 측정해서 거리가 가까운 클러스터끼리 묶는 방식이다.  그러면 두 클러스터의 거리를 측정할때 어디를 기준점으로 할것인가를 결정해야 하는데 다음 그림을 보자.



출처 : https://www.multid.se/genex/onlinehelp/hs515.htm


앞의 코드에서 사용한 complete linkage 방식은 두 클러스터상에서 가장 먼 거리를 이용해서 측정하는 방식이고 반대로  single linkage 방식은 두 클러스터에서 가장 가까운 거리를 사용하는 방식이다.

average linkage 방식은 각 클러스터내의 각 점에서 다른 클러스터내의 모든 점사이의 거리에 대한 평균을 사용하는 방식이다.


이 linkage 방식에 따라서 군집이 되는 모양이 다르기 때문에, 데이타의 분포에 따라서 적절한 linkage  방식을 변화 시켜가면서 적용해가는 것이 좋다.


계층 분석을 통한 군집의 결정

계층 분석은 최종적으로 1개의 군집으로 모든 데이타를 클러스터링 하는데, 그렇다면 n개의 군집으로 나누려면 어떻게 해야 하는가?

아래 dendrogram을 보자 y축이 각 클러스터간의 거리를 나타내는데, 위로 올라갈 수 록 클러스터가 병합되는 것을 볼 수 있다.




즉 적정 y 값에서 클러스터링을 멈추면 n개의 군집 까지만 클러스터링이 되는데, 위의 그림은 y 값을 3에서 클러스터링을 멈춰서 총 3개의 클러스터로 구분을 한 결과이다.


이렇게 계층형 분석에서 sklearn을 사용할 경우 fcluster 함수를 이용하면, 특정 y값에서 클러스터링을 멈출 수 있다. 다음 코드를 보자.


from scipy.cluster.hierarchy import fcluster

predict = pd.DataFrame(fcluster(mergings,3,criterion='distance'))
predict.columns=['predict']
ct = pd.crosstab(predict['predict'],labels['labels'])
print(ct)


앞의 코드에서 계층형 클러스터링을 한 mergings 변수를 fcluster 함수에 전달하고 두번째 인자에 y의 임계값을 3으로 지정하였다. Predict 컬럼에는 원본 입력데이타에 대한 예측 결과 (어느 클러스터에 속해있는지를 0,1,2로 입력 데이타의 수만큼 리턴한다.)를 리턴한다.


이를 원본 데이타의 라벨인 labels[‘label’]값과 Cross tabulation 분석을 해보았다.




세로축이 예측 결과, 가로측이 원래 값이다.

원래 label이 0인 데이타와 1인 데이타는 각각 잘 분류가 되었고, 2인 데이타는 34개만 정확하게 분류가 되었고 16개는 원본 레이블이 1인 데이타로 분류가 되었다.


지금까지 Hierachical clustering model에 대해서 알아보았다. K Means와 같은 군집화 모델이라도 내부 알고리즘에 따라서 군집화 결과가 다르기 때문에, 샘플 데이타의 분포를 보고 적절한 클러스터링 모델을 고르는 것이 필요하다. 다행이 sklearn의 경우 복잡한 수식 이해 없이도 간단한 라이브러리 형태로 다양한 클러스터링 모델 사용할 수 있도록 해놨기 때문에, 여러 모델을 적용해가면서 적정한 데이타 분류 방식을 찾아보는 것이 어떨까 한다.




저작자 표시 비영리
신고

오토인코더를 이용한 비정상 거래 검출 모델 구현 #4

신용카드 이상 거래 감지 코드


조대협 (http://bcho.tistory.com)


구현코드


전체 모델 코드는 https://github.com/bwcho75/tensorflowML/blob/master/autoencoder/creditcard_fraud_detection/3.model.ipynb 에 있다.


코드는 http://bcho.tistory.com/1198 에 설명한 MNIST 데이타를 이용한 오토인코더 모델과 다르지 않다. 차이는 데이타 피딩을 784개의 피쳐에서 28개의 피쳐로만 변환하였고, 데이타를 MNIST 데이타셋에서 CSV에서 읽는 부분만 변경이 되었기 때문에 쉽게 이해할 수 있으리라 본다.


학습 및 예측 결과

모델을 만들고 학습을 한후에, 이상 거래를 검출해봤다. 학습은

creditcard_validation.csv에 총 57108개의 거래로그가 저장되어 있었고, 그중에, 246개가 비정상 거래였다.

네트워크는 28,20,10,7,10,20,28 형태의 네트워크를 사용하였다.

입출력 값의 차이가 큰것을 기준으로 이 값이 어느 임계치 수준 이상이면 비정상 거래로 검출하도록 하고 실험을 해본 결과

다음과 같은 결과를 얻었다.


임계치

검출된 비정상 거래수

정상거래인데 비정상 거래로 검출된 거래

1.1

112

1

1.0

114

5

0.9

117

7

0.8

124

22


대략 검출 비율은 112~120 개 내외로 / 246개 중에서 50%가 안된다.

검출된 거래가 이상 거래인지 아닌지 여부는 대략 90% 이상이 된다.


결론

네트워크를 튜닝하고나 학습 시키는 피쳐를 변형 시키면 예상하건데, 50% 보다 높은 70~80%의 이상 거래는 검출할 수 있을 것으로 보인다.


그러나 이번 케이스의 경우는 비정상 거래가 레이블링이 되어 있었기 때문에 이런 실험이 가능했지만, 일반적인 이상 거래 검출의 경우에는 레이블링되어 있는 비정상 거래를 얻기 힘들다. 그래서 오토인코더를 통해서 전체 데이타를 학습 시킨후에, 각 트렌젝션이나 그룹별(사용자나 쇼핑몰의 경우 판매자등)로 오토인코더를 통해서 VALIDATION을 한후, 입출력값의 차이가 큰것의 경우에는 비정상 거래일 가능성이 매우 높기 때문에, 입출력값이 차이가 큰것 부터 데이타 탐색을 통하여 이상 거래 패턴을 찾아내고, 이를 통해서 임계치를 조정하여, 이상거래를 지속적으로 검출할 수 있도록 한후에, 이상 거래에 대한 데이타가 어느정도 수집되면 DNN등의 지도 학습 모델을 구축하여 이상 거래를 자동으로 검출할 수 있는 시스템으로 전환하는 단계를 거치는 방법이 더 현실적인 방법이 아닐까 한다.


저작자 표시 비영리
신고

오토인코더를 이용한 비정상 거래 검출 모델의 구현 #2

MNIST 오토인코더 샘플


조대협 (http://bcho.tistory.com)


신용카드 이상 거래 감지 시스템 구현에 앞서서, 먼저 오토인코더에 대한 이해를 하기 위해서 오토 인코더를 구현해보자. 오토 인코더 샘플 구현은 MNIST 데이타를 이용하여 학습하고 복원하는 코드를 만들어 보겠다.


이 코드의 원본은 Etsuji Nakai 님의 https://github.com/enakai00/autoencoder_example 코드를 사용하였다.


데이타 전처리

이 예제에서는 텐서플로우에 포함된 MNIST 데이타 tensorflow.contrib.learn.python.learn.datasets    tfrecord 로 변경해서 사용한다.TFRecord에 대한 설명은 http://bcho.tistory.com/1190 를 참고하기 바란다.

MNIST 데이타를 TFRecord로 변경하는 코드는 https://github.com/bwcho75/tensorflowML/blob/master/LAB5-Create-MNIST-TFRecord-Data.ipynb 에 있다. 이 코드를 실행하면, ./data/train.tfrecord ./data/test.tfrecords 에 학습 및 테스트 데이타 파일이 생성된다. 이 파일들을 아래서 만들 모델이 들어가 있는 디렉토리 아래 /data 디렉토리로 옮겨놓자.

학습 코드 구현

학습에 사용되는 모델은 텐서플로우 하이레벨 API인 tf.layers와 Estimator를 이용해서 구현한다.

하이레벨 API를 사용하는 이유는 http://bcho.tistory.com/1195 http://bcho.tistory.com/1196 에서도 설명했듯이 구현이 상대적으로 쉬울뿐더러, 분산 학습이 가능하기 때문이다.


전체 코드는 hhttps://github.com/bwcho75/tensorflowML/blob/master/LAB5-Autoencoder-MNIST-Estimator.ipynb 에 공유되어 있다.

데이타 입력부

데이타 입력 부분은 tfrecord 파일을 읽어서, 파일 큐를 생성해서 input_fn 을 생성하는 부분이다. 이렇게 생성된 input_fn 함수는 Estimator 를 통해서, 학습과 테스트(검증) 데이타로 피딩되게 된다.


데이타 입력 부분은 read_and_decode함수와 input_fn 함수로 구현되어 있는데, 각각을 살펴보자

def read_and_decode(filename_queue):
   reader = tf.TFRecordReader()
   _,serialized_example = reader.read(filename_queue)
   
   features = tf.parse_single_example(
       serialized_example,
       features={
           'image_raw':tf.FixedLenFeature([],tf.string),
           'label':tf.FixedLenFeature([],tf.int64),
       })
   
   image = tf.decode_raw(features['image_raw'],tf.uint8)
   image.set_shape([784]) #image shape is (784,)
   image = tf.cast(image,tf.float32)*(1.0/255)
   label = tf.cast(features['label'],tf.int32)
   
   return image,label


read_and_decode 함수는 filename_queue에서, 파일을 읽어서 순서대로 TFRecoderReader를 읽어서 파싱한후에, image_raw이름으로 된 피쳐와,  label로 된 피쳐를 읽어서 각각 image와 label 이라는 텐서에 저장한다.

image는 차원을 맞추기 위해서 set_shape를 이용하여 1차원으로 784의 길이를 가진 텐서로 변환하고, 학습에 적절하도록 데이타를 regulization 을 하기 위해서, 1.0/255 를 곱해줘서 1~255값의 칼라값을 0~1사이의 값으로 변환한다.

그리고 label값은 0~9를 나타내는 숫자 라벨이기 때문에, tf.int32로 형 변환을 한다.

변환이 끝난 image와 label 텐서를 리턴한다.


def input_fn(filename,batch_size=100):
   filename_queue = tf.train.string_input_producer([filename])
   
   image,label = read_and_decode(filename_queue)
   images,labels = tf.train.batch(
       [image,label],batch_size=batch_size,
       capacity=1000+3*batch_size)
   #images : (100,784), labels : (100,1)
   
   return {'inputs':images},labels

Input_fn 함수는 실제로 Estimator에 값을 피딩하는 함수로, 입력 받은 filename으로 파일이름 큐를 만들어서 read_and_decode 함수에 전달 한 후, image와 label 값을 리턴받는다.

리턴 받은 값을 바로 리턴하지 않고 배치 학습을 위해서 tf.train.batch를 이용하여 배치 사이즈(batch_size)만큼 묶어서 리턴한다.

모델 구현부

데이타 입력 부분이 완성되었으면, 데이타를 읽어서 학습 하는 부분을 살펴보자.


모델 구현

아래는 모델을 구현한 autoecndoer_model_fn 함수이다.

Custom Estimator를 구현하기 위해서 사용한 구조이다.


def autoencoder_model_fn(features,labels,mode):
   input_layer = features['inputs']
   dense1 = tf.layers.dense(inputs=input_layer,units=256,activation=tf.nn.relu)
   dense2 = tf.layers.dense(inputs=dense1,units=128,activation=tf.nn.relu)
   dense3 = tf.layers.dense(inputs=dense2,units=16,activation=tf.nn.relu)
   dense4 = tf.layers.dense(inputs=dense3,units=128,activation=tf.nn.relu)
   dense5 = tf.layers.dense(inputs=dense4,units=256,activation=tf.nn.relu)
   output_layer = tf.layers.dense(inputs=dense5,units=784,activation=tf.nn.sigmoid)
   
   #training and evaluation mode
   if mode in (Modes.TRAIN,Modes.EVAL):
       global_step = tf.contrib.framework.get_or_create_global_step()
       label_indices = tf.cast(labels,tf.int32)
       loss = tf.reduce_sum(tf.square(output_layer - input_layer))
       tf.summary.scalar('OptimizeLoss',loss)

       if mode == Modes.TRAIN:
           optimizer = tf.train.AdamOptimizer(learning_rate=0.001)
           train_op = optimizer.minimize(loss,global_step=global_step)
           return tf.estimator.EstimatorSpec(mode,loss = loss, train_op = train_op)
       if mode == Modes.EVAL:
           eval_metric_ops = None
           return tf.estimator.EstimatorSpec(
               mode,loss=loss,eval_metric_ops = eval_metric_ops)
       
   # prediction mode
   if mode == Modes.PREDICT:
       predictions={
           'outputs':output_layer
       }
       export_outputs={
           'outputs':tf.estimator.export.PredictOutput(predictions)
       }
       return tf.estimator.EstimatorSpec(
           mode,predictions=predictions,export_outputs=export_outputs) #이부분 코드 상세 조사할것


오토인코더 네트워크를 구현하기 위한 코드는 다음 부분으로 복잡하지 않다

   input_layer = features['inputs']
   dense1 = tf.layers.dense(inputs=input_layer,units=256,activation=tf.nn.relu)
   dense2 = tf.layers.dense(inputs=dense1,units=128,activation=tf.nn.relu)
   dense3 = tf.layers.dense(inputs=dense2,units=16,activation=tf.nn.relu)
   dense4 = tf.layers.dense(inputs=dense3,units=128,activation=tf.nn.relu)
   dense5 = tf.layers.dense(inputs=dense4,units=256,activation=tf.nn.relu)
   output_layer = tf.layers.dense(inputs=dense5,units=784,activation=tf.nn.sigmoid)


input_fn에서 피딩 받은 데이타를 input_layer로 받아서, 각 256,128,16,128,,256의 노드로 되어 있는  5개의 네트워크를 통과한 후에, 최종적으로 784의 아웃풋과  sigmoid 함수를 활성화(activation function)으로 가지는 output layer를 거쳐서 나온다.


다음 모델의 모드 즉 학습, 평가, 그리고 예측 모드에 따라서 loss 함수나 train_op 등이 다르게 정해진다.

  #training and evaluation mode
   if mode in (Modes.TRAIN,Modes.EVAL):
       global_step = tf.contrib.framework.get_or_create_global_step()
       label_indices = tf.cast(labels,tf.int32)
       loss = tf.reduce_sum(tf.square(output_layer - input_layer))
       tf.summary.scalar('OptimizeLoss',loss)


학습과 테스트 모드일 경우, global_step을 정하고, loss 함수를 정의한다.

학습 모드일 경우에는 아래와 같이 옵티마이저를 정하고,이 옵티마이저를 이용하여 loss 값을 최적화 하도록 하는 train_op를 정의해서 EstimatorSpec을 만들어서 리턴하였다.


      if mode == Modes.TRAIN:
           optimizer = tf.train.AdamOptimizer(learning_rate=0.001)
           train_op = optimizer.minimize(loss,global_step=global_step)
           return tf.estimator.EstimatorSpec(mode,loss = loss, train_op = train_op)


테스트 모드 일 경우에는 옵티마이즈할 필요가 없기 때문에, 옵티마이져를 정의하지 않고 loss 값을 리턴하고, 평가를 위한 Evalutaion metrics를 정해서 리턴한다. 아래 코드는 별도로 evaluation metrics 를 정의하지 않고, 디폴트 메트릭스를 사용하였다.


      if mode == Modes.EVAL:
           eval_metric_ops = None
           return tf.estimator.EstimatorSpec(
               mode,loss=loss,eval_metric_ops = eval_metric_ops)


예측 모드일 경우에는 loss 값이나 optimizer 등의 정의가 필요 없고, output값을 어떤 값을 내보낼지만 정의하면 되고, 예측 모델 (prediction model)을 프로토콜 버퍼 포맷으로 export 할때의 구조를 정의하기 위해서 export_outpus 부분만 아래와 같이 정의해주면 된다.


  # prediction mode
   if mode == Modes.PREDICT:
       predictions={
           'outputs':output_layer
       }
       export_outputs={
           'outputs':tf.estimator.export.PredictOutput(predictions)
       }
       return tf.estimator.EstimatorSpec(
           mode,predictions=predictions,export_outputs=export_outputs)

Estimator 생성

모델에 대한 정의가 끝났으면, Estimator를 생성하는데, Estimator 정의는 아래와 같이 앞에서 정의한 모델인 autoencoder_model_fn을 정의해주고

def build_estimator(model_dir):
   return tf.estimator.Estimator(
       model_fn = autoencoder_model_fn,
       model_dir = model_dir,
       config=tf.contrib.learn.RunConfig(save_checkpoints_secs=180))


실험 (Experiment) 구현

앞에서 구현된 Estimator를 이용하여, 학습과 테스트를 진행할 수 있는데, 직접 Estimator를 불러사용하는 방법 이외에 Experiment 라는 클래스를 사용하면, 이 부분을 단순화 할 수 있다.

Experiment에는 사용하고자 하는  Estimator와 학습과 테스트용 데이타 셋, 그리고 export 전략 및, 학습,테스트 스탭을 넣어주면 자동으로 Estimator를 이용하여 학습과 테스트를 진행해준다.

아래는 Experiment 를 구현한 예이다.


def generate_experiment_fn(data_dir,
                         train_batch_size = 100,
                         eval_batch_size = 100,
                         train_steps = 1000,
                         eval_steps = 1,
                         **experiment_args):
   def _experiment_fn(output_dir):
       return Experiment(
           build_estimator(output_dir),
           train_input_fn=get_input_fn('./data/train.tfrecords',batch_size=train_batch_size),
           eval_input_fn=get_input_fn('./data/test.tfrecords',batch_size=eval_batch_size),
           export_strategies = [saved_model_export_utils.make_export_strategy(
               serving_input_fn,
               default_output_alternative_key=None,
               exports_to_keep=1)
           ],
           train_steps = train_steps,
           eval_steps = eval_steps,
           **experiment_args
       )
   return _experiment_fn



learn_runner.run(
   generate_experiment_fn(
       data_dir='./data/',
       train_steps=2000),
   OUTDIR)


대략 50,000 스탭까지 학습을 진행하면 loss 값 500 정도로 수렴 되는 것을 확인할 수 있다.

검증 코드 구현

검증 코드는 MNIST 데이타에서 테스트용 데이타를 로딩하여 테스트 이미지를 앞에서 학습된 이미지로 인코딩했다가 디코딩 하는 예제이다. 입력 이미지와 출력 이미지가 비슷할 수 록 제대로 학습된것이라고 볼수 있다.

Export 된 모듈 로딩

아래 코드는 앞의 학습과정에서 Export 된 학습된 모델을 로딩하여 새롭게 그래프를 로딩 하는 코드이다.


#reset graph
tf.reset_default_graph()

export_dir = OUTDIR+'/export/Servo/'
timestamp = os.listdir(export_dir)[0]
export_dir = export_dir + timestamp
print(export_dir)

sess = tf.Session()
meta_graph = tf.saved_model.loader.load(sess,[tf.saved_model.tag_constants.SERVING],export_dir)
model_signature = meta_graph.signature_def['serving_default']
input_signature = model_signature.inputs
output_signature = model_signature.outputs

print(input_signature.keys())
print(output_signature.keys())


tf.reset_default_graph()를 이용하여, 그래프를 리셋 한후, tf.save_model.loader.load()를 이용하여 export_dir에서 Export 된 파일을 읽어서 로딩한다.

다음 입력값과 출력값의 텐서 이름을 알기 위해서 model_signature.input과 output 시그니쳐를 읽어낸후 각각 keys()를 이용하여 입력과 출력 텐서 이름을 출력하였다.

이 텐서 이름은 로딩된 그래프에 입력을 넣고 출력 값을 뽑을 때 사용하게 된다.

테스트 코드 구현

학습된 모델이 로딩 되었으면 로딩된 모델을 이용하여 MNIST 테스트 데이타를 오토 인코더에 넣어서 예측을 진행 해본다.


from tensorflow.examples.tutorials.mnist import input_data

mnist = input_data.read_data_sets("/tmp/data/", one_hot=True)
images, labels = mnist.test.images, mnist.test.labels

feed_dict = {sess.graph.get_tensor_by_name(input_signature['inputs'].name): mnist.test.images[:10]}
output = sess.graph.get_tensor_by_name(output_signature['outputs'].name)
results = sess.run(output, feed_dict=feed_dict)

fig = plt.figure(figsize=(4,15))
for i in range(10):
       subplot = fig.add_subplot(10,2,i*2+1)
       subplot.set_xticks([])
       subplot.set_yticks([])
       subplot.imshow(images[i].reshape((28,28)), vmin=0, vmax=1,
                      cmap=plt.cm.gray_r, interpolation="nearest")
       
       subplot = fig.add_subplot(10,2,i*2+2)
       subplot.set_xticks([])
       subplot.set_yticks([])
       subplot.imshow(results[i].reshape((28,28)), vmin=0, vmax=1,
                      cmap=plt.cm.gray_r, interpolation="nearest")

plt.show()


feed_dict = {sess.graph.get_tensor_by_name(input_signature['inputs'].name): mnist.test.images[:10]} 부분은 입력 데이타를 정의하는 부분으로, 앞에 모델 로딩시 사용했던 것과 같이 입력 텐서의 이름을 얻기 위해서 input_signature의 이름을 얻은 후, 그래프에서 그 이름으로 텐서를 가지고 온다. 그 이후, 가져온 텐서에 mnist 테스트 데이타셋에서 이미지 부분을 0~9 개를 피딩한다.


출력 값도 마찬가지로 output_signature에서 output 텐서 이름을 가지고 온후에, get_tensor_by_name 으로 해당 텐서를 가지고 온후에, output 변수에 저장한다.


마지막으로 sess.run을 통해서 feed_dict 값을 피딩하고, output 텐서를 리턴하여, 결과를 results로 리턴한다.

나머지는 리턴된 10개의 prediction result를 matplotlib를 이용하여 시각화 한 결과이다.

아래 결과와 같이 입력값과 출력값이 거의 유사하게 복원되었음을 확인할 수 있다.



테스트 코드를 웹으로 구현

테스트를 위해서 MNIST 데이타를 입력하는 것 말고, HTML 화면을 이용하여 직접 마우스로 숫자를 그래서 입력할 수 있도록 해보자


코드 구조 자체는 위의 예제와 같기 때문에 별도로 설명하지 않는다.



위의 그림과 같이 HTML 입력 박스에 마우스로 그림을 그리면 아래 그림과 같이 입력값과 함께 복원된 이미지를 보여 준다.

웹을 이용하여 숫자와 알파벳을 입력해서 입력과 결과값을 구분해본 결과, 영문이던 숫자이던 입출력 차이가 영문이나 숫자가 크게 차이가 나지 않아서, 변별력이 크지 않았다.



트레이닝 스탭이 이 50,000 스텝 정도면 loss값이 500 근처로 수렴을 하였는데, 1,000,000 스텝을 학습 시켜서 MNIST 데이타에 대한 기억 효과를 극대화 하려고 했지만 큰 효과가 없었다.

여러가지 원인이 있겠지만, HTML에서 손으로 이미지를 인식 받는 만큼, 글자의 위치나 크기에 따라서 loss 값이 크게 차이가 나는 결과를 보였다.  이 부분은 컨볼루셔널 필터 (Convolution Filter)를 사용하면 해결이 가능할것 같으나 적용은 하지 않았다.




또한 학습에 사용된 데이타는 0~255 의 흑백 값이지만, 위의 예제에서 웹을 통해 입력받은 값은 흑/백 (0 or 255)인 값이기 때문에 눈으로 보기에는 비슷하지만 실제로는 많이 다른 값이다.


또는 학습 데이타가 모자르거나 또는 네트워크 사이즈가 작았을 것으로 생각하는데, 그 부분은 별도로 테스트 하지 않았다.

신용 카드 데이타의 경우 손으로 그리는 그림이 아니기 때문에, 이런 문제는 없을 것으로 생각 하는데, 만약 문제가 된다면 네트워크 사이즈를 조정해보는 방안으로 진행할 예정이다.


다음 글에서는 신용 카드 데이타를 가지고 오토 인코더를 이용하여 비정상 거래를 검출하기 위해서 학습을 우하여 데이타 전처리를 하는 부분에 대해서 알아보도록 하겠다.


전체 코드 디렉토리가 변경되었습니다.

저작자 표시 비영리
신고

오토인코더를 이용한 비정상 거래 검출 모델의 구현 #1

신용카드 거래 데이타 분석


조대협 (http://bcho.tistory.com)


이미지 인식 모델은 만들어봤고, 아무래도 실제로 짜봐야 하는지라 좋은 시나리오를 고민하고 있는데, 추천 시스템도 좋지만, 이상 거래 감지에 대해 접할 기회가 있어서 이상 거래 감지 (Fraud Detection System)  시스템을 만들어 보기로 하였다


데이타셋

샘플 데이타를 구해야 하는데, 마침 kaggle.com 에 크레딧 카드 이상거래 감지용 데이타가 있었다.

https://www.kaggle.com/dalpozz/creditcardfraud 에서 데이타를 다운 받을 수 있다.




CSV 형태로 되어 있으며, 2013년 유럽 카드사의 실 데이타 이다. 2일간의 데이타 이고, 총 284,807건의 트렌젝션 로그중에, 492건이 비정상 데이타이고, 데이타 분포는 비정상 데이타가 0.172%로 심하게 불균형적이다.


전체 31개의 컬럼중, 첫번째 컬럼은 시간,30번째 컬럼은 비정상 거래 유무 (1이면 비정상, 0이면 정상) 그리고 마지막 31번째 컬럼은 결재 금액을 나타낸다 2~29번째 컬럼이 특징 데이타 인데, V1~V28로 표현되고 데이타 컬럼명은 보안을 이유로 모두 삭제 되었다.


데이타 분석

어떤 컬럼들을 피쳐로 정할것인가를 결정하기 위해서 데이타 분석을 시작한다.

데이타 분석 방법은  https://www.kaggle.com/currie32/predicting-fraud-with-tensorflow 를 참고하였다.


시간대별 트렌젝션양을 분석해보면 별다른 상관 관계를 찾을 수 없다.


트렌젝션 금액별로 비교를 한 그림이다.


위의 비정상 데이타를 보면, 작은 금액에서 비정상 거래가 많이 일어난것을 볼 수 있지만, 정상 거래군과 비교를 해서 다른 특징을 찾아낼 수 없다.


다음은 트랜젝션 금액을 기준으로 V1~V28 피쳐를 비교 분석해봤다.


붉은 점은 비정상, 파란점이 정상 거래이고, 가로축이 금액, 새로축이 V1 값이다. 이런 방법으로 V1~V8에 대한 그래프를 그려봤으나, 비정상 거래가 항상 정상거래의 부분집합형으로 별다른 특이점을 찾아낼 수 없었다.


다음으로 V1~V28 각 컬럼간의 값 분포를 히스토 그램으로 표현한 결과이다.

아래는 V2 피쳐의 값을 히스토그램으로 표현한 결과로 파란색이 정상, 붉은 색이 비정상 거래인데, 히스토그램이 차이가 나는 것을 확인할 수 있다.


V4 피쳐 역시 아래 그림과 같이 차이가 있는 것을 볼 수 있다.


V22 피쳐의 경우에는 정상과 비정상 거래의 패턴이 거의 유사하여 변별력이 없는것을 볼 수 있다.



이런식으로, V1~V28중에 비정상과 정상거래에 차이를 보이는 피쳐들만 선정한다.

위의 그래프들은 생성하는 코드는 https://github.com/bwcho75/tensorflowML/blob/master/autoencoder/Credit%20card%20fraud%20detection%20(Data%20Analytics).ipynb 에 있다.


모델 선택

정상거래와 비정상 거래가 라벨링이 되어 있기 때문에, 로지스틱 회귀나 일반적인 뉴럴네트워크를 사용해도 되지만, 비정상 거래 검출 로직의 경우 비정상 거래를 분별해서 라벨링한 데이타를 구하기가 매우 어렵다.

그래서 라벨된 데이타를 전제로 하는 지도학습보다 비지도학습 알고리즘을 선택하기로 한다.


비지도 학습 모델 중에서 오토 인코더라는 모델을 사용할 예정이다.

오토인코더 (AutoEncoder)

오토 인코더는 딥네트워크 기반의 비지도 학습 모델로, 뉴럴네트워크 두개를 뒤집어서 붙여놓은 형태이다.





<그림 출처 : https://deeplearning4j.org/deepautoencoder >

앞에 있는 뉴럴네트워크는 인코더, 뒤에 붙은 네트워크는 디코더가 된다.

인코더를 통해서 입력 데이타에 대한 특징을 추출해내고, 이 결과를 가지고 뉴럴 네트워크를 역으로 붙여서 원본 데이타를 생성해낸다.




이 과정에서 입력과 출력값이 최대한 같아지도록 튜닝함으로써, Feature를 잘 추출할 수 있게 하는것이 오토 인코더의 원리이다.


비정상 거래 검출에 있어서 이를 활용하는 방법은 학습이 되지 않은 데이타의 경우 디코더에 의해 복원이 제대로 되지 않고 원본 데이타와 비교했을때 차이값이 크기 때문에, 정상 거래로 학습된 모델은 비정상 거래가 들어왔을때 결과값이 입력값보다 많이 다를것이라는 것을 가정한다.


그러면 입력값 대비 출력값이 얼마나 다르면 비정상 거래로 판단할것인가에 대한 임계치 설정이 필요한데, 이는 실제 데이타를 통한 설정이나 또는 통계상의 데이타에 의존할 수 밖에 없다. 예를 들어 전체 신용카드 거래의 0.1%가 비정상 거래라는 것을 가정하면, 입력 값들 중에서 출력값과 차이가 큰 순서대로 데이타를 봤을때 상위 0.1%만을 비정상 거래로 판단한다.


또는 비지도 학습이기 때문에, 나온 데이타로 정상/비정상을 판단하기 보다는 비정상 거래일 가능성을 염두해놓고, 그 거래들을 비정상 거래일 것이라고 예측하고 이 비정상 거래 후보에 대해서 실제 확인이나 다른 지표에 대한 심층 분석을 통해서 비정상 거래를 판별한다.


이러한 과정을 거쳐서 비정상 거래가 판별이 되면, 비정상 거래에 대한 데이타를 라벨링하고 이를 통해서 다음 모델 학습시 임계치 값을 설정하거나 다른 지도 학습 알고리즘으로 변경하는 방법등을 고민해볼 수 있다.


다음글에서는 실제로 오토인코더 모델을 텐서플로우를 이용해서 구현해보겠다.


저작자 표시 비영리
신고

텐서플로우 하이레벨 API Estimator를 이용한 모델 정의 방법


조대협 (http://bcho.tistory.com)


텐서플로우의 하이레벨 API를 이용하기 위해서는 Estimator 를 사용하는데, Estimator 는 Predefined model 도 있지만, 직접 모델을 구현할 수 있다. 하이레벨 API와 Estimator에 대한 설명은 http://bcho.tistory.com/1195 글을 참고하기 바란다.


이 문서는 Custom Estimator를 이용하여 Estimator를 구현하는 방법에 대해서 설명하고 있으며, 대부분 https://www.tensorflow.org/extend/estimators 의 내용을 참고하여 작성하였다.

Custom Estimator

Estimator의 스켈레톤 코드는 다음과 같다. 모델을 정의하는 함수는 학습을 할 feature와, label을 입력 받고, 모델의 모드 (학습, 테스트, 예측) 모드를 인자로 받아서 모드에 따라서 모델을 다르게 정의할 수 있다. 예를 들어 학습의 경우 드롭 아웃을 사용하지만 테스트 모드에서는 드롭 아웃을 사용하지 않는다.

def model_fn(features, labels, mode, params):
  # Logic to do the following:
  # 1. Configure the model via TensorFlow operations
  # 2. Define the loss function for training/evaluation
  # 3. Define the training operation/optimizer
  # 4. Generate predictions
  # 5. Return predictions/loss/train_op/eval_metric_ops in EstimatorSpec object
  return EstimatorSpec(mode, predictions, loss, train_op, eval_metric_ops)

입력 인자에 대한 설명

그러면 각 인자를 구체적으로 살펴보자

  • features : input_fn을 통해서 입력되는 feature로 dict 형태가 된다.

  • labels : input_fn을 통해서 입력되는 label 값으로 텐서 형태이고, predict (예측) 모드 일 경우에는 비어 있게 된다.

  • mode : 모드는 모델의 모드로, tf.estimator.ModeKeys 중 하나를 사용하게 된다.

    • tf.estimator.ModeKeys.TRAIN : 학습 모드로 Estimator의 train()을 호출하였을 경우 사용되는 모드이다.

    • tf.estimator.ModeKeys.EVAL : 테스트 모드로, evaluate() 함수를 호출하였을 경우 사용되는 모드이다.

    • tf.estimator.ModeKeys.PREDICT : 예측모드로,  predict() 함수를 호출하였을 경우에 사용되는 모드이다.  

  • param : 추가적으로 입력할 수 있는 패러미터로, dict 포맷을 가지고 있으며, 하이퍼 패러미터등을 이 변수를 통해서 넘겨 받는다.

Estimator 에서 하는 일

Estimator 를 구현할때, Estimator 내의 내용은 모델을 설정하고, 모델의 그래프를 그린 다음에, 모델에 대한 loss 함수를 정의하고, Optimizer를 정의하여 loss 값의 최소값을 찾는다. 그리고 prediction 값을 계산한다.


Estimator의 리턴값

Estimator에서 리턴하는 값은 tf.estimator.EstimatorSpec 객체를 리턴하는데, 이 객체는 다음과 같은 값을 갖는다.

  • mode : Estimator가 수행한 모드. 보통 입력값으로 받은 모드 값이 그대로 리턴된다.

  • prediction (PREDICT 모드에서만 사용됨) : PREDICT 모드에서 예측을 수행하였을 경우, 예측된 값을 dict 형태로 리턴한다.

  • loss (EVAL 또는, TRAIN 모드에서 사용됨) : 학습과 테스트중에 loss 값을 리턴한다.

  • train_op (트레이닝 모드에서만 필요함) : 한 스텝의 학습을 수행하기 위해서 호출하는 함수를 리턴한다. 보통 옵티마이져의  minimize()와 같은 함수가 사용된다.
           optimizer = tf.train.AdamOptimizer(learning_rate=0.001)
           train_op = optimizer.minimize(loss, global_step=global_step)
           return tf.estimator.EstimatorSpec(mode, loss=loss, train_op=train_op)

  • eval_metrics_ops (optional) : EVAL (테스트) 모드에서 테스트를 위해서 사용된 인자들을 dict 형태로 리턴한다. tf.metrics에는 미리 정의된 일반적인 메트릭들이 정의되어 있는데, 예를 들어 accuracy 등이 이에 해당한다. 아래는 tf.metrics.accuracy를 이용하여 예측값 (predictions)과 라벨(labels)의 값을 계산하여, 메트릭으로 리턴하는 방법이다.

    eval_metric_ops = {
    "accuracy": tf.metrics.accuracy(labels, predictions) }

    만약 rmse를 evaluation metric으로 사용하고자 하면 다음과 같이 정의한다.
    eval_metric_ops = {
       "rmse": tf.metrics.root_mean_squared_error(
           tf.cast(labels, tf.float64), predictions)
    }

    만약에 별도의 메트릭을 정의하지 않으면, 디폴트로 loss 값만 EVAL 단계에서 계산되게 된다.

데이타 입력 처리

모델로의 데이타 입력은 Esitmator의 모델 함수로 입력되는 features 변수를 통해서 입력 된다.

features는 컬럼명으로된 키와, 컬럼 값으로 이루어진 dict 형태의 데이타 형으로, 뉴럴 네트워크 모델에 데이타를 입력하기 위해서는 이중에서 학습에 사용할 컬럼만을 추출하여, 입력 레이어에 넣어 줘야 한다.

이 features 에서 특정 컬럼만을 지정하여 추출한 후에, 그 컬럼의 값을 넣어주는 것은 tf.feature_column.input_layer 함수를 사용하면 된다.


예제를 보자

input_layer = tf.feature_column.input_layer(
 features=features, feature_columns=[age, height, weight])


위의 예제는 features 에서 age,height,weight 컬럼을 추출하여 input layer로 넣는 코드이다.

네트워크 정의

데이타를 읽었으면 이제 뉴럴네트워크를 구성해야 한다. 네트워크의 레이어는 tf.layers 로 간단하게 구현할 수 있다. tf.layer에는 풀링,드롭아웃,일반적인 뉴럴네트워크의 히든 레이어, 컨볼루셔널 네트워크들이 함수로 구현되어 있기 때문에 각 레이어를 하나의 함수로 간단하게 정의가 가능하다.


아래는 히든레이어를 구현하는 tf.layers.dense 함수이다.


tf.layers.dense( inputs, units, activation)


  • inputs는 앞의 레이어를 정의하고

  • units는 이 레이어에 크기를 정의하고

  • 마지막으로 activation은 sigmoid나,ReLu와 같은 Activation 함수를 정의한다.


다음 예제는 5개의 히든 레이어를 가지는 오토 인코더 네트워크를 정의한 예이다.

 input_layer = features['inputs'] # 784 pixels
   dense1 = tf.layers.dense(inputs=input_layer, units=256, activation=tf.nn.relu)
   dense2 = tf.layers.dense(inputs=dense1, units=128, activation=tf.nn.relu)
   dense3 = tf.layers.dense(inputs=dense2, units=16, activation=tf.nn.relu)
   dense4 = tf.layers.dense(inputs=dense3, units=128, activation=tf.nn.relu)
   dense5 = tf.layers.dense(inputs=dense4, units=256, activation=tf.nn.relu)
   output_layer = tf.layers.dense(inputs=dense5, units=784, activation=tf.nn.sigmoid)


5개의 히든 레이어는 각각 256,128,16,128,256 개의 노드를 가지고 있고, 각각 ReLu를 Activation 함수로 사용하였다.

그리고 마지막 output layer는 784개의 노드를 가지고 sigmoid 함수를 activation 함수로 사용하였다.

Loss 함수 정의

다음 모델에 대한 비용함수(loss/cost function)을 정의한다. 이 글을 읽을 수준이면 비용함수에 대해서 별도로 설명하지 않아도 되리라고 보는데, 비용함수는 예측값과 원래 라벨에 대한 차이의 합을 나타내는 것이 비용함수이다.


 # Connect the output layer to second hidden layer (no activation fn)

 output_layer = tf.layers.dense(second_hidden_layer, 1)
 # Reshape output layer to 1-dim Tensor to return predictions
 predictions = tf.reshape(output_layer, [-1])
 predictions_dict = {"ages": predictions}

 # Calculate loss using mean squared erro
 loss = tf.losses.mean_squared_error(labels, predictions)

코드를 보면, 최종 예측된 값은 predictions에 저장되고, 학습 데이타로 부터 받은 라벨 값은 labels에 저장된다. 이 차이를 계산할때, MSE (mean square error)를 사용하였다.

Training Op 정의

비용 함수가 적용되었으면, 이 비용함수의 값을 최적화 하는 것이 학습이기 때문에, 옵티마이저를 정의하고, 옵티마이저를 이용하여 비용함수의 최적화가 되도록 한다.

아래 코드는  Optimizer를 GradientDescentOptimizer로 정의하고, 이 옵티마이저를 이용하여 이용하여 loss 값을 최소화 하도록 하였다.

optimizer = tf.train.GradientDescentOptimizer(
   learning_rate=params["learning_rate"])

train_op = optimizer.minimize(
   loss=loss, global_step=tf.train.get_global_step())

전체 코드

그러면 위의 내용을 모두 합쳐서 model_fn으로 모아서 해보자.

def model_fn(features, labels, mode, params):
 """Model function for Estimator."""
 # Connect the first hidden layer to input layer
 # (features["x"]) with relu activation
 first_hidden_layer = tf.layers.dense(features["x"], 10, activation=tf.nn.relu)

 # Connect the second hidden layer to first hidden layer with relu
 second_hidden_layer = tf.layers.dense(
     first_hidden_layer, 10, activation=tf.nn.relu)

 # Connect the output layer to second hidden layer (no activation fn)
 output_layer = tf.layers.dense(second_hidden_layer, 1)


 # Reshape output layer to 1-dim Tensor to return predictions
 predictions = tf.reshape(output_layer, [-1])

 # Provide an estimator spec for `ModeKeys.PREDICT`.
 if mode == tf.estimator.ModeKeys.PREDICT:
   return tf.estimator.EstimatorSpec(
       mode=mode,
       predictions={"ages": predictions})

 # Calculate loss using mean squared error
 loss = tf.losses.mean_squared_error(labels, predictions)

 # Calculate root mean squared error as additional eval metric
 eval_metric_ops = {
     "rmse": tf.metrics.root_mean_squared_error(
         tf.cast(labels, tf.float64), predictions)
 }

 optimizer = tf.train.GradientDescentOptimizer(
  learning_rate=params["learning_rate"])

 train_op = optimizer.minimize(
     loss=loss, global_step=tf.train.get_global_step())

 # Provide an estimator spec for `ModeKeys.EVAL` and `ModeKeys.TRAIN` modes.

 return tf.estimator.EstimatorSpec(
     mode=mode,
     loss=loss,
     train_op=train_op,
     eval_metric_ops=eval_metric_ops)

데이타 입력

 first_hidden_layer = tf.layers.dense(features["x"], 10, activation=tf.nn.relu)

네트워크 정의

 # Connect the second hidden layer to first hidden layer with relu
 second_hidden_layer = tf.layers.dense(
     first_hidden_layer, 10, activation=tf.nn.relu)

 # Connect the output layer to second hidden layer (no activation fn)
 output_layer = tf.layers.dense(second_hidden_layer, 1)

first_hidden_layer의 입력값을 가지고 네트워크를 구성한다. 두번째 레이어는 first_hidden_layer를 입력값으로 하여, 10개의 노드를 가지고, ReLu를 activation 레이어로 가지도록 하였다.  

마지막 계층은 두번째 계층에서 나온 결과를 하나의 노드를 이용하여 합쳐서 activation 함수 없이 결과를 냈다.

 # Reshape output layer to 1-dim Tensor to return predictions
 predictions = tf.reshape(output_layer, [-1])

 # Provide an estimator spec for `ModeKeys.PREDICT`.
 if mode == tf.estimator.ModeKeys.PREDICT:
   return tf.estimator.EstimatorSpec(
       mode=mode,
       predictions={"ages": predictions})

예측 모드에서는 prediction 값을 리턴해야 하기 때문에, 먼저 예측값을 output_layer에서 나온 값으로, 행렬 차원을 변경하여 저장하고, 만약에 예측 모드 tf.estimator.ModeKeys.PREDICT일 경우 EstimatorSpec에 predction 값을 넣어서 리턴한다. 이때 dict 형태로 prediction 결과 이름을 age로 값을 predictions 값으로 채워서 리턴한다.

Loss 함수 정의

다음 비용 함수를 정의하고, 테스트 단계(EVAL)에서 사용할 evaluation metrics에 rmse를 테스트 기준으로 메트릭으로 정의한다.

 # Calculate loss using mean squared error
 loss = tf.losses.mean_squared_error(labels, predictions)

 # Calculate root mean squared error as additional eval metric
 eval_metric_ops = {
     "rmse": tf.metrics.root_mean_squared_error(
         tf.cast(labels, tf.float64), predictions)
 }

Training OP 정의

비용 함수를 정했으면, 비용 함수를 최적화 하기 위한 옵티마이져를 정의한다. 아래와 같이 GradientDescentOptimzer를 이용하여 loss 함수를 최적화 하도록 하였다.

 optimizer = tf.train.GradientDescentOptimizer(
  learning_rate=params["learning_rate"])

 train_op = optimizer.minimize(
     loss=loss, global_step=tf.train.get_global_step())

 # Provide an estimator spec for `ModeKeys.EVAL` and `ModeKeys.TRAIN` modes.

마지막으로, PREDICTION이 아니고, TRAIN,EVAL인 경우에는 EstimatorSpec을 다음과 같이 리턴한다.

Loss 함수와, Training Op를 정의하고 평가용 매트릭스를 정의하여 리턴한다.

 return tf.estimator.EstimatorSpec(
     mode=mode,
     loss=loss,
     train_op=train_op,
     eval_metric_ops=eval_metric_ops)

실행

그러면 완성된 Estimator를 사용해보자

train_input_fn = tf.estimator.inputs.numpy_input_fn(
   x={"x": np.array(training_set.data)},
   y=np.array(training_set.target),
   num_epochs=None,
   shuffle=True)

# Train

nn.train(input_fn=train_input_fn, steps=5000)

# Score accuracy

test_input_fn = tf.estimator.inputs.numpy_input_fn(
   x={"x": np.array(test_set.data)},
   y=np.array(test_set.target),
   num_epochs=1,
   shuffle=False)

ev = nn.evaluate(input_fn=test_input_fn)
print("Loss: %s" % ev["loss"])
print("Root Mean Squared Error: %s" % ev["rmse"])

각 코드를 보면

train_input_fn = tf.estimator.inputs.numpy_input_fn(
   x={"x": np.array(training_set.data)},
   y=np.array(training_set.target),
   num_epochs=None,
   shuffle=True)

를 이용하여 numpy 의 데이타로 input_fn 함수를 만들었다. training_set.data는 학습 데이타, training_set.target을 학습용 라벨로 설정하고, epoch는 무제한, 그리고 데이타는 셔플 하도록 하였다.

nn.train(input_fn=train_input_fn, steps=5000)

앞서 정의된 모델에 train_input_fn을 넣어서 총 5000 번 학습을 하도록 하였다.

학습이 끝난 모델을 테스트 해야 하는데, 같은 방법으로 test_input_fn을 정의하고

ev = nn.evaluate(input_fn=test_input_fn)

evaluate를 이용하여, 학습된 모델을 평가한다.

평가된 결과를 보기 위해서 loss 값과 rmse 값을 ev[‘loss’], ev[‘rmse’]로 출력하였다.

지금까지 Estimator를 만드는 방법에 대해서 알아보았다. 다음 글에서는 Auto Encoder 네트워크를 Estimator로 구현해보도록 하겠다.





저작자 표시 비영리
신고

텐서플로우 하이레벨 API

빅데이타/머신러닝 | 2017.09.06 14:57 | Posted by 조대협

텐서플로우 하이레벨 API에 대한 이해


머신러닝을 공부하고 구현하다 보니, 모델 개발은 새로운 모델이나 알고리즘을 개발하는 일 보다는, 기존의 알고리즘을 습득해서 내 데이타 모델에 맞도록 포팅하고, 학습 시키는 것이 주된 일이 되고, 오히려, 모델 보다는 데이타에 대한 이해와 전처리에 많은 시간이 소요되었다.


특히 여러번 실험을 하면서 패러미터를 조정하고 피쳐등을 조정하기 위해서는 많은 실험을 할 수 있어야 하는데, 이러기 위해서는 실험(학습)시간이 짧아야 한다. 이를 위해서는 모델 개발 보다 분산 러닝을 하기 위한 코드 변경 작업등이 많이 소요된다.


결론을 요약하자면, 실제로 알고리즘을 개발하는 데이타 과학자가 아니라, 머신러닝을 활용만 하는 프랙티셔너 입장이라면, 모델을 개발하는 것 보다는 있는 모델을 선택해서 쉽게 사용할 수 있는 방법을 찾으면 된다.

하이레벨 API

이런 관점에서 시작한 것이 머신러닝 하이레벨 API 이다. 복잡한 수식이 없이 마치 함수처럼 모델을 선택해서 사용하는 방법인데, 쉽게 이야기 하면, Hash table 알고리즘을 100% 이해하지 않더라도, hashtable 라이브러리를 가져다가 사용하면 되는것과 같은 원리이다.


머신러닝에서도 이미 이러한 하이레벨 API가 많이 제공되고 있는데, 파이썬 싸이킥 런(http://scikit-learn.org/) 이나 SparkML 등이 해당한다.

텐서플로우에도 같은 방식으로 하이레벨 API를 제공하는데, 텐서플로우 공식 SDK와 써드파티 오픈소스 라이브러리들이 있다.

그중에서 tf.contrib가 공식 텐서플로우의 하이레벨 API이며, 딥러닝 모델을 간단하게 만들 수 있는 Keras역시 얼마전에 텐서플로우 공식 하이레벨 API로 로 편입되었다.




텐서플로우에서는 Linear regression, SVM등 많이 쓰이는 일반적인 머신러닝 모델에서 부터 Deep Wide Network와 같은 딥 러닝 모델들을 Estimator 라는 형태로 제공하고 있다.

하이레벨 API를 쓰면 장점

그러면 이러한 하이레벨 API를 쓰면 장점이 무엇일까?

모델 개발이 쉽다

모델 개발이 매우 쉽다. 복잡한 모델을 손쉽게 개발할 수 있을뿐더러, 일부 모델들은 Out of box 형태로, 바로 라이브러리 식으로 불러서 사용만 하면 되기 때문에 모델 개발 시간이 줄어들고, 모델에 대한 기본적인 이해만 있더라도 쉽게 개발이 가능하다.

스케일링이 용이하다

큰 모델을 많은 데이타로 학습하기 위해서는 여러 머신에서 학습을 하는 분산 학습이 필요한데, 로우레벨 API를 이용할 경우 분산 학습을 개발하기가 쉽지 않다.  하이레벨 API를 이용할 경우 코드 변경 없이 싱글 머신에서 부터 GPU 그리고 분산 학습까지 손쉽게 지원이 되기 때문에, 실험 (학습/테스트) 시간을 많이 절약할 수 있다.


배포가 용이하다

모델을 학습 시킨 후 예측을 위해서 배포를 할 경우, 보통 모델을 *.pb 파일 형태로 Export 해야 하는데, 이 경우 학습에 사용된 그래프 말고 예측을 위한 그래프를 새로 그려야 하는 등 추가적인 작업이 필요하고 쉽지 않은데 반해 하이레벨 API의 경우, 코드 몇줄만으로도 손쉽게 예측 서비스를 위한 그래프를 Export할 수 있다.


텐서플로우 하이레벨 API

tf.layers

텐서플로우는 특히 딥러닝 (뉴럴네트워크)에 강점을 가지고 있는데, 딥네트워크의 각 계층을 설계 하기 위해서는 컨볼루셔널 필터, 풀링, 스트라이드,드롭 아웃 등 다양한 기법을 사용하게 된다. 이러한 것들을 복잡하게 구현하지 않고, 딥 네트워크를 손쉽게 만들 수 있게 각 레이어에 대한 구현을 함수식으로 제공한다.


다음 그림은 tf.layer로 컨볼루셔널 네트워크 (CNN)을 구현한 예제로 컨볼루셔널 레이어와, 맥스풀링, 드롭아웃, ReLu 엑티베이션 함수등을 사용하였다. 각 레이어는 tf.layers 라이브러리 하나씩으로 간단하게 구현되었다.


Estimator

일반적으로 머신러닝 개발은 다음과 같은 구조를 갖는다


개발한 모델에 Input,Labels 데이타를 넣은 후, 학습(Training), 테스트(Evaluation), 예측(Prediction)을 한후, 학습이 완료된 모델을 저장(Export)하여 배포한다.  거의 모든 모델 개발이 위의 구조를 반복하기 때문에, 이러한 구조를 추상화 해놓은 것이 Estimator 이다.


이 추상화를 통해서 Estimator에 데이타를 넣게 되면, Estimator는 Training, Evaluation, Prediction, Export를 위한 인터페이스를 제공한다. 텐서플로우 그래프 구축이나 세션 관리등은 모두 Estimator 안으로 추상화 한다.


Estimator는 직접 개발자가 모델을 직접 구현하여 Estimator를 개발할 수 도 있고 (Custom Estimator) 또는 이미 텐서플로우 tf.contrib.learn에 에 미리 모델들이 구현되어 있다. 딥네트워크 기반의 Classifier나 Regressor (DNNClassifieir, DNNRegressor), SVM, RNN, KMeans 등이 있기 때문에 간단하게 불러다 사용하기만 하면 된다.

Estimator 예제

Estimator 예제로 간단한 LinearRegression Estimator를 사용하는 예제를 보자

학습용 데이타

먼저 학습용 데이타와 라벨을 생성하였다.

import numpy as np

num_points = 300

vectors_set = []

for i in xrange(num_points):

 x = np.random.normal(5,5)+15

 y =  x*2+ (np.random.normal(0,3))*2

 vectors_set.append([x,y])

 

x_data = [v[0] for v in vectors_set ]

y_data = [v[1] for v in vectors_set ]


import matplotlib.pyplot as plt

plt.plot(x_data,y_data,'ro')

plt.ylim([0,100])

plt.xlim([5,35])

plt.xlabel('x')

plt.ylabel('y')

plt.legend()

plt.show()


데이타 분포는 아래와 같다.


모델 코드

데이타 리더

Estimator 를 사용하려면 데이타를 읽어서 Estimator 에 넣어주는 입력 함수를 구현해줘야 한다. 아래는  numpy 배열에서 데이타를 읽어서 리턴해주는 입력 함수이다.


input_fn_train = tf.estimator.inputs.numpy_input_fn(

   x = {"x":np.array(x_data[:200],dtype=np.float32)},

   y = np.array(y_data[:200],dtype=np.float32),

   num_epochs=100000,

   batch_size=50,

   shuffle=True

)


x_data 배열에서 0~200까지의 데이타를 학습용 데이타로 사용하였고, y_data 0~200을 라벨로 사용하였다. 한번에 50 개씩 리턴하도록 배치를 설정하였고, 100K epoch를 지원하고 데이타를 랜덤하게 리턴하도록 셔플 처리를 하였다.


input_fn_eval = tf.estimator.inputs.numpy_input_fn(

   x = {"x":np.array(x_data[200:300],dtype=np.float32)},

   y = np.array(y_data[200:300],dtype=np.float32),

   num_epochs=100000,

   batch_size=50,

   shuffle=True

)


input_fn_predict = tf.estimator.inputs.numpy_input_fn(

   x = {"x":np.array([15,20,25,30],dtype=np.float32)},

   num_epochs=1,

   shuffle=False

)


같은 방법으로 테스트용 데이타와 예측에 사용할 데이타 입력 함수를 같이 정의하였다.

모델 정의

column_x = tf.feature_column.numeric_column("x",dtype=tf.float32)

columns = [column_x]

읽어온 데이타에서, 어떤 컬럼을 학습에 사용할지, 그리고 그 컬럼의 데이타 타입 (연속형인지 분류형인지)를 정한다.  tf.feature_column.numeric_column("x",dtype=tf.float32) 는 컬럼 명 x를 학습 데이타로 사용하고 x는 연속형 변수로 지정하였다.

다음 columns에 피쳐로 사용할 컬럼 목록을 정한다.


LinearRegression Estimator를 정의하고, 여기에, column을 정해준다.  Optimizer나 Learning Rate등은 지정이 가능하다.

estimator = tf.contrib.learn.LinearRegressor(feature_columns=columns,optimizer="Adam")

학습과 예측

학습은 .fit 이라는 메서드를 사용하면 되고, 입력 함수와 학습 스텝을 정해주면 된다.

estimator.fit(input_fn = input_fn_train,steps=5000)

estimator.evaluate(input_fn = input_fn_eval,steps=10)

result = list(estimator.predict(input_fn = input_fn_predict))


마지막으로 예측은 predict 를 이용하면 된다.

x=15,20,25,30에 대해서 예측 결과는 다음과 같다.

[31.193062, 41.855644, 52.51823, 63.180817]



그래프와 비교해보면 유사 값이 나오는 것을 확인할 수 있다.



전체 코드 
https://github.com/bwcho75/tensorflowML/blob/master/HighLevel%20API%201.%20Linear%20Regression%20Estimator.ipynb






저작자 표시 비영리
신고

Object Detection API에 애완동물 사진을 학습 시켜 보자


조대협 (http://bcho.tistory.com)


Object Detection API에 이번에는 애완동물 사진 데이타를 학습시켜 보도록 한다.

애완 동물 학습 데이타의 원본은  Oxford-IIIT Pets lives  http://www.robots.ox.ac.uk/~vgg/data/pets/ 에 있다. 약 37개의 클래스에, 클래스당 200개 정도의 이미지를 가지고 있다.



이번 글에서는 이 애완동물 데이타를 다운 받아서, Object Detection API에 학습 시키는 것까지 진행을 한다.

데이타를 다운로드 받은 후, Object Detection API에 학습 시키기 위해서, 데이타 포맷을 TFRecord 형태로 변환한 후, 학습을 하는 과정을 설명한다.


주의할점 : 이 튜토리얼은 총 37개의 클래스 약 7000장의 이미지를 학습시키는데, 17시간 이상이 소요되며, 구글 클라우 CloudML의 텐서플로우 클러스터에서 분산 러닝을 하도록 설명하고 있는데, 많은 비용이 들 수 있다. 전체 흐름과 과정을 이해하기 위해서는 17시간을 풀 트레이닝 시키지 말고 학습 횟수를 줄이거나 아니면 중간에서 학습을 멈춰서 비용이 많이 나오지 않도록 하는 것을 권장한다.

학습 데이타 다운로드 받기

%curl -O http://www.robots.ox.ac.uk/~vgg/data/pets/data/images.tar.gz

%curl -O http://www.robots.ox.ac.uk/~vgg/data/pets/data/annotations.tar.gz

※ 맥이기 때문에, curl -O 를 사용했는데, Linux의 경우에는 wget을 사용하면 된다.

파일을 다운로드 받았으면 압축을 풀어보자

  • images.tar.gz에는 애완동물의 학습용 이미지가 들어가 있다.

  • annotations.tar.gz 는 각 이미지에 대한 메타 데이타가 들어있다. 이미지 마다 나타난 동물의 종류, 사진상 동물의 위치 (박스)

TFRecord 파일 포맷으로  컨버팅 하기

압축을 푼 메타데이타와 이미지 파일을 이용해서 tfrecord 파일 형태로 컨버팅을 해야 한다. Tfrecord 내에는 이미지 바이너리, 이미지에 대한 정보 (이미지 크기, 인식할 물체의 위치, 라벨)등이 들어간다. 상세 데이타 포맷에 대해서는 다음글에서 설명하도록 한다.

이 데이타를 가지고 tfrecord 타입으로 컨버팅 하는 코드는 object_detection/create_pet_tf_record.py

에 이미 작성되어 있다. 아래 코드를 이용해서 실행해주면 자동으로 pet_train.record에 학습용 데이타를 pet_val.record에 테스트용 데이타를 생성해준다.


python object_detection/create_pet_tf_record.py \
   --label_map_path=object_detection/data/pet_label_map.pbtxt \
   --data_dir=`pwd` \
   --output_dir=`pwd`

학습 환경 준비하기

데이타가 준비되었으면 학습을 위한 환경을 준비해야 한다.

학습은 구글 클라우드 플랫폼의 CloudML을 사용한다. CloudML은 구글 클라우드 플랫폼의 Tensorflow managed 서비스로, Tensorflow 클러스터 설치나 운영 필요 없이 간단하게 명령어 만으로 여러대의 머신에서 학습을 가능하게 해준다.

CloudML을 사용하기 위해서는 몇가지 환경 설정을 해줘야 한다.

  • 먼저 학습용 데이타 (tfrecord)파일을 구글 클라우드 스토리지 (GCS)로 업로드 해야 한다.

  • Object Detection API에서 사물 인식에 사용된 모델의 체크 포인트를 업로드 해야 한다.

  • 클라우드에서 학습을 하기 때문에, 텐서플로우 코드를 패키징해서 업로드해야 한다.

학습 데이타 업로드 하기

데이타를 업로드하기전에, 구글 클라우드 콘솔에서 구글 클라우드 스토리지 버킷을 생성한다.

생성된 버킷명을 YOUR_GCS_BUCKET 환경 변수에 저장한다.

export YOUR_GCS_BUCKET=${YOUR_GCS_BUCKET}


다음 gsutil 유틸리티를 이용하여 YOUR_GCS_BUCKET 버킷으로 학습용 데이타와, 라벨맵 데이타를 업로드 한다.


gsutil cp pet_train.record gs://${YOUR_GCS_BUCKET}/data/pet_train.record
gsutil cp pet_val.record gs://${YOUR_GCS_BUCKET}/data/pet_val.record
gsutil cp object_detection/data/pet_label_map.pbtxt gs://${YOUR_GCS_BUCKET}/data/pet_label_map.pbtxt


학습된 모델 다운로드 받아서 업로드 하기

다음은 학습된 모델을 받아서, 그중에서 체크포인트를  GCS에 올린다.


curl -O http://storage.googleapis.com/download.tensorflow.org/models/object_detection/faster_rcnn_resnet101_coco_11_06_2017.tar.gz

tar -xvf faster_rcnn_resnet101_coco_11_06_2017.tar.gz
gsutil cp faster_rcnn_resnet101_coco_11_06_2017/model.ckpt.* gs://${YOUR_GCS_BUCKET}/data/


체크 포인트를 다운받아서 업로드 하는 이유는, 트랜스퍼 러닝 (Transfer Learning)을 하기 위함인데, 하나도 학습이 되지 않은 모델을 학습을 시키는데는 시간이 많이 들어간다. 트랜서퍼러닝은 이미 학습이 되어 있는 모델로 다른 데이타를 학습 시키는 방법인데, 사물을 인식하는 상태로 학습되어 있는 모델을 다른 물체 (여기서는 애완동물)를 학습하는데 사용하면 학습 시간을 많이 줄 일 수 있다. 이런 이유로, 사물 인식용으로 학습된 체크포인트를 로딩해서 이 체크포인트 부터 학습을 하기 위함이다.

설정 파일 변경하기

Object Detection API를 사용하기 위해서는 학습에 대한 설정 정보를 정의해야 한다.

이 설정 파일안에는 학습 데이타의 위치, 클래스의 수 및 각종 하이퍼 패러미터들이 정의되어 있다. 패러미터에 대한 자세한 설명은  https://github.com/tensorflow/models/blob/master/object_detection/g3doc/configuring_jobs.md를 참고하기 바란다. 이 예제에서는 설정 파일을 따로 만들지 않고 애완동물 사진 학습을 위해서 미리 정의되어 있는 템플릿 설정 파일을 이용하도록 한다.  설정 파일은 미리 정의된 모델에 따라 다른데, 여기서는 faster_rcnn_resnet101_pets 모델을 사용하기 때문에 object_detection/samples/configs/faster_rcnn_resnet101_pets.config 파일을 사용한다.


파일의 위치가 PATH_TO_BE_CONFIGURED 문자열로 정의되어 있는데, 이를 앞에서 만든 GCS 버킷명으로 변경해야 하기 때문에, 아래와 같이 sed 명령을 이용하여 해당 문자열을 변경하자


Linux : sed -i "s|PATH_TO_BE_CONFIGURED|"gs://${YOUR_GCS_BUCKET}"/data|g" object_detection/samples/configs/faster_rcnn_resnet101_pets.config


Max : sed -i ‘’ -e "s|PATH_TO_BE_CONFIGURED|"gs://${YOUR_GCS_BUCKET}"/data|g" object_detection/samples/configs/faster_rcnn_resnet101_pets.config


설정 파일 작성이 끝났으면 이를 GCS 버킷에 올린 후에, 학습시에 사용하도록 한다. 다음 명령어는 설정 파일을 GCS 버킷에 올리는 명령이다.

gsutil cp object_detection/samples/configs/faster_rcnn_resnet101_pets.config \
   gs://${YOUR_GCS_BUCKET}/data/faster_rcnn_resnet101_pets.config


텐서플로우 코드 패키징 및 업로드

학습에 사용할 데이타와 체크포인트등을 업로드 했으면, 다음 텐서플로우 코드를 패키징 해야 한다. 이 글에서는 학습을 로컬 머신이 아니라 구글 클라우드의 텐서플로우 메니지드 서비스인 CloudML을 사용하는데, 이를 위해서는 텐서플로우코드와 코드에서 사용하는 파이썬 라이브러리들을 패키징해서 올려야 한다.


Object Detection API 모델 디렉토리에서 다음 명령어를 실행하면, model 디렉토리와 model/slim 디렉토리에 있는 텐서플로우 코드 및 관련 라이브러리를 같이 패키징하게된다.


# From tensorflow/models/
python setup.py sdist
(cd slim && python setup.py sdist)


명령을 실행하고 나면 패키징된 파일들은 dist/object_detection-0.1.tar.gzslim/dist/slim-0.1.tar.gz 에 저장되게 된다.

학습하기

구글 CloudML을 이용하여 학습하기. 그러면 학습을 시작해보자. 학습은 200,000 스탭에 총 17시간 정도가 소요되며, 비용이 3000$ 이상이 소요되니, 비용이 넉넉하지 않다면, 학습을 중간에 중단 시키기를 권장한다. 테스트 목적이라면 약 10~20분 정도면 충분하지 않을까 한다. 아니면 앞의 config 파일에서 trainning step을 작게 낮춰서 실행하기 바란다.


# From tensorflow/models/
gcloud ml-engine jobs submit training `whoami`_object_detection_`date +%s` \
   --job-dir=gs://${YOUR_GCS_BUCKET}/train \
   --packages dist/object_detection-0.1.tar.gz,slim/dist/slim-0.1.tar.gz \
   --module-name object_detection.train \
   --region asia-east1 \
   --config object_detection/samples/cloud/cloud.yml \
   -- \
   --train_dir=gs://${YOUR_GCS_BUCKET}/train \
   --pipeline_config_path=gs://${YOUR_GCS_BUCKET}/data/faster_rcnn_resnet101_pets.config


학습을 시킬 텐서플로우 클러스터에 대한 정보는 object_detection/samples/cloud/cloud.yml 에 들어 있다. 내용을 보면,

trainingInput:

 runtimeVersion: "1.0"

 scaleTier: CUSTOM

 masterType: standard_gpu

 workerCount: 5

 workerType: standard_gpu

 parameterServerCount: 3

 parameterServerType: standard


scaleTier로 클러스터의 종류를 정의할 수 있는데, 서버 1대에서 부터 여러대의 클러스터까지 다양하게 적용이 가능하다. 여기서는 모델이 크기가 다소 크기 때문에, Custom으로 설정하였다.


역할

서버 타입

댓수

Master server

standard_gpu

1

Worker

standard_gpu

5

Parameter Server

standard

5


각 서버의 스펙은 상세 스펙은 나와있지 않고, 상대값으로 정의되어 있는데 대략 내용이 다음과 같다.



출처 https://cloud.google.com/ml-engine/docs/concepts/training-overview#machine_type_table




학습을 시작하고 나면 CloudML 콘솔에서 실행중인 Job을 볼 수 있고, Job을 클릭하면 자원의 사용 현황을 볼 수 있다. (CPU와 메모리 사용량)



학습을 시작한 후에, 학습된 모델을 Evaluate할 수 있는데, Object Detection API에서는 학습 말고 Evaluation 모델을 별도로 나눠서, 잡을 나눠서 수행하도록 하였다. 학습중에 생성되는 체크포인트 파일을 읽어서 Evaluation을 하는 형태이다.

다음을 Evaluation을 실행하는 명령어인데, 위의 학습 작업이 시작한 후에, 한시간 정도 후부터 실행해도 실행 상태를 볼 수 있다.


# From tensorflow/models/
gcloud ml-engine jobs submit training `whoami`_object_detection_eval_`date +%s` \
   --job-dir=gs://${YOUR_GCS_BUCKET}/train \
   --packages dist/object_detection-0.1.tar.gz,slim/dist/slim-0.1.tar.gz \
   --module-name object_detection.eval \
   --region asia-east1 \
   --scale-tier BASIC_GPU \
   -- \
   --checkpoint_dir=gs://${YOUR_GCS_BUCKET}/train \
   --eval_dir=gs://${YOUR_GCS_BUCKET}/eval \
  --pipeline_config_path=gs://${YOUR_GCS_BUCKET}/data/faster_rcnn_resnet101_pets.config


학습 진행 상황 확인하기

학습이 진행중에도, Evaluation을 시작했으면, Tensorboard를 이용하여 학습 진행 상황을 모니터링 할 수 있다. 학습 진행 데이타가 gs://${YOUR_GCS_BUCKET} 에 저장되기 때문에, 이 버킷에 있는 데이타를 Tensorboard로 모니터링 하면 된다.

실행 방법은 먼저 GCS 에 접속이 가능하도록 auth 정보를 설정하고, Tensorboard에 로그 파일 경로를

GCS 버킷으로 지정하면 된다.

gcloud auth application-default login
tensorboard --logdir=gs://${YOUR_GCS_BUCKET}


아래는 실제 실행 결과이다.



Evaluataion이 끝났으면, 테스트된 이미지도 IMAGES 탭에서 확인이 가능하다.



학습된 모델을 Export 하기

학습이 완료되었으면, 이 모델을 예측 (Prediction)에 사용하기 위해서 Export 할 수 있다. 이렇게 Export 된 이미지는 나중에 다시 로딩하여 예측(Prediction)코드에서 로딩을 하여 사용이 가능하다.

${YOUR_GCS_BUCKET}에 가면 체크 포인트 파일들이 저장되어 있는데, 이 체크 포인트를 이용하여 모델을 Export 한다.



GCS 버킷에서 Export 하고자 하는 Check Point 번호를 선택한 후에 Export 하면 된다, 여기서는 200006 Check Point를 Export 해보겠다.


${CHECKPOINT_NUMBER} 환경 변수를

export CHECKPOINT_NUMBER=200006

으로 설정한 다음에 다음 명령어를 실행한다.


# From tensorflow/models
gsutil cp gs://${YOUR_GCS_BUCKET}/train/model.ckpt-${CHECKPOINT_NUMBER}.* .
python object_detection/export_inference_graph.py \

   --input_type image_tensor \

   --pipeline_config_path object_detection/samples/configs/faster_rcnn_resnet101_pets.config \

   --trained_checkpoint_prefix model.ckpt-${CHECKPOINT_NUMBER} \

   --output_directory output_inference_graph.pb


명령을 실행하고 나면 output_inference_graph.pb 디렉토리에 모델이 Export 된것을 확인할 수 있다.

다음 글에서는 직접 자신의 사진 데이타만을 가지고 학습과 예측을 하는 방법에 대해서 알아보겠다.


참고 자료



저작자 표시 비영리
신고


Tensorflow Object Detection API


조대협 ( http://bcho.tistory.com)


Tensorflow Object Detection API는, Tensorflow 를 이용하여 이미지를 인식할 수 있도록 개발된 모델로, 라이브러리 형태로 제공되며, 각기 다른 정확도와 속도를 가지고 있는 5개의 모델을 제공한다. 머신러닝이나 텐서플로우에 대한 개념이 거의 없더라도 라이브러리 형태로 손쉽게 사용할 수 있으며, 직접 사용자 데이타를 업로드해서 학습을 하여, 내 시나리오에 맞는 Object Detection System을 손쉽게 만들 수 있다.


Object Detection API를 설치하기 위해서는 텐서플로우 1.x 와 파이썬 2.7x 버전이 사전 설치되어 있어야 한다. 이 글에서는 파이썬 2.7.13과 텐서플로우 2.7.13 버전을 기준으로 하고, 맥에 설치하는 것을 기준으로 한다. 리눅스나 다른 플랫폼 설치는 원본 설치 문서 https://github.com/tensorflow/models/blob/master/object_detection/g3doc/installation.md 를 참고하기 바란다.


설치 및 테스팅

Protocol Buffer 설치

Object Detection API는 내부적으로 Protocol Buffer를 사용한다. MAC에서 Protocol Buffer를 설치 하는 방법은 https://github.com/google/protobuf/tree/master/pythonhttp://bcho.tistory.com/1182 를 참고하기 바란다.

설치가 되었는지를 확인하려면, 프롬프트 상에서 protoc 명령을 실행해보면 된다.

파이썬 라이브러리 설치

프로토콜 버퍼 설치가 끝났으면, 필요한 파이썬 라이브러리를 설치한다.

% pip install pillow

% pip install lxml

% pip install jupyter

% pip install matplotlib

Object Detection API 다운로드 및 설치

Object Detection API 설치는 간단하게, 라이브러리를 다운 받으면 된다. 설치할 디렉토리로 들어가서 git clone 명령어를 통해서, 라이브러리를 다운로드 받자

% git clone https://github.com/tensorflow/models

Protocol Buffer 컴파일

다음 프로토콜 버퍼를 사용하기 위해서 protoc로 proto 파일을 컴파일 한데, Object Detection API를 설치한 디렉토리에서 models 디렉토리로 들어간 후에, 다음 명령어를 수행한다.


protoc object_detection/protos/*.proto --python_out=.

PATH 조정하기

설치가 끝났으면 Object Detection API를 PATH와 파이썬 라이브러리 경로인 PYTHONPATH에 추가한다. 맥에서는 사용자 홈디렉토리의 .bash_profile 에 추가 하면되낟.

PYTHONPATH 환경 변수에 {Object Detection API 설치 디렉토리}/models/slim 디렉토리와 Object Detection API 설치 디렉토리}/models/models 디렉토리를 추가한다.

같은 디렉토리를 PATH에도 추가해준다.


export PYTHONPATH=$PYTHONPATH:/Users/terrycho/dev/workspace/objectdetection/models:/Users/terrycho/dev/workspace/objectdetection/models/slim

export PATH=$PATH:/Users/terrycho/dev/workspace/objectdetection/models:/Users/terrycho/dev/workspace/objectdetection/models/slim

테스팅

설치가 제대로 되었는지를 확인하기 위해서 {Object Detection API 설치 디렉토리}/models/ 디렉토리에서 다음 명령을 실행해보자


% python object_detection/builders/model_builder_test.py


문제 없이 실행이 되었으면 제대로 설치가 된것이다.


사용하기

설치가 끝났으면 실제로 사용해 보자, Object Detection API를 인스톨한 디렉토리 아래 models/object_detection/object_detection_tutorial.ipynb 에 테스트용 노트북 파일이 있다. 이 파일을 주피터 노트북 (http://jupyter.org/)을 이용하여 실행해보자.
(원본 코드 https://github.com/tensorflow/models/blob/master/object_detection/object_detection_tutorial.ipynb)


실행을 하면 결과로 아래와 같이 물체를 인식한 결과를 보여준다.




이 중에서 중요한 부분은 Model Preparation이라는 부분으로,

여기서 하는 일은 크게 아래 3가지와 같다.