텐서플로우 튜토리얼 – 3

이 글은 Illia Polosukhin 가 쓴 TensorFlow Tutorial – Part 3 을 번역한 글 입니다. (update: 2016-04-20) 텐서플로우 0.8 버전에 맞추어 코드를 수정하였고 번역을 다듬었습니다. 아래 예제를 쥬피터 노트북으로 작성하여 깃허브에 올려 놓았습니다.

이전 튜토리얼 – 1, 튜토리얼 – 2 에서 텐서플로우(TensorFlow)와 사이킷플로우(Scikit Flow)를 소개하고 타이타닉 데이터셋을 이용하여 몇가지 모델을 만드는 법을 소개했습니다.

이번에는 카테고리 변수를 다루는 좀 더 복잡한 모델을 만들어 보겠습니다.

일반적으로 머신러닝에서는 카테고리 변수를 다루기위해 각 카테고리에 대해 one-hot 벡터(혹은 one-hot encoding, 한 요소만 1인 벡터)를 만듭니다. 딥러닝에서는 분산표현방식(Distribution representation) 또는 임베딩(Embedding) 이라고 부르는 방법이 있습니다.

임베딩 방식을 사용하면 각 카테고리를 원하는 사이즈의 실수 벡터로 표현할 수 있으며 나중에 모델에서 피처(feature)로 사용합니다. 참고할 점은 텐서플로우 컴포넌트(그리고 다른 딥러닝 프레임워크들도)의 미분계산 능력때문에 작업에 가장 최적화된 모델을 트레이닝 시키게 도와줍니다. 이는 개개의 피처 엔지니어링(feature engineering)을 할 필요가 없게 만드는 딥러닝 툴킷의 가장 강력한 기능입니다.

수백, 수천개의 많은 카테고리 변수들이 있어나 값들이 채워져지지 않고 드문드문한 경우 더 진가를 발휘합니다. N개의 카테고리로 된 값이 입력되면 압축하여 고정된 사이즈의 임베딩(embedding)을 만듭니다.

적은 갯수의 카테고리일 때에도 카테고리 마다 one-hot 벡터를 모델링하기 위해 임베딩(embedding) 방식을 여전히 사용할 수 있습니다.(예로, 의미를 고려하지 않고 카테고리를 분산시킵니다)

타이타닉 데이터셋의 ‘Embarked’ 카테고리 변수를 이용하여 간단한 예측 모델을 만들어 보겠습니다.

import random
import pandas
import numpy as np
import tensorflow as tf
from sklearn import metrics, cross_validation

from tensorflow.contrib import skflow

random.seed(42)
data = pandas.read_csv('data/titanic_train.csv')
X = data[["Embarked"]]
y = data["Survived"]
X_train, X_test, y_train, y_test = cross_validation.train_test_split(X, y, test_size=0.2, random_state=42)

embarked_classes = X_train["Embarked"].unique()
print('Embarked has next classes: ', embarked_classes)

cat_processor = skflow.preprocessing.CategoricalProcessor()
X_train = np.array(list(cat_processor.fit_transform(X_train)))
X_test = np.array(list(cat_processor.transform(X_test)))

# Total number of classes for this variable from Categorical Processor.
# Includes unknown token and unique classes for variable.
n_classes = len(cat_processor.vocabularies_[0])

### Embeddings

EMBEDDING_SIZE = 3

def categorical_model(X, y):
    features = skflow.ops.categorical_variable(
        X, n_classes, embedding_size=EMBEDDING_SIZE, name='embarked')
    return skflow.models.logistic_regression(tf.squeeze(features, [1]), y)

classifier = skflow.TensorFlowEstimator(model_fn=categorical_model, 
    n_classes=2)
classifier.fit(X_train, y_train['Survived'])

print("Accuracy: {0}".format(metrics.accuracy_score(classifier.predict(X_test), y_test)))
print("ROC: {0}".format(metrics.roc_auc_score(classifier.predict(X_test), y_test)))

### One Hot

def one_hot_categorical_model(X, y):
    features = skflow.ops.one_hot_matrix(X, n_classes)
    return skflow.models.logistic_regression(tf.squeeze(features, [1]), y)

classifier = skflow.TensorFlowEstimator(model_fn=one_hot_categorical_model, 
    n_classes=2, steps=1000, learning_rate=0.01)
classifier.fit(X_train, y_train['Survived'])

print("Accuracy: {0}".format(metrics.accuracy_score(classifier.predict(X_test), y_test)))
print("ROC: {0}".format(metrics.roc_auc_score(classifier.predict(X_test), y_test)))

