다중 로지스틱 회귀(Multinomial Logistic Regression)

김우빈·2022년 5월 25일
0

JUST BUILD DEEP_LEARNING

목록 보기
5/9

전 게시글에서 로지스틱 회귀(Logistic Regression)를 통해 2개의 선택지 중에서 1개를 고르는 이진 분류(Binary Classification)를 해결하는 딥러닝 모델을 설계 해봤습니다.
이번에는 다항의 선택지중에서, 1개를 선택하는 다중 로지스틱 회귀(Multinomial Logistic Regression), 다른 말로는 소프트맥스 회귀(Softmax Regression)에 대해서 알아 보도록 하겠습니다.

다중 로지스틱 회귀(Multinomial Logistic Regression)란?

앞서 로지스틱 회귀(Logistic Regression)에서 사용한 시그모이드 함수(Sigmoid Function)는 입력된 데이터에 대해,
0과 1사이의 값을 출력하여 해당 값이 둘 중 하나에 속할 확률을 보여주는 모델 이였습니다.
예를 들어 0이 친구추가를 받지못할 확률, 1이 반대의 경우라고 가정한다면,
시그모이드 함수(Sigmoid Function)의 0과 1사이의 출력값을 친구추가 유유무의 확률이라고 예측할 수 있었습니다
확률값이 0.5를 넘으면 1에 가까우니 친구추가가 된다고 판단하면되고, 그 반대의 경우에는 친구추가가 안된다 판단하면 될것입니다.(ㅠ.ㅠ)

활성함수(Activation Function)가 시그모이드 함수(Sigmoid Function)인 로지스틱 회귀(Logistic Regression)의경우,
두 개의 선택지 중 하나를 고르는 문제였습니다.

이제 전 게시글에서 예고 한 대로,
세 개 이상의 선택지 중 하나를 고르는 다중 로지스틱 회귀(Multinomial Logistic Regression)의 구현에 대해서 설명 드리려고합니다.

Sklearn의 iris 데이터는 붓꽃의 꽃받침 길이, 꽃받침 넓이, 꽃잎 길이, 꽃잎 넓이로부터 setosa, versicolor, virginica라는 3개의 품종 중 어떤 품종인지를 예측하는 문제를 위한 데이터로
전형적인 다중 로지스틱 회귀(Multinomial Logistic Regression)를 연습 하기위한 데이터라고 할 수 있습니다.

tensorflow로 구현하기

데이터를 불러오고 확인을 위해 출력해봅니다.

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

