Tensorflow - 분류모델, 원핫인코딩, Softmax(아이리스 품종 분류)
[강의 출처] opentutorials.org/module/4966/28987
세번째 딥러닝 - 아이리스 품종 분류 - Tensorflow 1
수업소개 아이피스 품봉을 분류하는 딥러닝 모델을 텐서플로우를 이용하여 만들어 보고, 분류모델과 회귀모델의 차이점을 이해합니다. 범주형 변수의 처리 방법인 원핫인코딩을 해야하는 이유
opentutorials.org
아이리스 품종 분류
꽃잎길이 | 꽃잎폭 | 꽃받침길이 | 꽃받침폭 | 품종 |
5.1 | 3.5 | 1.4 | 0.2 | setosa |
7.0 | 3.2 | 4.7 | 1.4 | versicolor |
6.7 | 3.3 | 5.7 | 2.1 | virginica |
-위 데이터와 같은 독립변수(꽃잎길이, 꽃잎폭, 꽃받침길이, 꽃받침폭)를 가지고 종속변수(품종)을 찾아내는 문제
-아이리스 문제는 기존 레모네이드, 보스턴 집값 문제와는 달리, 종속변수인 '품종'이 숫자값이 아닌 범주형 데이터임
-범주형 데이터는 해당 범주(ex이 아이리스가 어떤 품종 아이리스인지)에 따라 결과를 분류하기 때문에 분류모델
-분류모델의 범주들을 수식으로 처리하려면 원핫인코딩과 같은 변환 작업이 필요
-분류모델은 예측결과값을 해당 범주에 해당할 확률값(0~100%)으로 리턴하며, 그 과정에서 Softmax/Sigmoid 함수를 이용
회귀모델과 분류모델
-회귀모델(Regression) : 종속변수가 양적 데이터인 경우 (ex 37점/48점/67점 등등)
-분류모델(Classification) : 종속변수가 범주형 데이터인 경우 (ex 합격/불합격)
원핫인코딩(onehot-encoding)
-아래 테이블에서처럼, 품종 분류만큼 범주를 추가한 다음, 해당 범주에 해당하면 1, 아니면 0으로 데이터를 변환하는 작업
-pd.get_dummies(데이터)로 처리 가능
품종 | → | setosa | vriginica | versicolor |
setosa | 1 | 0 | 0 | |
virginica | 0 | 1 | 0 | |
versicolor | 0 | 0 | 1 |
-위의 아이리스 데이터 예제를 변환하면 아래와 같이 됨
꽃잎길이 | 꽃잎폭 | 꽃받침길이 | 꽃받침폭 | 품종.setosa | 품종.versicolor | 품종.virginica |
5.1 | 3.5 | 1.4 | 0.2 | 1 | 0 | 0 |
7.0 | 3.2 | 4.7 | 1.4 | 0 | 1 | 0 |
6.7 | 3.3 | 5.7 | 2.1 | 0 | 0 | 1 |
Softmax/Sigmoid
-결과를 확률표현으로 받기 위해 이용하는 함수. K가 범주 개수일 때,
-Softmax: K > 2, 다층 분류시 사용 (the multiclass logistic regression)
-Sigmoid: K = 2, 이진 분류시 사용 (the two-class logistic regression)
[출처] stats.stackexchange.com/questions/233658/softmax-vs-sigmoid-function-in-logistic-classifier
-아이리스 문제의 경우, 종속변수가 3개이기 때문에 수식도 3개가 필요.
y1 = w1x1 + w2x2 + w3x3 + w4x4 + b
y2 = w1x1 + w2x2 + w3x3 + w4x4 + b
y3 = w1x1 + w2x2 + w3x3 + w4x4 + b
-위와 같은 경우, y1, y2, y3은 이론적으로 +-무한대의 값을 가질 수 있기 때문에, 이를 확률값으로 변환하기 위해서 아래와 같이 함수 적용
y1 = softmax(w1x1 + w2x2 + w3x3 + w4x4 + b)
y2 = softmax(w1x1 + w2x2 + w3x3 + w4x4 + b)
y3 = softmax(w1x1 + w2x2 + w3x3 + w4x4 + b)
-이렇게 적용된 값이 아래와 같다면,
y1(품종.setosa) == 0.2
y2(품종.virginica) == 0.3
y3(품종.versicolor) == 0.5
각각 setosa일 확률은 20%, virginica일 확률은 30%, versicolor일 확률은 50%라는 의미
-이 경우 Softmax처럼, 퍼셉트론의 출력 양식을 조절해주는 함수들을 활성화 함수(Activation)이라고 부름
# 라이브러리 사용
import tensorflow as tf
import pandas as pd
# 1.과거의 데이터를 준비합니다.
파일경로 = 'https://raw.githubusercontent.com/blackdew/tensorflow1/master/csv/iris.csv'
아이리스 = pd.read_csv(파일경로)
아이리스.head()
# 원핫인코딩
인코딩 = pd.get_dummies(아이리스)
"""
데이터 내의 범주형 데이터에 대해 원핫인코딩한 결과를 얻을 수 있음
"""
인코딩.head()
# 칼럼이름 출력
print(인코딩.columns)
"""
Index(['꽃잎길이', '꽃잎폭', '꽃받침길이', '꽃받침폭', '품종_setosa', '품종_versicolor',
'품종_virginica'],
dtype='object')
# pandas에서 원핫인코딩이 완료되었기 때문에 품종_품종명 컬럼이 새로 생김
"""
# 독립변수, 종속변수
독립 = 인코딩[['꽃잎길이', '꽃잎폭', '꽃받침길이', '꽃받침폭']]
종속 = 인코딩[['품종_setosa', '품종_versicolor', '품종_virginica']]
print(독립.shape, 종속.shape) # (150, 4) (150, 3)
# 2. 모델의 구조를 만듭니다
X = tf.keras.layers.Input(shape=[4])
"""독립변수 = ['꽃잎길이', '꽃잎폭', '꽃받침길이', '꽃받침폭']"""
Y = tf.keras.layers.Dense(3, activation='softmax')(X)
"""종속변수 = ['품종_setosa', '품종_versicolor', '품종_virginica']
분류문제이기 때문에 활성화함수(activation)에 softmax 지정 필요
기존 레모네이드/보스턴 집값 문제는 y=x 형태의 identity 활성화 함수를 적용했었던 것"""
model = tf.keras.models.Model(X, Y)
model.compile(loss='categorical_crossentropy', # 분류모델이므로, 회귀의 mse와는 다름
metrics='accuracy') # 분류문제는 성능을 정확도로 출력이 가능
# 3.데이터로 모델을 학습(FIT)합니다.
model.fit(독립, 종속, epochs=100)
"""
Epoch 78/100
5/5 [==============================] - 0s 2ms/step - loss: 0.3041 - accuracy: 0.9400
Epoch 79/100
5/5 [==============================] - 0s 2ms/step - loss: 0.3028 - accuracy: 0.9467
# loss가 점차 줄어들고 있는 상황에서는 여력이 있으므로 accuracy가 1에 근접할 때까지 반복학습
"""
# 모델을 이용합니다.
# 맨 처음 데이터 5개
print(model.predict(독립[:5]))
"""
[[9.86754239e-01 1.31175015e-02 1.28261789e-04] # setosa 0.986754239
[9.73487616e-01 2.59828754e-02 5.29477198e-04] # setosa 0.973487616
[9.81271088e-01 1.84753798e-02 2.53479055e-04] # setosa 0.981271088
[9.63053584e-01 3.63809019e-02 5.65536087e-04] # setosa 0.963053584
[9.87355530e-01 1.25438590e-02 1.00636840e-04]] # setosa 0.987355530
"""
print(종속[:5]) # 실제 정답 확인
"""
품종_setosa 품종_versicolor 품종_virginica
0 1 0 0
1 1 0 0
2 1 0 0
3 1 0 0
4 1 0 0
"""
# 맨 마지막 데이터 5개
print(model.predict(독립[-5:]))
"""
[[3.0813608e-04 1.8219605e-01 8.1749576e-01] # virginica 0.81749576
[3.5609794e-04 2.2095713e-01 7.7868676e-01] # virginica 0.77868676
[5.7861791e-04 3.2042387e-01 6.7899752e-01] # virginica 0.67899752
[3.8180550e-04 3.3763635e-01 6.6198188e-01] # virginica 0.66198188
[8.5562665e-04 4.7935012e-01 5.1979423e-01]] # virginica 0.51979423 versicolor 0.47935012
"""
print(종속[-5:]) # 실제 정답 확인
"""
품종_setosa 품종_versicolor 품종_virginica
145 0 0 1
146 0 0 1
147 0 0 1
148 0 0 1
149 0 0 1
"""
# weights & bias 출력
print(model.get_weights())
"""
y1 y2 y3
[array([[ 0.72453135, 0.05253643, 0.41662827], # 꽃잎길이
[ 1.4853274 , 0.3600737 , -1.2542167 ], # 꽃잎폭
[-2.1532962 , 0.42979974, 0.42914116], # 꽃받침길이
[-1.7550048 , -1.0885421 , 1.1693642 ]], dtype=float32), # 꽃받침폭
array([ 1.1139759 , 0.4094376 , -0.87570363], dtype=float32)] # bias
# 위의 weight와 bias로 수식을 구성한다면 아래와 같이 됨
y1 = softmax(0.72453135 * x1 + 1.4853274 * x2 + -2.1532962 * x3 + -1.7550048 * x4 + 1.1139759)
"""