(역주. 원문에서 와는 달리 fit 메소드에 y_train을 그냥 넣어주면 결과는 나오지만 VisibleDeprecationWarning 경고가 발생합니다. skflow에서 y_train을 numpy.array로 변환을 하는 데 그 결과가 2차원 배열 형태가 됩니다. 하지만 사용할 때는 1차원 배열처럼 인덱스 하나만을 지정하기 때문입니다. numpy.array 변환시 1차원 배열로 나오게 하기 위해 y_train[‘Survived’] 로 하여 pandas.Series 형태를 만들어 파라메타를 넘겼습니다.)

피처로 ‘Embarked’ 컬럼 하나만 선택하고 전체 데이터에서 20%를 분리하여 테스트 셋을 만듭니다.

피처에 어떤 값들이 있는 지는 꼭 살펴봐야 합니다.

| Embarked 는 ‘S’, ‘C’, ‘Q’,  nan 값을 가집니다.

이 변수를 카테고리 변수를 숫자 아이디로 매핑해 주는 클래스인 CategoricalProcessor 에 전달합니다. 이 경우에는 S -> 1, C -> 2, Q -> 3 그리고 nan -> 0 으로 만들어 해당 컬럼을 숫자(id)로 바꾸어 줍니다.

마지막 모델 생성은 간단합니다. 헬퍼 함수인 categorical_variable은 embedding_size에 의해 n_classes 사이즈인 임베딩 매트릭스를 만들고 입력 데이터에서 id 값을 조회합니다. 이것은 one_hot_matrix와 유사하지만 주어진 카테고리 변수에 대해 학습이 가능한 분산표현(learnable distributed representations) 형태로 리턴한다는 점이 다릅니다.

최종적으로 모델을 훈련하고 테스트 데이터를 이용하여 예측결과를 만듭니다. 카테고리 변수에 대해 분산 표현 방식을 이용한 모델을 만든 것 입니다.

| Accuracy: 0.625698324022
| ROC: 0.610550615595

임베딩 방식 다음으로는 비교를 위해 one-hot 벡터 방식의 간단한 모델을 만들었습니다. 클래스 1, 2, 3 에 대해 해당 클래스의 위치에는 1 을 그 외에는 0 을 갖는 벡터로 매핑합니다. 예를 들면 클래스 C(2) 는 [0, 0, 1, 0] 벡터가 될 것 입니다.

여기에서 예측을 위해서 3개의 클래스를 갖는 하나의 변수를 사용했습니다. 결과는 임베딩의 경우와 완전히 동일합니다. (역주. 사실 one-hot 벡터의 결과가 조금 다릅니다. Accuracy:  0.6201117318435754, ROC: 0.6027310924369748 로 임베딩 방식을 사용한 것 보다 조금 낮습니다.)

다음으로

위에서 고차원 카테고리 변수에 대해서 분산 표현 방식이 효과적이라고 언급했습니다. 다음 포스트에서는 어떻게 이 방법을 이용하여 자연어처리(Natural Language Understanding) – 문서분류 같은 – 를 위해 카테고리 변수를 다루는지 보도록 하겠습니다.

텐서플로우 튜토리얼 – 3”에 대한 6개의 생각

  1. 초보자

    classifier.fit(X_train, y_train[‘Survived’])
    이부분에서 에러가나는데, 번역 대상 페이지를 가보니
    classifier.fit(X_train, y_train) 이더군요 !
    이렇게 하니까 실행이 되어요~

    좋아요

    응답
    1. 로드홈 글의 글쓴이

      아마도 설치한 패키지들의 버전에 따라 조금 다를 수 있을 것 같습니다. 제가 위에 설명을 넣은 것 처럼 numpy 에서 변환을 어떻게 하는지에 따라 상이한 결과가 나올 수 있습니다. 혹은 skflow나 tesnorflow 버전에 따라 다르게 나올 수 있습니다. 저는 os x + conda + python 3.5.1 + pandas 0.18.0 + numpy 1.11.0 + tensorflow 0.8.0rc 에서 테스트 했습니다.

      좋아요

      응답
  2. 이홍규

    안녕하세요. 책보며 독학으로 머신러닝을 공부하는 학생입니다.
    one-hot encoding에 적합하지 않은 데이터는 어떻게 처리하나요??
    예를 들어 수학 문제의 유형, 난이도, 정답 등등의 특징을 하나의 Vector로 만들려고 하는데
    유형이 500개, 난이도가 10개, 정답이 2 개의 특징이므로 one hot encoding 하면… 10000개의 특징이 나오는데 학습을 하기에 너무 많다는 생각이 들어서요 ㅜ
    RNN을 사용하려는데 거의 모든 예제가 one-hot encoding 되어있어 방향을 못잡고 있습니다.
    매우 부족한 질문이지만 조언 부탁드립니다!

    Liked by 1명

    응답

댓글 남기기

이 사이트는 스팸을 줄이는 아키스밋을 사용합니다. 댓글이 어떻게 처리되는지 알아보십시오.