{'data': array([[5.1, 3.5, 1.4, 0.2],
[4.9, 3. , 1.4, 0.2],
[4.7, 3.2, 1.3, 0.2],
[4.6, 3.1, 1.5, 0.2],
[5. , 3.6, 1.4, 0.2],
...

다음과 같은 numpy array 형태의 데이터를 확인 하실 수 있습니다.
이를 쉽게 다루기위해 pandas module을 사용해, 데이터프레임화 시킨후, 이를 시각화 해보면,

df = pd.DataFrame(iris.data, columns=iris.feature_names)
df['class'] = iris.target

df

다음과 같은 데이터프레임을 보실수 있습니다.

다음에서 calss column은 각각 붓꽃의 품종을 의미하는데,
각 서 0은 setosa, 1은 versicolur, 2는virginica으로 이미 라벨링 되어있는것을 알 수 있습니다.

또 각각의 설명변수(coulmn명)는,

sepal length: 꽃잎길이, sepal width: 꽃잎폭
petal length: 꽃받침길이, petal width: 꽃받침폭
인것을 알 수 있습니다.

컬럼명이 코드로 사용하기엔 불편 함이 있어, 다음과 같은 코드로 정리 해주고 확인 하였습니다.

df.columns=['sepal_length', 'sepal_width', 'petal_length', 'petal_width', 'class']
df.head(5)

계속해서 전처리 진행하도록 하겠습니다.
다음은 결측치(NULL, None)가 있는지 확인 해주겠습니다.

df.isnull().any()

sepal_length False
sepal_width False
petal_length False
petal_width False
class False
dtype: bool

결측치(NULL, None)가 존재하지 않아 중복된 데이터가 있는지 확인 해보도록 하겠습니다.

df.loc[df.duplicated() ,:]

다음코드를 입력하면,

이렇게 중복되는 데이터를 확인하실 수 있습니다.

df.drop_duplicates(inplace=True)

다음코드를 통해 중복되는 데이터를 쉽게 제거 해줄수있습니다.

마지막으로 훈련(train)데이터와 검증(validation)데이터를 나누어 줍니다!

from sklearn.model_selection import train_test_split
from tensorflow.keras.utils import to_categorical

x_data=df.loc[:, 'sepal_length':'petal_width'] #설명변수 범위로 지정
y_data=df.loc[:, 'class'] #종속변수

#전체 중 20%를 테스트용으로 분할,나머지 80%는 훈련용
(x_train, x_valid, y_train, y_valid) = train_test_split(x_data, y_data, train_size=0.8, random_state=1)

#원-핫 인코딩(one-hot encoding)
y_train = to_categorical(y_train)
y_valid = to_categorical(y_valid)

#5개씩만 출력
print(y_train[:5])
print(y_valid[:5])

다음과 같이 원-핫 인코딩(One-Hot Encoding)된 결과를 확인 하실 수 있습니다.

[[0. 0. 1.][0. 1. 0.]
[1. 0. 0.][0. 0. 1.]
[1. 0. 0.]]
[[0. 0. 1.][0. 1. 0.]
[0. 1. 0.][0. 1. 0.]
[0. 1. 0.]]

다음과 같이 sklearn의 train_test_split을 사용해 쉽게 나눌수 있습니다.

다중 분류를 위해서는
이제 원-핫 인코딩(One-Hot Encoding)을 해어야합니다.

원-핫 인코딩(One-Hot Encoding)이란?

사람과 기계(컴퓨터)는 데이터를 바라보는 형태가 다릅니다.
사람은 어떠한 물체를 보며 숫자로 인식하지는 않습니다.
기계(컴퓨터)에게 학습을시키기 위해서는 기계(컴퓨터)가 인식할수있도록 숫자값으로 변환을 헤야합니다.

사람이 사용하는 언어인 자연어(natural language)를 기계(컴퓨터)에게 학습을위해 주입시키기 위한 가장 기본적인 방법입니다.

iris데이터를 예로 들어 각각 setosa, versicolor, virginica 세가지의 붓꽃 품종이 있습니다. 이들은 각각 setosa는 0 , versicolor는 1, virginica는 2로 라벨링 되어있는 상태입니다.

이를 원-핫 인코딩(One-Hot Encoding) 하면 다음과 같은 행렬이 나옵니다.

[[0. 0. 1.][0. 1. 0.]
[1. 0. 0.][0. 0. 1.]
[1. 0. 0.]]
[[0. 0. 1.][0. 1. 0.]
[0. 1. 0.][0. 1. 0.]
[0. 1. 0.]]

이는각각 [setosa,versicolor, virginica]라고 볼 수 있고, 그에 맞는 값을 가지고 있는 자리는 1이 되게됩니다.

예를들어 첫번째 값인 [0.0.1]을 보면 마지막 자리에 1이 있는것을 확인 하실 수 있습니다.
마지막 자리는 virginica 라는 품종이므로, 첫번째 값은 virginical 라는것을 아실 수 있습니다.
이와같은 방법의 인코딩을 원-핫 인코딩(One-Hot Encoding)이라고 합니다.

이제깔끔하게 전처리가된 데이터를 가지고, 본격적으로 tensorflow를 사용해 구현해보도록 하겠습니다.

tesorflow로 구현하기

from tensorflow.keras import Sequential
from tensorflow.keras.layers import Dense, Activation

# 모델을 준비한다.
model = Sequential()

# 입력 변수의 개수가 4이고 출력 개수가 3
model.add(Dense(3, input_dim=4, activation='softmax'))

# Loss funtion과 Optimizer를 선택한다.
model.compile(loss='categorical_crossentropy', optimizer='adam',metrics=['accuracy']) 

# epochs만큼 반복
hist=model.fit(x_train, y_train, epochs=500, batch_size=20,validation_data=(x_valid, y_valid))

로지스틱 회귀(Logistic Regression)의 코드와 크게 다르지않지만,
들어오는 종속변수(yy)의 갯수가 4개
(sepal length: 꽃잎길이, sepal width: 꽃잎폭
petal length: 꽃받침길이, petal width: 꽃받침폭)이므로,

입력노드의(Input Node)갯수는 4개로 설정해주고,

출력노드는 [1.0.0], [0.1.0], [0.0.1] 3개이므로
3으로 지정하여줍니다.

활성함수(Activation Function)는 다중분류에 사용하는 함수인 소프트맥스(softmax)를 사용하는 Dense Layer를 모델에 추가해줍니다.

다음은 다중분류에 사용하는 손실함수(Loss Function)인 범주형 교차 엔트로피(categorical crossentropy)를 사용하고,
믿고쓰는 옵티마이저(optimizer)인 adam,
측정항목(metric) 정확도(accuracy)를 모니터링하기위해 모델에 엮어줍니다.(compile)

그후 실행해보면,

Epoch 1/500
6/6 [==============================] - 0s 27ms/step - loss: 4.0047 - accuracy: 0.0168 - val_loss: 4.9660 - val_accuracy: 0.0333
Epoch 2/500
6/6 [==============================] - 0s 6ms/step - loss: 3.9339 - accuracy: 0.0084 - val_loss: 4.8935 - val_accuracy: 0.0000e+00
Epoch 3/500
6/6 [==============================] - 0s 6ms/step - loss: 3.8638 - accuracy: 0.0000e+00 - val_loss: 4.8255 - val_accuracy: 0.0000e+00
Epoch 4/500
6/6 [==============================] - 0s 6ms/step - loss: 3.7994 - accuracy: 0.0000e+00 - val_loss: 4.7603 - val_accuracy: 0.0000e+00
.
.
.
Epoch 498/500
6/6 [==============================] - 0s 5ms/step - loss: 0.3670 - accuracy: 0.9664 - val_loss: 0.3991 - val_accuracy: 0.9667
Epoch 499/500
6/6 [==============================] - 0s 5ms/step - loss: 0.3667 - accuracy: 0.9664 - val_loss: 0.3995 - val_accuracy: 0.9667
Epoch 500/500
6/6 [==============================] - 0s 5ms/step - loss: 0.3661 - accuracy: 0.9664 - val_loss: 0.3992 - val_accuracy: 0.9667

다음과 같은 결과를 확인 하실 수 있습니다.
마지막 epoch를 확인해보면 훈련(train)데이터의
손실율(Loss Value)은 0.3361, 정확도(accuracy)는 0.9664(96.64%),
검증데이터의 손실율(Loss Value)은 0.3992,정확도(accuracy)는 0.9667(96.67%)로,
굉장히 잘 설계된 모델이라는것을 확인 하실 수 있습니다.
(tensorflow 만세)

모델 평가를 위해 위 수치를 시각화 해보겠습니다.

import matplotlib.pyplot as plt
fig, loss_ax = plt.subplots()
acc_ax = loss_ax.twinx()

loss_ax.plot(hist.history['loss'], 'y', label = 'train loss')
loss_ax.plot(hist.history['val_loss'], 'r', label = 'val loss')

acc_ax.plot(hist.history['accuracy'], 'b', label = 'train accuracy')
acc_ax.plot(hist.history['val_accuracy'], 'g', label = 'valid accuracy')

loss_ax.set_xlabel('epoch')
loss_ax.set_ylabel('loss')
acc_ax.set_ylabel('accuracy')

loss_ax.legend(loc='upper left')
acc_ax.legend(loc='lower left')

plt.show()

다음과 같이 시각화된 아름다운 그래프를 확인 하실 수있습니다.

마무리

본 문에선 로지스틱 회귀(Logistic Regression)에 이어,
다중 로지스틱 회귀(Multinomial Logistic Regression)에 대해서 알아 보았습니다.
다음 게시글에선 CNN(Convolutional Neural Network)을 이용한 이미지 분류에 대해서 다뤄 보도록 하겠습니다.
감사합니다.

profile
DeepLearning, MLOps

0개의 댓글